♪ Modális szintézis, 1. gyakorlat: a trambulintól a modális szintézis egyenletéig

1. Mi az a módus?

Egy harang, egy gong vagy egy gitártest nem egyetlen hangot ad, hanem sokat egyszerre. A modális szintézis (Adrien, 1991 [1]) azt feltételezi, hogy a tárgy lineáris és időben állandó (LTI) rendszer: a rezgés ereje nem változtatja meg a tárgy tulajdonságait, a válasz az ütés erejével arányosan nő. Kis kitérésnél ez a legtöbb hangszerre és használati tárgyra jó közelítés [3][12]. Nemlineáris jelenségek (a gong felfutása, a húr feszülésváltozása) ebben a modellben nincsenek.

Ilyen rendszerben létezik néhány különleges mozgásforma, a módus: olyan lengés, amelyben a tárgy minden pontja ugyanazon a frekvencián leng, a pontok kitéréseinek aránya pedig állandó. Ezt a kitérés-eloszlást nevezzük módusalaknak. Egy N tömegből (szabadságfokból) álló modellnek N módusa van, és a rendszer bármilyen mozgása a módusok összege.

🩰 Tánckar: mindenki ugyanabban az ütemben mozog, de mindenkinek más a mozdulata. Ez egy módus. A tárgynak több ilyen „koreográfiája” van, és a hangja ezek keveréke.

Minden módust három szám jellemez: a frekvenciája (\(\omega_n\)), a lecsengési rátája (\(\sigma_n\)) és az erőssége (\(a_n\)). Az első kettő a tárgyé (anyag, méret, alak), az erősség az ütés és a hallgatás helyétől is függ. A modális szintézis ennek a három listának a hanggá alakítása [1][3].

A lecsengési ráta azt írja le, milyen gyorsan fogy egy módus amplitúdója: \(e^{-\sigma t}\) szerint, nagyobb \(\sigma\) rövidebb hangot jelent. A valódi tárgyakban a magasabb módusok csillapítása nagyobb, ezért azok hamarabb halnak ki, és lecsengés közben a hang sötétebbé válik. A zongoránál az ütés után a csilingelő felső rész hamar eltűnik, a mély alap marad [14].

2. Egy rezgő: tömeg, rugó, fék

A legegyszerűbb rezgő egy tömeg (\(m\)), egy rugó (\(k\)) és egy fék (\(c\)). Newton második törvénye szerint a tömeg gyorsulásából adódó erő egyenlő a rá ható erők összegével: a rugó visszahúz (\(-kx\)), a fék lassít (\(-c\dot x\)), és lehet külső erő (\(f\)). Ebből a mozgásegyenlet [13]:

\[m\ddot x+c\dot x+kx=f(t).\]

Mértékegységek. Az egyenlet SI-egységekben érvényes: \(m\) [kg], \(k\) [N/m], \(c\) [N·s/m], \(x\) [m], \(f\) [N]. A gramm és a kN/m használata átváltás nélkül a leggyakoribb hiba, mert a képlet csak koherens egységrendszerben igaz.

Sajátfrekvencia. Ha nincs külső erő és fék, a rendszer a saját ütemében leng: \(\omega_0=\sqrt{k/m}\) [rad/s]. A hertzben mért frekvencia \(f_0=\omega_0/2\pi\), mert egy kör \(2\pi\) radián, a hertz a köröket számolja másodpercenként. Feszesebb rugó (nagyobb \(k\)) gyorsabb lengést ad, nagyobb tömeg lassabbat: a feszes dobbőr magas, a nagydob mély hangot ad. A \(\omega_0\) a tömeg és a rugó aránya, tehát a tömeg dupláztával \(f_0\) a \(\sqrt2\)-edére csökken.

3. Lecsengés és csillapítás

A fék miatt a lengés amplitúdója exponenciálisan fogy. A lecsengési ráta \(\sigma=\dfrac{c}{2m}\) [1/s], a csillapítási tényező \(\zeta=\dfrac{c}{c_{krit}}\), ahol a kritikus csillapítás \(c_{krit}=2\sqrt{km}\). Így \(\zeta=\sigma/\omega_0\). A \(\zeta\) azt mondja meg, hányad része a fék a kritikusnak: zenei tárgyaknál rendkívül kicsi (\(10^{-4}\)–\(10^{-2}\)), ilyenkor a rendszer sokat leng, mielőtt elhal.

Három eset különböztethető meg (a levezetést lásd a 10. pontban): ha \(\zeta<1\), a mozgás lecsengő szinusz \(\omega_d=\sqrt{\omega_0^2-\sigma^2}\) csillapított frekvenciával; ha \(\zeta=1\), a rendszer éppen már nem leng át (kritikus csillapítás); ha \(\zeta>1\), nincs lengés, csak lassú visszatérés. Utóbbi két esetben nincs csengés, csak puffanás hallatszik, mintha a trambulin vásznát mézbe merítenénk.

A hangot egy rövid ütés (impulzus, \(J\) [N·s]) hozza létre, amely a tömeg sebességét \(J/m\)-re állítja. Erre a rendszer válasza, az impulzusválasz:

\[x(t)=h(t)=\frac{J}{m\,\omega_d}\,e^{-\sigma t}\sin(\omega_d t).\]

Utózengési idő. A \(T_{60}\) az az idő, amely alatt az amplitúdó az ezredrészére (−60 dB) esik: \(e^{-\sigma T_{60}}=10^{-3}\), így \(T_{60}=\dfrac{\ln1000}{\sigma}\approx\dfrac{6{,}9}{\sigma}\) [14]. Az ezerszeres arány természetes logaritmusa 6,9, ezért nem 3 (az a tízes alapú logaritmus). Ugyanez a mennyiség a reverb pluginok RT60-a, vagyis a terem utózengési ideje.

4. Több szabadságfok: mátrixok

