Hide code cell source

import matplotlib as mpl
mpl.rcParams['font.size'] = 14
mpl.rcParams["figure.figsize"] = (15, 5)
import warnings
warnings.filterwarnings('ignore')

Linearni, časovno invariantni (LTI) sistemi 2 - prenosne funkcije#

Domača naloga#

Domača naloga

Na podlagi meritev nosilca, ki ste jih v skupini zajeli na prejšnji vaji, izračunajte in prikažite frekvenčne prenosne funkcije pospešenosti za vse pomerjene lokacije vzbujanja na nosilcu. Pri obdelavi zajetih signalov ustrezno uporabite eksponentno okno ter “force” okno s parametri iz podatkov naloge.

Pripravite kratko poročilo (obseg od 3 do 10 celic s kodo v okolju Jupyter Notebook), iz katerega naj bodo razvidni podatki naloge (iz tabele), ter da ste vse parametre in zahteve naloge naloge tudi upoštevali.

Poročilo oddajte v .pdf obliki (glejte navodila za oddajo domačih nalog).

Dodatek: Na podlagi pripravljenih FPF pri različnih točkah nosilca ocenite prvo lastno obliko obravnavanega nosilca.

Lastna oblika podaja razmerje amplitud odziva sistema na vzbujanje v različnih točkah \(i\):

\[\{A\}^r = \{A_0^r, A_1^r, \dots A_i^r \dots A_n^r\}\]

kjer so \(A^r_i\) t. i. modalne konstante sistema pri lastni frekvenci \(\omega_r\).

Modalne konstante lahko ocenite s poljubno metodo (glejte spodnji zaznamek).

Za identifikacijo modalnih konstant lahko uporabite tudi paket sdypy-EMA. Pomagate si lahko s temle primerom uporabe.

Metoda največjih amplitud

Ena najpreprostejših metod modalne identifikacije je metoda največjih amplitud (Peak amplitude, tudi Peak Picking method), zapisana tukaj za frekvenčno prenosno funkcijo pospešenosti (\(A(\omega)\)):

\(\omega_r = \text{arg max}(|A(\omega)|)\) (krožna frekvenca resonančnega vrha)

\(\eta_r = \frac{\omega_a - \omega_b}{\omega_r}\) (razmernik dušenja), kjer sta \(\omega_a\) in \(\omega_b\) t. i. točki polovične moči v okolici \(\omega_r\):

\(|A(\omega_{a, b})| = \frac{|A(\omega_r)|} {\sqrt{2}}\)

Iz FPF za posamezno obravnavano točko \(i\) pa lahko določite modalne konstante:

\(A^r_i = |A_i(\omega_r)| \, \eta_r\)


Hide code cell source

import numpy as np
from scipy import signal
import matplotlib.pyplot as plt

import lvm_read

Frekvenčna prenosna funkcija podajnosti \(\alpha(\omega)\) predstavlja razmerje med (kompleksnimi) amplitudami harmonskega odziva (pomikov) in vzbujanja (sile) za opazovan sistem:

\[ \alpha(\omega) = \frac{X(\omega)}{F(\omega)} \]

Impulzna prenosna funkcija \(h(t)\) podaja odziv sistema na impulzno motnjo.

Odziv na poljubno vzbujanje (signal \(f(t)\)) določa naslednja zveza:

\[ x(t) = f(t) * h(t)= h(t)*f(t), \]

kjer \(*\) označuje konvolucijo.

Note

Impulzna prenosna funkcija in frekvenčna prenosna funkcija sta Fourierov par:

\[ h(t)=\mathcal{F}^{-1}\{\alpha(\omega)\}\qquad\textrm{ali}\qquad% \alpha(\omega)=\mathcal{F}\{h(t)\}. \]

Note

Oblike frekvenčih prenosnih funkcij

