Optimaalne meetod perioodilise signaali fundamentaalsageduse (ehk perioodi) määramiseks sõltub signaali iseloomust. Esmalt vaatleme sellist olukorda, kus perioodiliselt leiab aset signaali tugevuse järsk muutus:

Algoritm on kätketud järgmisse funktsiooni, mis tagastab nii perioodi kui ka selle standardhälbe:

from scipy.stats import linregress

def leia_periood(aeg, signaal):
    signaal = signaal - 0.5 * (signaal.min() + signaal.max())
    valitud = np.logical_and( signaal[:-1] > 0, signaal[1:] < 0 )
    üleminekuhetked = aeg[:-1][valitud]
    indeks = np.arange(len(üleminekuhetked))
    T, _, _, _, ΔT = linregress(indeks, üleminekuhetked)
    return T, ΔT

Siin teostatakse järgmised sammud:

Hinnanguliselt, sellisel viisil määratud perioodi viga on ilmselt suurusjärgus $\Delta t/n$, kus $\Delta t$ on mõõtmise ajasamm ja $n$ on tuvastatud täisperioodide arv.

Järgmine levinud stsenaarium on selline, kus signaal on vähemalt ligikaudu harmooniline:

Seega mingit lõiku sellest signaalist võiks sobitada siinus- või koosinusfunktsiooniga. Ei ole ka raske modelleerida amplituudi muutumist, näiteks sumbumist või modulatsiooni. Antud signaali võiks kirjeldada järgmine funktsioon: $$f(t)=Ae^{-kt}\sin(\omega t+\phi) + b.$$ Siin vabad parameetrid on algamplituud $A$, ringsagedus $\omega$, sumbetegur $k$, algfaas $\phi$ ja kesknivoo ehk baasjoon $b$. Selliste mittelineaarsete funktsioonide sobitamiseks (vähimruutude mõttes) vajaliku algoritmi realiseerib scipy.optimize.curve_fit:

from scipy.optimize import curve_fit

#mudelfunktsioon, peab olema vektoriseeritud kujul
f = lambda t, a, k, w, phi, b: a * exp(-k * t) * sin(w * t + phi) + b

#alglähend, katse-eksituse meetodil
p = 0.036, 6, 410, -0.5, 2.495

#esialgu, alglähendi nägemiseks, kommenteerida välja
p, _ = curve_fit(f, aeg, signaal, p)

ξ = np.linspace(0, 0.3, 500)
ψ = f(ξ, *p)

figure(figsize=(6,2.5))
plot(aeg, signaal, 'r-', label='katse', lw=0.75)
plot(ξ, ψ, 'b-', label='mudel')
xlim(0, 0.3)
xlabel('Aeg')
ylabel('Signaal')
grid()
legend()
show()

Kiire Fourier' teisenduse abiga võib ka arvutada signaali spektri tervikuna, kuigi see otseselt põhisagedust ei anna. Sellegipoolest peaks hästi näha olema sageduse nihe, kui võrrelda erinevate signaalide spektreid (või sama signaali spektreid erinevates ajavahemikes). Pikema signaali korral ongi selleks otstarbeks spetsiaalne tööriist scipy.signal.spectrogram.

def arvuta_spekter(aeg, signaal):
    n = len(aeg)
    fft = np.fft.rfft(signaal) / n
    intens = np.abs(fft)**2
    Δt = (aeg[-1] - aeg[0]) / (n - 1)  # keskmine ajasamm
    sagedus = np.fft.rfftfreq(n, Δt)
    return sagedus, intens

sagedus, intens = arvuta_spekter(aeg, signaal)

figure(figsize=(6,2.5))
plot(sagedus, intens, 'b-')
xlim(40, 90)
ylim(0, 3e-5)
xlabel('Sagedus')
ylabel('Intensiivsus')
grid()
show()

Vaata lisaks

Sisukord