6.15. Filtreleme ve spektrogramlar¶
Filtreleme, yumuşatma ve büyüklük spektrumları, ham bir FFT’nin yanı başındaki işlerdir: bir örnek akışını yumuşatmak veya bant geçiren filtreden geçirmek, tahsis yapmadan akışlı bir döngüde büyüklük spektrumlarını hesaplamak ve ham çevre birimi arabelleklerini float dizileri olarak yeniden yorumlamak. Mevcut araçlar şunlardır:
sosfilt()– art arda bağlı ikinci derece bölümler aracılığıyla uygulanan dijital filtre.spectrogram()– ara tahsisler olmadan büyüklükabs(fft(...)).from_int16_buffer()ve diğerulab.utilsfrom_*_bufferyardımcıları – dtype’ını yerleşikfrombuffer()işlevinin kapsamadığı bir arabellekten float dizi çekmek için.
6.15.1. sosfilt ile filtreleme¶
sosfilt(), dijital bir sonsuz dürtü yanıtı (IIR) filtresini, ikinci derece bölümlerin (SOS) bir art arda dizisi olarak – sayısal açıdan sağlam bir biçimde – uygular. sos, 6 uzunluğunda bölümlerden oluşan bir dizidir; x ise 1 boyutlu giriştir:
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)
sos dizisinin her satırı, bir biquad bölümü için altı katsayı [b0, b1, b2, a0, a1, a2] içerir. sos dizisi genellikle bir PC üzerinde scipy.signal.iirfilter(..., output='sos') ile önceden hesaplanır ve bir Python değişmezi olarak kamera betiğine kopyalanır.
İsteğe bağlı zi= anahtar sözcüğü, filtre durumunu arabellekler arasında taşır. (n_sections, 2) şeklinde bir başlangıç durumu geçirin; işlev (y, zf) döndürür – filtrelenmiş çıkış ve son durum – böylece bir arabelleğin son durumu bir sonrakinin başlangıç durumunu besler:
y0, zf0 = sp.signal.sosfilt(sos, buffer0, zi=zi)
y1, zf1 = sp.signal.sosfilt(sos, buffer1, zi=zf0)
# ...
Bu, arabelleğe alınmış veriler üzerinde akışlı bir filtre için standart kalıptır – bir seferde 1024 örnek okunan mikrofon girişi, DMA tabanlı parçalarda biriktirilen ADC örnekleri, bir pencere boyunca toplanan IMU okumaları.
6.15.2. Spektrogramlar¶
spectrogram(), Fourier dönüşümünün büyüklüğünü hesaplar. Kavramsal olarak, bir fft() çağrısından sonra np.sqrt(real * real + imag * imag) ifadesine eşdeğerdir, ancak işi tek bir çağrıda toplar – ara real * real, imag * imag, toplamı veya açık büyüklük dizisini herhangi bir anda RAM’de tutmadan. Bu da onu, spektrumların tekrar tekrar hesaplandığı herhangi bir döngüde doğru araç yapar:
from ulab import numpy as np
from ulab import utils
x = np.linspace(0, 10, num=1024)
spectrum = utils.spectrogram(x)
Argüman biçimi fft() ile aynıdır: tek bir gerçel dizi veya giriş bir sanal kısma sahip olduğunda bir (real, imag) çifti.
Üç anahtar sözcük argümanı tahsiste yardımcı olur:
scratchpad=None–spectrogram()işlevinin çalışma alanı olarak kullandığı,2 * len(signal)uzunluğunda 1 boyutlu yoğun bir float dizi.out=None– sonucun yazılacağı 1 boyutlu bir float dizi.log=False–Trueolduğunda, döndürmeden önce büyüklüğünlog()değerini alır; bu aynı çağrıya katlanır.
Akış kalıbı, her şeyi bir kez tahsis etmek ve bir daha asla tahsis yapmamaktır:
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 ...
Bariz ama savurgan sürümle karşılaştırın:
while True:
signal = read_samples(N)
spectrum = np.log(utils.spectrogram(signal)) # two allocations
Her ikisi de aynı sayıları üretir, ancak ilk sürüm döngü içinde hiçbir şey tahsis etmez – kamera her yinelemede aynı belleği kullanmayı sürdürür ve döngü daha hızlı çalışır.
6.15.3. 16 bitten geniş çevre birimi arabellekleri¶
frombuffer(), yalnızca numpy modülünün kendisinin tanımladığı dtype’ları (uint8 / int8, uint16 / int16, float) işler. Bir çevre birimi 32 bitlik tamsayı örnekler ürettiğinde – 24 veya 32 bitlik bir ADC, yüksek çözünürlüklü bir mikrofon – ulab.utils açık dönüştürme yardımcıları sunar:
Her biri bytes benzeri bir arabellek alır ve bir float ndarray döndürür:
from ulab import utils
buf = bytearray([1, 1, 0, 0, 0, 0, 0, 255])
utils.from_uint32_buffer(buf)
# array([257.0, 4278190080.0])
İşlevler, spectrogram() ile aynı tahsis tasarrufu ayarlarını kabul eder:
Bir başlığı atlamak veya okumayı sınırlamak için
count=veoffset=.Önceden tahsis edilmiş bir float diziye yazmak için
out=.Çevre birimi, bayt sırası konusunda MCU ile anlaşmazlığa düştüğünde
byteswap=True.
Birleşik kalıp – döngünün dışından gelen out= arabellekleriyle, doğrudan bir spectrogram() çağrısına giden tek bir from_int32_buffer() çağrısı – yüksek çözünürlüklü bir mikrofon üzerinde çalışan akışlı bir spektrum çözümleyicisi için doğru şablondur.