\[\begin{split} \begin{aligned} \alpha(\omega)&=\frac{X(\omega)}{F(\omega)},&&\textrm{podajnost ali receptanca (ang. }receptance\text{),}\\ Y(\omega)&=\frac{\dot{X}(\omega)}{F(\omega)}= \mathrm{i}\,\omega\,\alpha(\omega),&&\textrm{pomičnost (ang. }mobility\text{),}\\ A(\omega)&=\frac{\ddot{X}(\omega)}{F(\omega)}=-\omega^2\,\alpha(\omega),&&\textrm{pospešenost (ang. }accelerance\text{),}\\ \end{aligned} \end{split}\]

Opis LTI sistemov#

Odzivni model LTI sistema opišemo z njegovo prenosno funkcijo.

Poglejmo primer enostavnega linearnega oscilatorja, ki ga opisuje gibalna enačba:

\[m \, \ddot{x} + c \, \dot{x} + k \, x = f(t)\]

lin-oscilator

Frekvenčna domena#

Frekvenčna prenosna funkcija podajnosti dušenega linearnega oscilatorja je podana z:

\[\alpha(\omega) = X(\omega) / F(\omega) = \frac{1}{-\omega^2 \, m + \mathrm{i} \, \omega \, c + k}\]

Laplace-ova domena

Fourierova transformacija je posebna oblika Laplace-ove transfomacije, ki jo pogosto uporabimo za pretvorbo diferencialnih enačb v algebrajske enačbe.

Velja naslednja zveza med frekvenčno (\(\omega\)) in Laplace-ovo (\(s\)) domeno:

\(s = \mathrm{i} \, \omega\)

Zgornjo prenosno funkcijo linearnega oscilatorja v \(s\)-domeni tako zapišemo:

\[H(s) = \frac{1}{m \, s^2 + c \, s + k}\]

Poglejmo konkreten primer:

m = 2
k = 50
c = 2.5

freq = np.linspace(0, 10, 101)
w = 2*np.pi*freq
def H_f(freq, m, k, c):
    """
    Frekvenčna prenosna funkcija linearnega oscilatorja.
    """
    omega = 2*np.pi*freq
    return 1 / (-omega**2*m + 1j*omega*c + k)
def H_s(freq, m, k, c):
    """
    Prenosna funkcija linearnega oscilatorja v s-domeni.
    """
    omega = 2*np.pi*freq
    s = 1j*omega
    return 1 / (m*s**2 + c*s + k)

Hide code cell source

plt.plot(freq, np.abs(H_f(freq, m, k, c)), label=r'$H({\omega})$')
plt.plot(freq, np.abs(H_s(freq, m, k, c)), '--', label='$H(s)$')
plt.axvline(x=np.sqrt(k/m) / (2*np.pi), c='k', lw=0.5)
plt.legend()
plt.xlabel('f [Hz]')
plt.ylabel('|H(f)|');
../_images/9b2f7fccf0ed8daa699fcbe6b0469d1e617bf4300b657bf2ab744b9c9691762c.png

Naloga 1 (10 minut): uporaba scipy.signal.lti

Sistem linearnega oscilatorja definirajte z uporabo scipy.signal.lti. Pomagajte si z dokumentacijo.

Pri tem uporabite prenosno funkcijo sistema v \(s\)-domeni:

\[H(s) = \frac{1}{m \, s^2 + c \, s + k}\]

Primerjajte frekvenčno in impulzno prenosno funkcijo, pripravljeni na podlagi zgornje enačbe, s tistima, ki ju dobite z lti.freqresp ter lti.impulse.

T = 1 / (freq[1] - freq[0])
dt =  1/ (2*freq[-1])
t = np.arange(0, T+dt, dt)

Spomnimo se, frekvenčna prenosna funkcija \(\alpha(\omega)\) in impulzna prenosna funkcija \(h(t)\) sta Fourierov par:

h = np.fft.irfft(H_f(freq, m, k, c), n=2*(len(freq)-1)+1)

Hide code cell source

plt.plot(t, h)
plt.xlabel('t [s]')
plt.ylabel('$h(t)$');
../_images/79431e55dc2817cee11299c5d36ebfa2ce8035f00ca5e7fb742cb8607536947e.png
../_images/2e82fad8eebf58ef122b231e39aeabb903e130ebc150e4040691a5e22e8cbc56.png

Opazimo, da sta izračunani impulzni prenosni funkciji različno normirani.

