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.