Ha a tárgyat több tömegre és rugóra bontjuk, a mozgásegyenletek összekapcsolódnak, mert a szomszédos tömegek hatnak egymásra. Az egyenleteket mátrixokba rendezzük [13]:

\[\mathbf M\ddot{\mathbf x}+\mathbf C\dot{\mathbf x}+\mathbf K\mathbf x=\mathbf f(t).\]

Az \(\mathbf M\) a tömegmátrix (átlóján a tömegek), a \(\mathbf K\) a merevségmátrix (a rugók kapcsolata), a \(\mathbf C\) a csillapításmátrix. Az \(\mathbf M\) és \(\mathbf K\) szimmetrikus; az \(\mathbf M\) pozitív definit, a \(\mathbf K\) pozitív (szemi)definit. Egy tömegekből és rugókból álló láncnál a \(\mathbf K\) átlójában a tömeget tartó rugók összege áll, a mellette lévő elemek \(-k\)-t kapnak: a negatív előjel azt fejezi ki, hogy a szomszéd visszahúz. A szabad vég azért különbözik, mert ott csak egy rugó kapcsolódik, ezért a \(\mathbf K\) megfelelő átlóeleme kisebb.

5. Sajátfrekvenciák és sajátalakok

Ha nincs fék és erő, a rendszer akkor leng tiszta, egyetlen ütemben, ha \(\mathbf x=\mathbf u\,e^{j\omega t}\) alakú. Behelyettesítve:

\[(\mathbf K-\omega^2\mathbf M)\,\mathbf u=\mathbf 0.\]

Ennek csak akkor van nullától különböző megoldása, ha \(\det(\mathbf K-\omega^2\mathbf M)=0\). Ez \(\omega^2\)-ben \(N\)-edfokú egyenlet, tehát \(N\) sajátérték (\(\omega_n^2\)) van, és mindegyikhez tartozik egy \(\mathbf u_n\) sajátvektor, vagyis módusalak. A vektor csak irányáig meghatározott: megadja a pontok kitéréseinek arányát, a skálája szabadon választható. Egy gitárhúr sem akármilyen frekvencián cseng, hanem csak a sajátfrekvenciáin.

A számításhoz célszerű \(\lambda=\omega^2/\omega_0^2\) arányt bevezetni (\(\omega_0=\sqrt{k/m}\)): mértékegység nélküli, mint egy zenei intervallum. Illusztrációként a legegyszerűbb esetben, két azonos tömegből és rugóból álló, falhoz rögzített, szabad végű láncban \((2-\lambda)(1-\lambda)-1=0\), azaz \(\lambda^2-3\lambda+1=0\), és \(\lambda=\frac{3\mp\sqrt5}{2}\). Ebből \(\omega_{1,2}=0{,}618\,\omega_0\) és \(1{,}618\,\omega_0\). Az első módusban a két tömeg együtt mozog, a másodikban ellentétesen (libikóka), köztük nyugvópont van. A két frekvencia hányadosa 2,618: a húr felhangjai 1 : 2 : 3, itt a viszony nem egész, ezért szól fémesebben, harangszerűen. Az ilyen sort inharmonikusnak nevezzük [1][12].

6. Módusalakok, erősség, az ütés és a hallgatás helye

A módusalakok ortogonálisak a tömegmátrixra nézve: \(\mathbf u_m^T\mathbf M\mathbf u_n=0\), ha \(m\ne n\) (a bizonyítást lásd a 11. pontban). Emiatt a bonyolult rendszer \(N\) független rezgőre esik szét, mindegyiknek saját módus-tömege van: \(m_n=\mathbf u_n^T\mathbf M\mathbf u_n\). A módus-tömeg azt fejezi ki, hogy az adott módus mennyi tömeget „mozgat meg”.

Ha a \(p\) pontban ütünk és a \(q\) pontban hallgatunk, az \(n\). módus erőssége

\[a_n=\frac{u_n(p)\,u_n(q)}{m_n}.\]

Ez a szorzat az, ami a hangszínt alakítja. Ha ugyanott ütünk és hallgatunk, a szorzat négyzet. Ha az ütés a módus csomópontjában történik (\(u_n(p)=0\)), a módus egyáltalán nem szólal meg: ez a gitár flageolettje, ahol a húr csomópontját érintve az alaphang eltűnik, az oktáv szól. Gitáron a híd mellett pengetve (ponticello) a magasabb módusok erősebbek, a fogólap fölött (tasto) az alaphang dominál. Az ütés helye tehát a hangszín gombja [3][12]. A módusok frekvenciáit viszont nem változtatja meg.

7. Hogyan számol a gép?

7.1 A két mintás rezgő és a három számítási módszer

A digitális rendszer mintánként számol: \(f_s=44100\) minta/s, \(T=1/f_s\). Egy rezgő hangja két mintás szabállyal állítható elő: a mostani minta az előző két minta lineáris keveréke,

\[y[n]=a_1\,y[n-1]+a_2\,y[n-2].\]

Az \(a_1,a_2\) értékét háromféleképpen adhatjuk meg:

\(a_1\)\(a_2\)
explicit Euler\(2-2\sigma T\)\(-(1-2\sigma T+\omega_0^2T^2)\)
szemi-implicit Euler\(2-2\sigma T-\omega_0^2T^2\)\(-(1-2\sigma T)\)
pontos (impulzus-invariáns)\(2r\cos\theta\)\(-r^2\)

Az Euler-módszerek a differenciálegyenletet közelítik: minden lépésben a pillanatnyi meredekséggel haladnak tovább, mint aki sötétben, csak az orra irányát nézve lép. Az explicit Euler a kitérést a régi sebességgel, a szemi-implicit az újonnan kiszámolt sebességgel frissíti; a különbség egyetlen sor, de a viselkedés más [15]. A pontos megoldás a kontinuus rendszer megoldásából indul ki: az \(e^{sT}\) leképezéssel (impulzus-invariancia [10]) a pólusokat \(re^{\pm j\theta}\)-ra viszi, ahol \(r=e^{-\sigma T}\), \(\theta=\omega_dT\). Három szám építi fel: a cos a hullám forgási sebessége (hangmagasság), az r az, hogy lépésenként mennyi marad meg (lecsengés), a sin az első lökés (az ütés).