../_images/88d2d364ce409922e3c201e8de85eb1baa00c4fa47845dde790a2937eae77772.png

Naloga 2 (20 minut): lastnosti LTI sistemov

Z uporabo zgoraj pripravljene impulzne prenosne funkcije \(h(t)\) ter lti.output na dva načina prikažite načelo superpozicije:

\[ a_1\,f_1(t)+a_2\,f_2(t) \to {\textrm{Linearen sistem}} \to a_1\,x_1(t)+a_2\,x_2(t) \]

in lastnost časovne invariantnosti:

\[ f(t-t_0) \to {\textrm{Časovno invarianten sistem}} \to x(t-t_0) \]

LTI sistema.

Uporabite spodaj pripravljena signala \(f_1\), \(f_2\) ter vrednosti konstant \(a_1\), \(a_2\).

a_1 = 25
a_2 = -35
f_1 = np.zeros_like(t)
f_1[10:20] = np.sin(2*np.pi*np.arange(10)/20)

f_2 = np.zeros_like(t)
f_2[32:36] = np.sin(2*np.pi*np.arange(4)/8)

Hide code cell source

plt.plot(t, a_1*f_1, label='$a_1 \, f_1(t)$')
plt.plot(t, a_2*f_2, label='$a_2 \, f_2(t)$')
plt.xlabel('t [s]')
plt.ylabel('$f(t)$')
plt.legend();
../_images/7674e418943789d1fb9c3c4fc937f2e906b16f11b60e793f92a4b04d2d8acffd.png
../_images/9ac9ffc8a2a29d3ece981fca597fe169ec2b2e564acf310610e60bb291d65b2b.png
../_images/28a7e32c41199e3501edc5c15a7507f0510675493ce4ad69171ee58eb39f8e4f.png

Obdelava signalov za oceno impulzne prenosne funkcije#

Naloga 3 (30 minut): Prenosne funkcije nosilca

Na primeru nosilca, obravnavanega na prejšnji vaji, ocenimo izmerjene frekvenčne prenosne funkcije pospešenosti nosilca.

\[H(\omega) = A(\omega)=\frac{\ddot{X}(\omega)}{F(\omega)}\]

Naložimo datoteko z meritvami:

meritev_pot = 'data/06/meritev.lvm'
meritev = lvm_read.read(meritev_pot)

Izberimo eno od obravnavanih točk.

Za demonstracijo pomena obdelave zajetih signalov uporabimo le del zajetih časovnih vrst (\(T_{\text{analiza}}\)).

točka = 7
T_analiza = 0.5

dt = meritev[točka]['Delta_X'][0]
N = int(T_analiza * 1/dt)
print(meritev[točka]['Y_Unit_Label'])
['Newtons', 'g', '']
f, a_g = meritev[točka]['data'][:N].T
a = a_g * 9.81
t = np.arange(len(f)) * dt

Hide code cell source

fig, ax = plt.subplots()
ax2 = ax.twinx()
ax.plot(t, a, alpha=1, label='$a(t)$')
ax2.plot(t, f, alpha=1, c='C1', label='$f(t)$')

ax.legend(loc=1)
ax2.legend(loc=2)

ax2.set_ylabel('F [N]')
ax.set_ylabel('a [m/s$^2$]')
ax.set_xlabel('t [s]');
../_images/f6099bf24b35e92a617ed20aa5a3c415514d6ed6cbcc4545f59b5c04105818ec.png

Opazimo, da se v opazovanem časovnem intervalu zajet odziv sistema ne izniha popolnoma.

Poglejmo amplitudna spektra zajetih signalov za izbrano točko:

F = np.fft.rfft(f) / len(f)
F[1:] *= 2

A = np.fft.rfft(a) / len(a)
A[1:] *= 2

freq = np.fft.rfftfreq(len(t), dt)

Hide code cell source

fig, ax = plt.subplots()
ax2 = ax.twinx()
ax.semilogy(freq, np.abs(A), alpha=1, label='$A(f)$')
ax2.semilogy(freq, np.abs(F), alpha=1, c='C1', label='$F(f)$')

ax.legend(loc=1)
ax2.legend(loc=2)

