6.15. Suodatus ja spektrogrammit¶
Suodatus, tasoitus ja magnitudispektrit ovat raakaa FFT:tä lähellä olevia tehtäviä: näytevirran tasoitus tai kaistanpäästösuodatus, magnitudispektrien laskeminen suoratoistosilmukassa ilman varaamista ja raakojen oheislaitepuskureiden uudelleentulkinta liukulukutaulukoina. Käytettävissä olevat työkalut:
sosfilt()– digitaalinen suodatin, joka toteutetaan kaskadoiduilla toisen asteen osioilla.spectrogram()– magnitudiabs(fft(...))ilman välivaiheen varauksia.from_int16_buffer()ja muutulab.utils-moduulinfrom_*_buffer-apufunktiot – vetävät liukulukutaulukon puskurista, jonka dtype-tyyppiä sisäänrakennettufrombuffer()ei kata.
6.15.1. Suodatus sosfilt-funktiolla¶
sosfilt() soveltaa digitaalisen äärettömän impulssivasteen (IIR) suodattimen toisen asteen osioiden (SOS) kaskadina – numeerisesti robusti muoto. sos on jono pituudeltaan 6:n osioita; x on yksiulotteinen syöte:
from ulab import numpy as np
from ulab import scipy as sp
x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
sos = [[1, 2, 3, 1, 5, 6],
[1, 2, 3, 1, 5, 6]]
y = sp.signal.sosfilt(sos, x)
Jokainen sos-rivi sisältää kuusi kerrointa [b0, b1, b2, a0, a1, a2] yhdelle biquad-osiolle. sos-taulukko esilasketaan yleensä PC:llä komennolla scipy.signal.iirfilter(..., output='sos') ja kopioidaan kameran skriptiin Python-literaalina.
Valinnainen avainsana zi= kuljettaa suodattimen tilan puskurien välillä. Anna alkutila muodoltaan (n_sections, 2), niin funktio palauttaa (y, zf) – suodatetun tulosteen ja lopullisen tilan – jolloin yhden puskurin lopullinen tila syöttää seuraavan alkutilan:
y0, zf0 = sp.signal.sosfilt(sos, buffer0, zi=zi)
y1, zf1 = sp.signal.sosfilt(sos, buffer1, zi=zf0)
# ...
Tämä on vakiokaava puskuroidun datan suoratoistosuodattimelle – mikrofonisyöte luettuna 1024 näytettä kerrallaan, ADC-näytteet kerättyinä DMA-vetoisina lohkoina, IMU-lukemat kerättyinä ikkunan yli.
6.15.2. Spektrogrammit¶
spectrogram() laskee Fourier-muunnoksen magnitudin. Se vastaa käsitteellisesti lauseketta np.sqrt(real * real + imag * imag) fft()-kutsun jälkeen, mutta kokoaa työn yhteen kutsuun – pitämättä välivaiheen real * real-, imag * imag-arvoja, summaa tai eksplisiittistä magnitudituaulukkoa missään vaiheessa RAM-muistissa. Se tekee siitä oikean työkalun missä tahansa silmukassa, jossa spektrejä lasketaan toistuvasti:
from ulab import numpy as np
from ulab import utils
x = np.linspace(0, 10, num=1024)
spectrum = utils.spectrogram(x)
Argumenttimuoto noudattaa fft()-funktiota: yksi reaalitaulukko tai (real, imag)-pari, kun syötteellä on imaginaariosa.
Kolme avainsana-argumenttia auttaa varaamisessa:
scratchpad=None– yksiulotteinen tiheä liukulukutaulukko pituudeltaan2 * len(signal), jotaspectrogram()käyttää työtilana.out=None– yksiulotteinen liukulukutaulukko, johon tulos kirjoitetaan.log=False– kunTrue, ottaa magnitudinlog()-arvon ennen palauttamista, samaan kutsuun koottuna.
Suoratoistokaava on varata kaikki kerran eikä koskaan varata uudelleen:
from ulab import numpy as np
from ulab import utils
N = 1024
scratch = np.zeros(2 * N)
out = np.zeros(N)
while True:
signal = read_samples(N)
utils.spectrogram(signal, out=out, scratchpad=scratch,
log=True)
# out now holds the log-magnitude spectrum for this window ...
Vertaa ilmeiseen mutta tuhlailevaan versioon:
while True:
signal = read_samples(N)
spectrum = np.log(utils.spectrogram(signal)) # two allocations
Molemmat tuottavat samat luvut, mutta ensimmäinen versio ei varaa mitään silmukan sisällä – kamera pitää saman muistin käytössä joka iteraatiolla, ja silmukka suoriutuu nopeammin.
6.15.3. 16-bittiä leveämmät oheislaitepuskurit¶
frombuffer() käsittelee vain ne dtype-tyypit, jotka numpy itse määrittelee (uint8 / int8, uint16 / int16, float). Kun oheislaite tuottaa 32-bittisiä kokonaislukunäytteitä – 24- tai 32-bittinen ADC, korkearesoluutioinen mikrofoni – ulab.utils tarjoaa eksplisiittiset muunnosapufunktiot:
Kukin ottaa tavumaisen puskurin ja palauttaa liukuluku-ndarray-taulukon:
from ulab import utils
buf = bytearray([1, 1, 0, 0, 0, 0, 0, 255])
utils.from_uint32_buffer(buf)
# array([257.0, 4278190080.0])
Funktiot hyväksyvät samat varaamista säästävät säätimet kuin spectrogram():
count=jaoffset=ohittavat otsikon tai rajaavat lukemisen.out=kirjoittaa ennalta varattuun liukulukutaulukkoon.byteswap=Truekun oheislaite on eri mieltä MCU:n kanssa tavujärjestyksestä.
Yhdistetty kaava – yksi from_int32_buffer()-kutsu suoraan yhteen spectrogram()-kutsuun, molemmat silmukan ulkopuolelta tulevilla out=-puskureilla – on oikea malli korkearesoluutioisella mikrofonilla pyörivälle suoratoistospektrianalysaattorille.