7.2 A pólus sugara: stabilitás

A szabály sorsát egy szám dönti el: a pólus sugara \(r=\sqrt{-a_2}\). Ez a visszacsatolás erőssége, mint a mikrofon és a hangfal között: egynél kisebb erősítésnél a hang elhal, egynél nagyobbnál minden mintánál nő, és üvölt. Explicit Eulernél \(r^2=1-2\sigma T+\omega_0^2T^2\), ami \(\omega_0^2T^2>2\sigma T\) esetén 1-nél nagyobb: a közelítési hiba negatív csillapításként viselkedik, és a hang elszáll. A szemi-implicit Eulernél \(r^2=1-2\sigma T<1\): stabil, de a frekvenciája \(\omega_0T\) arányában eltér a valóditól, magasabb frekvencián nagyobb mértékben. A pontos megoldásnál \(r=e^{-\sigma T}\), amely \(\sigma>0\) esetén mindig 1 alatt marad, ezért nem szállhat el, és a frekvenciája sem torzul [10][15].

7.3 Összeáll a modális szintézis

Minden módus egy ilyen két mintás rezgő. Egy tárgy hangja a módusok összege, ez a modális szintézis egyenlete (a levezetés a 3. és 11. pontból adódik) [1][3]:

\[y(t)=\sum_{n=1}^{N}\frac{a_n}{\omega_{d,n}}\,e^{-\sigma_n t}\sin(\omega_{d,n}t),\qquad a_n=\frac{u_n(p)\,u_n(q)}{m_n}.\]

A hang megadásához három lista kell: a frekvenciák (\(\omega_{d,n}\)), a lecsengések (\(\sigma_n\)) és az erősségek (\(a_n\)). Egy tárgy akkor „modellezett”, ha ez a három lista ismert, akár számolásból, akár mérésből [3][4][5].

8. (kiegészítés) A diszkrét rezgő pontossága és stabilitása

A 2. pont rezgőjének átviteli függvénye \(H(s)=\dfrac{1}{m\,(s^2+2\sigma s+\omega_0^2)}\), pólusai \(s=-\sigma\pm j\omega_d\). Az \(z=e^{sT}\) leképezés (impulzus-invariancia) a pólusokat \(re^{\pm j\theta}\)-ra viszi, \(r=e^{-\sigma T}\), \(\theta=\omega_dT\). A nevező \(1-2r\cos\theta\,z^{-1}+r^2z^{-2}\), vagyis a 2 mintás rezgő \(a_1=2r\cos\theta\), \(a_2=-r^2\) együtthatóival. Következmények: (i) a frekvencia és a lecsengés pontos (nincs frekvenciatorzulás, szemben a bilineáris transzformációval); (ii) stabil, ha \(\sigma>0\), azaz \(r<1\); (iii) a \(\omega>\pi f_s\) módusok visszatükröződnének, ezért kihagyjuk (a demó \(0{,}9\pi f_s\)-nél vág); (iv) a diszkrét rezgő az ideális válasz egy mintával eltolt másolatát adja, amplitúdóban legfeljebb \(e^{\sigma T}\)-szeres eltéréssel (ez gyakorlatilag 1), ami nem hallható.

9. (kiegészítés) Átviteli függvény és a módusok mint pólusok

A 2. és 7. pont összefüggése frekvenciatartományban: az \(f(t)\) bemenet és az \(x_q\) kimenet közötti átviteli függvény \(H_{pq}(s)=\sum_n\dfrac{u_n(p)\,u_n(q)}{m_n\,(s^2+2\sigma_ns+\omega_n^2)}\). A pólusok (\(\omega_n,\sigma_n\)) a rendszer sajátjai, a számlálók (maradékok) az ütés és a hallgatás helyétől függnek. A parciális törtekre bontás és az állapottér diagonalizálása ugyanazt adja: a pólusok minden bemenetre és kimenetre közösek, a diagonalizált rendszer pedig fizikailag helyes párhuzamos szűrőbank [17]. Feltétel: az arányos csillapítás. Általános csillapításnál a módusok komplexek, és az állapottér-sajátérték feladatot kell megoldani.

10. (kiegészítés) Az impulzusválasz levezetése és a három eset

A \(x=e^{st}\) próbafüggvény a \(ms^2+cs+k=0\), vagyis \(s^2+2\sigma s+\omega_0^2=0\) egyenletre vezet, a gyökök \(s_{1,2}=-\sigma\pm\sqrt{\sigma^2-\omega_0^2}\) [13]. Három eset van:

EsetGyökökMozgásHang
\(\zeta<1\) alulcsillapított\(-\sigma\pm j\omega_d\)lecsengő szinuszcseng
\(\zeta=1\) kritikus\(-\sigma\) (kettős)\((A+Bt)e^{-\sigma t}\)puffanás
\(\zeta>1\) túlcsillapítottkét valós negatívkét exponenciális összegepuffanás

Egy \(J\) [N·s] ütés a sebességet \(v(0^+)=J/m\)-re állítja, \(x(0)=0\). Ezeket illesztve (\(\zeta<1\)) jön a 3. pont válasza: \(h(t)=\dfrac{J}{m\omega_d}e^{-\sigma t}\sin\omega_dt\). A csillapított frekvencia kisebb \(\omega_0\)-nál: \(\omega_d=\omega_0\sqrt{1-\zeta^2}\). Zenei \(\zeta\)-nál (\(10^{-4}\)–\(10^{-2}\)) ez elhanyagolható, \(\zeta=0{,}1\)-nél már 0,5%. A módus egy póluspár: a képzetes rész a hangmagasság, a valós rész a lecsengés.