ax2.set_ylabel('|F [N]|')
ax.set_ylabel('a [m/s$^2$]')
ax.set_xlabel('f [Hz]');
../_images/79e68053593be5c6cc4f73810541afde8d79fb59c8ff691427e76f43f43b4dc0.png

Ocenimo frekvenčno prenosno funkcijo:

H = A / F

Hide code cell source

plt.semilogy(freq, np.abs(H))
plt.ylabel('$|H(f)|$')
plt.xlabel('f [Hz]');
../_images/c5ae10327ff07c7527ed2e743d894ddc7ae015311df7561052e0759cc852df90.png

Ekponentno okno#

Da zadostimo predpostavki periodičnosti signala v primeru, ko se odziv sistema v zajetem časovnem intervalu ne izniha, uporabimo t. i. eksponentno okno:

\[w_e(t) = \mathrm{e}^{-t / \tau}\]

Namesto parametra časovne konstante \(\tau\) pogosto želimo podati končno amplitudo \(p\) (v obliki deleža začetne amplitude), ki jo okno doseže pri času \(T\). Velja:

\[\tau = -\frac{T}{\log(p)}\]
p = 0.01 # 1 %
tau = -(len(t) - 1) / np.log(p)
w_exponential = signal.windows.exponential(len(t), center=0, tau=tau, sym=False)
w_exponential[-1]
np.float64(0.010000000000000004)

Primer uporabe eksponentnega okna na numeričnem modelu#

k2 =  (100*2*np.pi)**2
m2 = 1
c2 = 5.

sistem_primer = signal.lti([1], [m2, c2, k2])
f_primer = np.zeros_like(t)
f_primer[1000:1010] = 1.
t, x_primer, _ = sistem_primer.output(f_primer, t)

Hide code cell source

fig, ax = plt.subplots()
ax.plot(t, x_primer, label='odziv')
ax2 = ax.twinx()
ax2.plot(t, f_primer, 'C1', label='vzbujanje');
ax.legend(loc=1)
ax2.legend(loc=2)

ax2.set_ylabel('F [N]')
ax.set_ylabel('x [m]')
ax.set_xlabel('t [s]');
../_images/2dabdd04a477be57ef5531722a1d89b06abab4d98c0f878f6a1a9e5c5277fa21.png
X_primer = np.fft.rfft(x_primer) / len(t)
X_primer[1:] *= 2

Hide code cell source

plt.semilogy(freq, np.abs(X_primer))
plt.xlim(0, 500);
plt.ylabel('$|X(f)|$')
plt.xlabel('f [Hz]');
../_images/b963967da7e3ff1dd2edd93c48dbd7e036f960bf218152a2ac337b01d67bc4e7.png

Ker v opazovanem časovnem oknu nismo zajeli popolnoma periodičnega signala, v amplitudnem spektru opazimo pojav frekvenčnega odtekanja (ang. Spectral Leakage).

Odpravimo ga lahko z ustrezno uporabo oken.

X_okno = np.fft.rfft(x_primer*w_exponential) / len(t)
X_okno[1:] *= 2

Hide code cell source

plt.semilogy(freq, np.abs(X_primer), label='brez okna')
plt.semilogy(freq, np.abs(X_okno), label='z eksponentnim oknom')
plt.xlim(0, 500);
plt.legend()
plt.ylabel('$|H(f)|$')
plt.xlabel('f [Hz]');
../_images/7c3dcb95a2671ba50881f5c2dfb1f92b6071a52b939c961c5c3da38a56933ee2.png
F_primer = np.fft.rfft(f_primer) / len(t)
F_primer[1:] *= 2

w, H_primer = sistem_primer.freqresp(2*np.pi*freq)
H_okno = X_okno/F_primer

Hide code cell source

plt.semilogy(freq, np.abs(H_okno), label='z eksponentnim oknom')
plt.semilogy(freq, np.abs(H_primer), label='sympy.lti')
plt.xlim(0, 500);
plt.ylim(1e-9, 1e-2)
plt.legend()
plt.ylabel('$|H(f)|$')
plt.xlabel('f [Hz]');
../_images/37d40a1858b31c0c0af53faaa6120c0860e511b817b63e1d1014313cf56a1cd7.png

