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:

Kastsignaal

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 = ( 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:

Kastsignaali perioodi määramine

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:

Harmooniline signaal

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 * np.exp(-k * t) * np.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()
Sumbuv harmooniline võnkumine

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()
Spekter

Vaata lisaks

Sisukord