11. (kiegészítés) Módusok mátrixokból: ortogonalitás, szétcsatolás, Rayleigh-csillapítás

Sajátérték-feladat. Csillapítás és erő nélkül az \(\mathbf x=\mathbf u e^{j\omega t}\) alak a \((\mathbf K-\omega^2\mathbf M)\mathbf u=\mathbf 0\) egyenletre vezet; nemtriviális megoldás csak \(\det(\mathbf K-\omega^2\mathbf M)=0\) esetén van. Ez \(N\) frekvenciát (\(\omega_n\)) és \(N\) alakot (\(\mathbf u_n\)) ad [13].

Ortogonalitás. \(\mathbf M\) és \(\mathbf K\) szimmetrikus, ezért \(\mathbf u_m^T\mathbf M\mathbf u_n=0\), ha \(m\ne n\). Bizonyítás: a \(\mathbf K\mathbf u_n=\omega_n^2\mathbf M\mathbf u_n\) egyenletet szorozd \(\mathbf u_m^T\)-vel, a fordítottját \(\mathbf u_n^T\)-vel, és vond ki: \((\omega_n^2-\omega_m^2)\,\mathbf u_m^T\mathbf M\mathbf u_n=0\). Módus-tömeg: \(m_n=\mathbf u_n^T\mathbf M\mathbf u_n\), módus-merevség: \(k_n=\omega_n^2m_n\).

Szétcsatolás. Az \(\mathbf x=\sum_nq_n\mathbf u_n\) helyettesítés és az \(\mathbf u_n^T\)-vel való szorzás \(N\) független egyenletet ad: \(m_n\ddot q_n+c_n\dot q_n+k_nq_n=\mathbf u_n^T\mathbf f\). Ez ugyanaz az egyenlet, mint a 2. pontban, csak az erő a vetület \(\mathbf u_n^T\mathbf f\). Tehát egy N szabadságfokú rendszer N független rezgő.

Rayleigh-csillapítás. Ha \(\mathbf C=\alpha\mathbf M+\beta\mathbf K\), akkor \(c_n=\alpha m_n+\beta k_n\) és \(\sigma_n=\dfrac{c_n}{2m_n}=\dfrac{\alpha+\beta\omega_n^2}{2}\) [14]. Az \(\alpha\) minden módust arányosan fékez (levegő), a \(\beta\) a magasabbakat négyzetesen jobban (anyagbelső súrlódás): ezért tompul a hang lecsengés közben. Általános \(\mathbf C\)-nél komplex módusok jönnek, lásd a 9. pontot.

12. (kiegészítés) Láncok zárt alakban

Azonos \(m\), \(k\) esetén (\(\omega_0=\sqrt{k/m}\)), a láncok képletei:

Lánc\(\omega_n\)\(u_n(j)\)\(m_n\)
fal – szabad\(2\omega_0\sin\frac{(2n-1)\pi}{4N+2}\)\(\sin\frac{(2n-1)j\pi}{2N+1}\)\(m\frac{2N+1}{4}\)
fal – fal (húr)\(2\omega_0\sin\frac{n\pi}{2N+2}\)\(\sin\frac{nj\pi}{N+1}\)\(m\frac{N+1}{2}\)

Illusztráció: \(N=2\), fal–szabad: \(2\sin18^\circ=0{,}618\), \(2\sin54^\circ=1{,}618\). A fal–fal lánc frekvenciái \(N\to\infty\)-ben a húr \(1:2:3\dots\) sorához tartanak, a fal–szabad lánc inharmonikus marad (harangjelleg).

Ha \(u_n(p)=0\) vagy \(u_n(q)=0\) (csomópont), az \(n\). módus nem szólal meg.

13. (kiegészítés) Gyakorlati kérdések a megvalósításhoz

  • Nyquist: csak \(\omega_d<0{,}9\pi f_s\) módus kerül a bankba.
  • Denormál: a gen~ history és delay operátorai alapból fixdenorm-ot alkalmaznak a bemenetükre [16], ezért a lecsengett rezgő nem terheli a CPU-t.
  • Paraméterváltás futás közben: az állapot (\(y[n-1],y[n-2]\)) megmarad, de az \(a_1,a_2\) ugrása kattanást adhat; simítsd a paramétereket.
  • Hangerő: a módusok számával nő az összeg, normalizálni kell. Költség: módusonként kb. 4 szorzás mintánként, így százas nagyságrend valós időben kezelhető [12].

Demó 1: tömegek lánca (módusok és lassított felvétel)

🎯 Mit csinálj?
N = 1-nél egyetlen rezgőt kapsz. Növeld N-et, és nézd, hogyan szól a lánc. A rajz lassított felvétel: kapcsold ki-be az egyes módusokat, így látod, hogy a mozgás a módusok összege. Az ütés után az animáció újraindul.

Hang az idő függvényében

Módusalakok (bal oldalon a fal)

Kódok: gen~ / GenExpr

A kódok a Max gen~ objektumának codebox-ában (GenExpr nyelv) futnak. Minden kód ugyanazt számolja, mint az Elmélet fül: a 2. pont rezgőjét, az Euler-összehasonlítást (7. pont) és a modális bankot (7.3). A paraméterek mértékegységei megegyeznek a demó csúszkáival.

A GenExpr alapjai (hivatalos dokumentáció szerint [16])

  • A codebox GenExpr-kódot fogad. A in1, in2… és out1, out2… kulcsszavak a codebox be- és kimeneteit jelölik. A szintaxis a C-hez és a JavaScripthez hasonló; pontosvessző több utasításnál kell.
  • Param név(alapérték, min=…, max=…); paramétert deklarál, úgy viselkedik, mint a param objektum, és üzenettel állítható.
  • History név(kezdőérték); egy mintányi késleltetés: ez adja a visszacsatolást. Példa a dokumentációból: History x1, y1; y = in1 - x1 + y1*0.9997; x1 = in1; y1 = y; out1 = y;
  • A samplerate beépített állandó (értéke a patch újraindításáig nem frissül). Data + peek/poke tömbös állapothoz való. GenExpr függvények is definiálhatók.
  • A kód mintánként fut, felülről lefelé: a History-t előbb olvasod, aztán írod.