Uporaba eksponentnega okna na meritvi nosilca#

Hide code cell source

fig, ax = plt.subplots()
ax2 = ax.twinx()
ax.plot(t, a, alpha=1, label='$a(t)$')
ax2.plot(t, w_exponential, alpha=1, c='C1', label='$w(t)$')
ax2.set_ylim(-1.1, 1.1)

ax.legend(loc=1)
ax2.legend(loc=2)

ax2.set_ylabel('w(t) [/]')
ax.set_ylabel('a [m/s$^2$]')
ax.set_xlabel('t [s]');
../_images/8057590042572265f96bd78bb1d4c9d2406210427fbcf76e3e48417381d4cf7c.png
a_w = a * w_exponential
A_w = np.fft.rfft(a_w) / len(a_w)
A_w[1:] *= 2

Hide code cell source

fig, ax = plt.subplots()
ax.semilogy(freq, np.abs(A), alpha=1, c='C1', label='$\mathcal{F}(a)$')
ax.semilogy(freq, np.abs(A_w), alpha=1, label='$\mathcal{F}(a \cdot w)$')

ax.legend(loc=1)

ax.set_ylabel('A(f) [N]')
ax.set_xlabel('f [Hz]');
../_images/b76677c7432f537236f2fab46291ed9546366093c2dc26a197e74ce2c125d793.png

Force okno#

Da zmanjšamo vpliv šuma na vhodnem signalu \(f(t)\) uporabimo t. i. “force” okno, s katerim izničimo vrednosti signala sile po koncu udarca.

Parameter “force” okna je dolžina segmenta okna (v obliki deleža skupne dolžine signala) z enotsko amplitudo, ki jo bomo označili z \(l_w\).

Pri pripravi “force” okna si lahko pomagamo z oknom kosinusnega upada scipy.signal.windows.tukey.

l_w = 0.1
N_w = int(l_w * len(t))
w_force = np.zeros_like(t)
w_force[:N_w] = signal.windows.tukey(len(t)*2, alpha=0.05)[-N_w:]

Ker smo na signalu odziva uporabili eksponentno okno, moramo eksponentno okno uporabiti tudi na signalu sile.

w_f = w_force * w_exponential

Hide code cell source

fig, ax = plt.subplots()
ax2 = ax.twinx()
ax.plot(t, w_force, alpha=1, c='C2', label='$w(t)$')
ax.plot(t, w_f, alpha=1, c='C4', label='$w_f(t) \cdot w_e(t)$')
ax2.plot(t, f, alpha=1, c='C1', label='$f(t)$')

ax.legend(loc=0)

ax.set_ylabel('w(t) [/]')
ax2.set_ylabel('f(t) [N]')
ax.set_xlabel('t [s]');
../_images/ba335eca892ef449f00b0880c0afdaf2298753c99f2673276e463b5c9c7069a1.png

Uporaba force okna:

f_w = f * w_f
F_w = np.fft.rfft(f_w) / len(f_w)
F_w[1:] *= 2

Hide code cell source

fig, ax = plt.subplots()
ax.semilogy(freq, np.abs(F), alpha=1, c='C1', label='$\mathcal{F}(f)$')
ax.semilogy(freq, np.abs(F_w), alpha=1, lw=2, label='$\mathcal{F}(f \cdot w)$')

ax.legend(loc=1)

ax.set_ylabel('F [N]')
ax.set_xlabel('f [Hz]');
../_images/087818b018fdb8e76b13746f7fc128fe8172103b40baddb542bdbc8bef0b215f.png

FRF z okni#

H_w = A_w / F_w

Hide code cell source

plt.semilogy(freq, np.abs(H), label='brez oken')
plt.semilogy(freq, np.abs(H_w), label='z okni')
plt.ylabel('$|H(f)|$')
plt.xlabel('f [Hz]')
plt.legend()
plt.xlim(0, 5000);
../_images/ff78d86a5f88ea21022c88e7d92bdb0253c99f71c6e37628aa0fa6da7d32b058.png