Névütközés: az y1, y2 (betű+szám) nevek ütközhetnek beépítettekkel, ezért a kódokban ya, yb áll. Az if/else-ben vagy ciklusban először létrehozott változó kívül nem látszik, ezért az ideiglenes változók a kód elején kapnak kezdőértéket.

Patch-beállítás: [click~] → [gen~] bal bemenete; nyisd meg a gen~-et, tegyél bele codebox-ot, és kösd be-/kimenetre (in 1, out 1). Az ütés a [click~]. Vizsgáld: [spectroscope~], [scope~].

1. kód: egyetlen rezgő (a 2. pont)

Két mintás rezgő, a₁ = 2r·cosθ, a₂ = −r². Várt: 438,8 Hz és T₆₀ ≈ 2,8 s. A c-t 55 körülire állítva puffanás jön (kritikus fék). Újabb ütés a futó hanghoz hozzáadódik, ami lineáris rendszerre helyes.

// in1: ütés (0→1)   out1: kitérés [m]
Param m(10, min=1, max=100);        // tömeg [g]
Param k(76, min=5, max=500);        // rugómerevség [kN/m]
Param c(0.049, min=0, max=100);     // fék [N·s/m]
Param J(1, min=0, max=10);          // impulzus [N·s]
History ya(0), yb(0), prev(0);

mm = m*0.001;                         // g → kg
w0 = sqrt(k*1000/mm);                 // omega_0 [rad/s]
s  = c/(2*mm);                        // sigma [1/s]
wd = sqrt(max(w0*w0 - s*s, 1e-9));    // omega_d
r  = exp(-s/samplerate);  th = wd/samplerate;
trig = (in1 > 0 && prev <= 0);        // felfutó él = ütés
v = trig*J/(mm*wd)*sin(th) + 2*r*cos(th)*ya - r*r*yb;
yb = ya;  ya = v;  prev = in1;
out1 = v;

2. kód: Kód-labor, három módszer egy patchben (7.1–7.2)

out1: explicit Euler, out2: szemi-implicit Euler, out3: pontos. A kitérés ≈ 0,036 m, ezért szorzunk 20-szal. Várt: out1 másodpercek alatt elszáll (a clip védi a hangszórót), out2 és out3 csúcsa ≈ 0,7. A két Euler között egyetlen sor a különbség: az x a régi vagy az új sebességgel lép.

Param m(10), k(76), c(0.049), J(1);
History xe(0), ve(0), xs(0), vs(0), ya(0), yb(0), prev(0);

mm = m*0.001;  kk = k*1000;  T = 1/samplerate;
w0 = sqrt(kk/mm);  s = c/(2*mm);
wd = sqrt(max(w0*w0 - s*s, 1e-9));
r  = exp(-s*T);  th = wd*T;
trig = (in1 > 0 && prev <= 0);  prev = in1;
kick = trig*J/mm;                         // az ütés = sebesség-ugrás

// 1) explicit Euler: x az RÉGI sebességgel lép
ae   = (-kk*xe - c*ve)/mm;
xe_n = xe + T*ve;
ve_n = ve + T*ae + kick;
xe = xe_n;  ve = ve_n;

// 2) szemi-implicit Euler: x az ÚJ sebességgel lép
as_  = (-kk*xs - c*vs)/mm;
vs_n = vs + T*as_ + kick;
xs_n = xs + T*vs_n;
xs = xs_n;  vs = vs_n;

// 3) pontos (impulzus-invariáns)
yn = trig*J/(mm*wd)*sin(th) + 2*r*cos(th)*ya - r*r*yb;
yb = ya;  ya = yn;

out1 = clip(20*xe, -1, 1);
out2 = 20*xs;
out3 = 20*yn;
A pólus sugara az explicit Eulernél: sqrt(1 - 2*s*T + w0*w0*T*T) ≈ 1,0019. Köss rá egy [number~]-t, és ellenőrizd.

3. kód: modális bank, fal–szabad lánc, N = 3 (7.3, 12. pont)

Módusonként ugyanaz a rezgő, függvényként. Erősség: a = u(p)·u(q)/S, S = (2N+1)/4; csillapítás: σ = (α + β·ω²)/2 (11. pont). Várt (m = 10 g, k = 76 kN/m): 195, 547, 791 Hz. A p (ütés helye) a hangszín gombja: próbáld 1 és 3 között.

// in1: ütés   out1: hang
modal(w, s, a, t) {
    History ya(0), yb(0);
    wd = sqrt(max(w*w - s*s, 1e-9));
    r  = exp(-s/samplerate);  th = wd/samplerate;
    v  = t*(a/wd)*sin(th) + 2*r*cos(th)*ya - r*r*yb;
    yb = ya;  ya = v;
    return v * (w < 0.9*pi*samplerate);   // Nyquist-védelem
}

Param m(10, min=1, max=100);        // [g]
Param k(76, min=5, max=500);        // [kN/m]
Param c(16, min=0, max=200);        // alfa-hoz: tömegenkénti fék [N·s/m]
Param beta(0, min=0, max=100);      // beta [µs]
Param p(3, min=1, max=3);           // ütés helye
Param q(3, min=1, max=3);           // hallgatás helye
Param gain(20, min=0, max=200);
History prev(0);

N = 3;  mm = m*0.001;  w0 = sqrt(k*1000/mm);
alpha = c/mm;  b = beta*1e-6;  S = (2*N+1)/4;
trig = (in1 > 0 && prev <= 0);  prev = in1;

w1 = 2*w0*sin(1*pi/(4*N+2));  w2 = 2*w0*sin(3*pi/(4*N+2));  w3 = 2*w0*sin(5*pi/(4*N+2));
s1 = (alpha + b*w1*w1)/2;     s2 = (alpha + b*w2*w2)/2;     s3 = (alpha + b*w3*w3)/2;
a1 = sin(1*p*pi/(2*N+1))*sin(1*q*pi/(2*N+1))/S;
a2 = sin(3*p*pi/(2*N+1))*sin(3*q*pi/(2*N+1))/S;
a3 = sin(5*p*pi/(2*N+1))*sin(5*q*pi/(2*N+1))/S;

out1 = gain*(modal(w1,s1,a1,trig) + modal(w2,s2,a2,trig) + modal(w3,s3,a3,trig));
Ha a fordító nem enged History-t függvényben, vidd az állapotot a főprogramba (History y1a(0), y1b(0) stb. módusonként); a számítás ugyanaz. A gen~ kimenetét hasonlítsd a Demó 1 hangjához (N = 3, ütés és hallgatás a 3. tömegnél).

Python és SuperCollider kód

Kód-labor: Euler és a pontos megoldás (Python)

Három módszer ugyanarra a rezgőre (m=0,01, k=76e3, c=0,049), 22 050 lépés. A két Euler között egyetlen sor a különbség: az x az új vagy a régi sebességet használja. Várt kimenet: explicit ≈ 2,3, majd ≈ 5·1016; szemi és pontos ≈ 0,036. Magyarázat: Elmélet, 7. pont.

import numpy as np
m, k, c, fs = 0.01, 76e3, 0.049, 44100
T = 1/fs

def euler(explicit, J=1.0, dur=0.5):
    """Lépésenként számolt rezgő. explicit=True: explicit Euler, False: szemi-implicit."""
    x, v = 0.0, J/m                    # az ütés: kezdősebesség
    y = np.zeros(int(fs*dur))
    for n in range(len(y)):
        y[n] = x
        acc = (-k*x - c*v)/m           # a rugó visszahúz, a fék lassít
        v_new = v + T*acc
        x = x + T*(v if explicit else v_new)   # az egyetlen különbség
        v = v_new
    return y

def exact(J=1.0, dur=0.5):
    """Pontos együtthatókkal: y[n] = a1 y[n-1] + a2 y[n-2]."""
    w0, s = np.sqrt(k/m), c/(2*m); wd = np.sqrt(w0**2 - s**2)
    r, th = np.exp(-s*T), wd*T
    a1, a2 = 2*r*np.cos(th), -r*r
    y = np.zeros(int(fs*dur)); y1 = y2 = 0.0
    for n in range(len(y)):
        y[n] = (J/(m*wd)*np.sin(th) if n == 0 else 0) + a1*y1 + a2*y2
        y2, y1 = y1, y[n]
    return y

for nev, y in (("explicit", euler(True)), ("szemi", euler(False)), ("pontos", exact())):
    print(nev, "0,05 s-ig:", np.abs(y[:int(0.05*fs)]).max(), "| 0,5 s-ig:", np.abs(y).max())

Közös alap (Python, SuperCollider)

Python

import numpy as np, wave
LN1000 = np.log(1000)

def oscillator(m, k, c, J=1.0, fs=44100, T=3.0):
    """1. pont: egy tömeg–rugó–fék (SI), kitérés egy J impulzusra."""
    w0, s = np.sqrt(k/m), c/(2*m); wd = np.sqrt(w0**2 - s**2)
    t = np.arange(int(fs*T))/fs
    return J/(m*wd) * np.exp(-s*t) * np.sin(wd*t)

def resonator(m, k, c, J=1.0, fs=44100, T=3.0):
    """Ugyanez két mintás rezgőként: y[n] = a1 y[n-1] + a2 y[n-2]."""
    w0, s = np.sqrt(k/m), c/(2*m); wd = np.sqrt(w0**2 - s**2)
    r, th = np.exp(-s/fs), wd/fs; a1, a2 = 2*r*np.cos(th), -r*r
    y = np.zeros(int(fs*T)); y1 = y2 = 0.0
    for i in range(len(y)):
        y[i] = (J/(m*wd)*np.sin(th) if i == 0 else 0) + a1*y1 + a2*y2
        y2, y1 = y1, y[i]
    return y

def bank(w, s, a, fs=44100, T=3.0):
    """Modális bank. w: szögfrekvencia [rad/s], s: sigma [1/s], a: erősség (1/w_d-t a függvény adja)."""
    w, s, a = map(np.asarray, (w, s, a))
    t = np.arange(int(fs*T))/fs
    ok = (w < 0.9*np.pi*fs) & (s < w)               # Nyquist fölött / túlcsillapított: kihagyjuk
    wd = np.sqrt(w[ok]**2 - s[ok]**2)
    y = (a[ok]/wd * np.exp(-np.outer(t, s[ok])) * np.sin(np.outer(t, wd))).sum(1)
    return 0.5*y/np.max(np.abs(y))

def write_wav(name, y, fs=44100):
    with wave.open(name, "wb") as f:
        f.setnchannels(1); f.setsampwidth(2); f.setframerate(fs)
        f.writeframes((y*32767).astype("<i2").tobytes())

SuperCollider

(
// Közös hangszóró-függvény: spec = [w, s, a] listák (w: rad/s, s: sigma, a: erősség)
~modal = { |spec, dur=4, level=0.5|
    var w = spec[0], s = spec[1], a = spec[2];
    var nyq = 0.9*pi*Server.default.sampleRate;
    var ok  = (0..w.size-1).select { |i| (w[i] < nyq) and: { s[i] < w[i] } };
    var wd  = ok.collect { |i| (w[i].squared - s[i].squared).sqrt };
    var amp = ok.collect { |i, j| a[i] / wd[j] };
    var sg  = ok.collect { |i| s[i] };
    var t   = Sweep.ar(Impulse.ar(0));                       // idő az ütés óta
    var y   = Mix(SinOsc.ar(wd/(2*pi), 0, amp) * (sg.neg * t).exp);
    y * level / amp.abs.sum.max(1e-12) * EnvGen.kr(Env([1,1,0], [dur, 0.05]), doneAction: 2)
};
// 1. pont (egyetlen rezgő): m=0.01, k=76000, c=0.049
{ var m=0.01, k=76000, c=0.049, w0=(k/m).sqrt, s=c/(2*m), wd=(w0.squared-s.squared).sqrt;
  SinOsc.ar(wd/(2*pi)) * (s.neg * Sweep.ar(Impulse.ar(0))).exp * 0.3 * EnvGen.kr(Env([1,1,0],[3,0.05]), doneAction: 2) ! 2 }.play;
)

Feladatok (1. óra)

  1. Három beállítás (az 1. pont és az 1. demó után). Számold ki \(f_0\), \(\zeta\), \(T_{60}\) és \(c_{krit}\) értékét: (a) \(m=10\) g, \(k=76\) kN/m, \(c=0{,}049\) N·s/m; (b) \(m=5\) g, \(k=300\) kN/m, \(c=7{,}6\) N·s/m; (c) \(m=10\) g, \(k=76\) kN/m, \(c=55{,}1\) N·s/m. Ellenőrizd a láncdemóval (N = 1).
  2. N = 2 kézzel. Számold ki \(f_1\), \(f_2\) és a módusalakokat \(f_0=439\) Hz-re, majd az amplitúdóarányt \(a_2/a_1\) (ütés és hallgatás a 2. tömegnél).
  3. Python (házi). Futtasd a Kódok fül oscillator és resonator függvényét (m=0.01, k=76e3, c=0.049), és vesd össze a két kimenetet: mekkora a relatív eltérésük, ha az egyiket egy mintával eltolod? Miért?
  4. gen~ (házi). Állítsd be az 1. kódot az (a), (b), (c) értékekre. Mit mutat a spectroscope~, és mikor tűnik el a csengés? Hasonlítsd a számolt \(f_0\), \(\zeta\), \(T_{60}\) értékekhez.
  5. gen~ (Euler). A 2. kóddal mérd meg a három pólussugarat. Majd \(k=500\) kN/m, \(m=1\) g mellett nézd, mennyivel tér el a szemi-implicit frekvenciája a pontostól (várt kb. 1,1%).
  6. gen~ (bank). A 3. kódban állítsd \(p=q=1\)-re, majd \(p=q=3\)-ra. Melyik módus súlya változik a legtöbbet? Támaszd alá az \(a_n\) értékekkel (12. pont).
  7. gen~ (kiterjesztés). Írd át a 3. kódot fal–fal láncra (12. pont táblázata), és mérd az \(f_n/f_1\) arányokat \(N=3\)-ra. Mennyire harmonikus a sor?

Mini-teszt (6 kérdés, 10 pont)

  1. (1 pont) Mekkora \(f_0\), ha \(m=10\) g, \(k=76\) kN/m?
  2. (2 pont) \(m=5\) g, \(k=300\) kN/m, \(c=7{,}6\) N·s/m: mekkora \(\zeta\) és \(T_{60}\)?
  3. (1 pont) Mekkora a kritikus csillapítás \(m=10\) g, \(k=76\) kN/m esetén?
  4. (2 pont) Két tömegű fal–szabad láncban mekkora \(f_2/f_1\)?
  5. (2 pont) Miért száll el az explicit Euler?
  6. (2 pont) Mi a cos szerepe az \(a_1=2r\cos\theta\) együtthatóban?

Skála: 9–10 kiváló · 7–8 jó · 5–6 megfelelő · 4 vagy kevesebb: nézd át a Megoldások fület.

Megoldások (ellenőrzéshez)

1. feladat. \(c_{krit}=2\sqrt{km}\).

\(f_0\)\(\zeta\)\(T_{60}=13{,}8\,m/c\)\(c_{krit}\)
(a)438,8 Hz\(8{,}9\cdot10^{-4}\)2,82 s55,1 N·s/m
(b)1232,8 Hz0,0989,1 ms77,5 N·s/m
(c)438,8 Hz0,9993 (majdnem kritikus)2,5 ms55,1 N·s/m

A (c) esetben \(\omega_d\approx0\), a rendszer nem lengést, hanem gyors lecsengést ad (a demóban a hang tompa „puffanás”).

2. feladat. \(f_1=271\) Hz, \(f_2=710\) Hz; \(\mathbf u_1=(1;1{,}618)\), \(\mathbf u_2=(1;-0{,}618)\). Módus-tömegek: \(m_1=3{,}618\,m\), \(m_2=1{,}382\,m\). Ütés és hallgatás a 2. tömegnél: erősség \(a_n/\omega_n=u_n(2)^2/(m_n\omega_n)\), tehát \(a_1\propto0{,}7236/\omega_1\), \(a_2\propto0{,}2764/\omega_2\), így \(a_2/a_1=0{,}382\cdot0{,}382\approx0{,}146\) (a 2. módus kb. 17 dB-lel halkabb).

3. feladat. A relatív eltérés kb. \(6\cdot10^{-5}\) (a két kimenet egy mintával eltolva egyezik).

Mini-teszt. (1) 439 Hz. (2) \(\zeta=0{,}098\), \(T_{60}=9{,}1\) ms. (3) 55,1 N·s/m. (4) \(f_2/f_1=2{,}618\) (nem 1,618). (5) Az explicit Euler \(|a_2|=1-2\sigma T+\omega_0^2T^2\) kis csillapításnál 1 fölé megy, a pólus sugara 1-nél nagyobb, így minden mintánál nő a hang, mint a visszacsatolás. (6) A cos adja a hullám sebességét (az óriáskerék forgása): ez a hangmagasság.

gen~ feladatok. (a) 438,8 Hz, 2,8 s; (b) 1232,8 Hz, 9,1 ms; (c) puffanás. Sugarak: 1,0019 / 0,99994 / 0,99994. Bank: p=q=1-nél az alaphang gyenge, p=q=3-nál erős (a₁ nő). Fal–fal lánc (N = 3): \(f_n\propto\sin(n\pi/8)\), az arány 1 : 1,85 : 2,41, vagyis a húr 1 : 2 : 3 sorához közelít.

Szótár (magyar – angol)

FogalomAngolulJelentés
MódusmodeMozgásforma, ahol minden pont ugyanazon a frekvencián, rögzített arányban mozog.
Sajátfrekvencia, sajátalaknatural frequency, mode shapeA módus ωn és un: a det(K − ω²M) = 0 megoldásai.
Tömeg-, merevség-, csillapításmátrixmass, stiffness, damping matrixM, K, C: a mozgásegyenlet Mẍ + Cẋ + Kx = f mátrixai.
OrtogonalitásorthogonalityumTM un = 0, ha m ≠ n; ezért esik szét a rendszer független rezgőkre.
Módus-tömegmodal massmn = unTM un.
Módus-koordinátamodal coordinateqn: az n. módus kitérése, x = Σ qnun.
Csillapítási tényező, σ, ζdamping ratio, decay rateσ = c/2m [1/s]; ζ = c/(2√(km)) [–]; ζ = 1 a kritikus csillapítás.
Rayleigh-csillapításRayleigh dampingC = αM + βK; σn = (α + βωn²)/2.
T60T60, decay timeA lecsengés ideje 60 dB-lel (az amplitúdó ezredrészére): T60 = ln 1000 / σ.
Impulzusválaszimpulse responseA rendszer válasza egy rövid ütésre; a modális szintézis ennek a módusonkénti összege.
Két pólusú rezgőtwo-pole resonatoryn = a₁yn−1 + a₂yn−2; a modális bank építőeleme.
Explicit / szemi-implicit Eulerexplicit / semi-implicit EulerKözelítő, lépésenkénti számolás; az explicit elszállhat.
Pólus sugarapole radiusr = √(−a2): 1 alatt a hang elhal, 1 fölött elszáll.
Modális bankmodal filter bankPárhuzamosan futó rezgők összege.
Nyquist-frekvenciaNyquist frequencyfs/2; efölötti módust nem szintetizálunk (a demó 0,45·fs-nál vág).
Ütés és hallgatás helyeexcitation / pickup pointAz erősség módusonként un(p)·un(q).
Klank / DynKlankKlank, DynKlank (SuperCollider)Rezonátorbank: frekvencia-, amplitúdó- és 60 dB-es lecsengési lista.
gen~, genexprgen~, genexpr (Max)Mintaszintű jelfeldolgozás Max-ban, szöveges kóddal.

Jelölések és mértékegységek

JelEgységJelentés
m, k, ckg, N/m, N·s/mtömeg, rugómerevség, csillapítás
ω0, f0rad/s, Hz√(k/m), illetve ω0/2π
σ, ζ1/s, –lecsengési ráta, csillapítási tényező
ωdrad/scsillapított szögfrekvencia √(ω² − σ²)
un(j)–az n. módusalak a j. tömegnél
mnkgmódus-tömeg (a demóban m·S)
p, q–ütés és hallgatás helye (tömeg sorszáma)
α, β1/s, sRayleigh-együtthatók (a demóban β µs-ban)
g, fc–, Hzmagas módusok féke, kalapács vágófrekvenciája
fsHzmintavételi frekvencia

Források

JelHivatkozásMire használható
[1]Adrien, J.-M. (1991). The Missing Link: Modal Synthesis. In: De Poli, Piccialli, Roads (szerk.), Representations of Musical Signals, MIT Press, 269. oldaltól.a modális szintézis alapgondolata, 6. és 7. pont
[2]Morrison, J. D., Adrien, J.-M. (1993). MOSAIC: A Framework for Modal Synthesis. Computer Music Journal 17(1), 45–56.modális keretrendszer, Modalys előzménye
[3]van den Doel, K., Pai, D. K. (1998). The Sounds of Physical Shapes. Presence 7(4), 382–395.módusok, ütés helye, bank algoritmus (7. pont)
[4]van den Doel, K., Kry, P. G., Pai, D. K. (2001). FoleyAutomatic: Physically-based Sound Effects for Interactive Simulation and Animation. SIGGRAPH 2001, 537–544.interaktív modális szintézis, anyagparaméterek
[5]O'Brien, J. F., Cook, P. R., Essl, G. (2001). Synthesizing Sounds from Physically Based Motion. SIGGRAPH 2001, 529–536.módusok számítása, csillapítás
[10]Smith, J. O. Physical Audio Signal Processing, W3K Publishing (online: ccrma.stanford.edu/~jos/pasp/).hullámvezetők, két pólusú rezgő, módusok
[12]Cook, P. R. (2002). Real Sound Synthesis for Interactive Applications, A K Peters.modális szintézis játékokban, gyakorlat
[13]Inman, D. J. Engineering Vibration, Pearson.mozgásegyenlet, sajátérték-feladat, modális csillapítás (2–6. pont)
[14]Rayleigh, J. W. S. (1894). The Theory of Sound, 2. kiadás, Macmillan.lineáris rezgések, a módusszétválasztás klasszikus forrása
[15]Bilbao, S. (2009). Numerical Sound Synthesis, Wiley.véges differenciás sémák, stabilitás (7.2 pont)
[16]SuperCollider Help: Klank, DynKlank, Ringz. · Cycling '74: Max dokumentáció, gen~ és genexpr.a Kódok fül gen~ részei (GenExpr, Gen Overview, gen~ Operators: docs.cycling74.com)
[17]Smith, J. O. Review of Physical Signal Models (Music 420), CCRMA, Stanford University. ccrma.stanford.edu/~jos/ReviewPM/ (State Space to Modal Synthesis)pólusok megosztása, diagonalizálás, párhuzamos szűrőbank (9. pont)