6.15. การกรองและสเปกโตรแกรม¶
การกรอง การปรับให้เรียบ และสเปกตรัมขนาด เป็นงานที่อยู่ติดกับ FFT ดิบ ได้แก่ การปรับให้เรียบหรือกรองแบบ band-pass สตรีมของตัวอย่าง การคำนวณสเปกตรัมขนาดในลูปการสตรีมโดยไม่ต้องจัดสรรหน่วยความจำ และการตีความบัฟเฟอร์อุปกรณ์ต่อพ่วงดิบใหม่เป็นอาร์เรย์ float เครื่องมือที่มีอยู่:
sosfilt()-- ตัวกรองดิจิทัลที่ใช้ผ่านส่วนอันดับสองแบบเรียงต่อกันspectrogram()-- ขนาดabs(fft(...))โดยไม่มีการจัดสรรหน่วยความจำกลางfrom_int16_buffer()และตัวช่วยเหลือfrom_*_bufferอื่น ๆ ของulab.utils-- ดึงอาร์เรย์ float ออกจากบัฟเฟอร์ที่มี dtype ซึ่งfrombuffer()ในตัวไม่รองรับ
6.15.1. การกรองด้วย sosfilt¶
sosfilt() ใช้ตัวกรองดิจิทัล infinite impulse response (IIR) เป็นแบบเรียงต่อกันของ second-order sections (SOS) ซึ่งเป็นรูปแบบที่มีความเสถียรเชิงตัวเลข sos คือลำดับของส่วนที่มีความยาว 6 ส่วน และ x คืออินพุต 1 มิติ:
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 มีสัมประสิทธิ์หกตัว [b0, b1, b2, a0, a1, a2] สำหรับส่วน biquad หนึ่งส่วน อาร์เรย์ sos มักถูกคำนวณล่วงหน้าบน PC ด้วย scipy.signal.iirfilter(..., output='sos') แล้วคัดลอกลงในสคริปต์กล้องเป็น Python literal
คีย์เวิร์ด zi= ที่เป็นตัวเลือกจะส่งสถานะตัวกรองข้ามบัฟเฟอร์ ส่งสถานะเริ่มต้นที่มีรูปร่าง (n_sections, 2) และฟังก์ชันจะคืนค่า (y, zf) ซึ่งเป็นเอาต์พุตที่กรองแล้วและสถานะสุดท้าย เพื่อให้สถานะสุดท้ายของบัฟเฟอร์หนึ่งป้อนสถานะเริ่มต้นของบัฟเฟอร์ถัดไป:
y0, zf0 = sp.signal.sosfilt(sos, buffer0, zi=zi)
y1, zf1 = sp.signal.sosfilt(sos, buffer1, zi=zf0)
# ...
นี่คือรูปแบบมาตรฐานสำหรับตัวกรองการสตรีมบนข้อมูลบัฟเฟอร์ ไม่ว่าจะเป็นอินพุตไมโครโฟนที่อ่าน 1024 ตัวอย่างต่อครั้ง ตัวอย่าง ADC ที่สะสมเป็นชิ้น ๆ ที่ขับเคลื่อนด้วย DMA หรือการอ่าน IMU ที่รวบรวมไว้ในหน้าต่าง
6.15.2. สเปกโตรแกรม¶
spectrogram() คำนวณขนาดของการแปลงฟูเรียร์ มีความเท่ากันทางแนวคิดกับ np.sqrt(real * real + imag * imag) หลังการเรียก fft() แต่รวมงานทั้งหมดไว้ในการเรียกครั้งเดียว โดยไม่เก็บ real * real, imag * imag, ผลรวม หรืออาร์เรย์ขนาดที่ชัดเจนไว้ใน RAM ณ จุดใดจุดหนึ่ง ทำให้เป็นเครื่องมือที่เหมาะสมในลูปที่คำนวณสเปกตรัมซ้ำ ๆ:
from ulab import numpy as np
from ulab import utils
x = np.linspace(0, 10, num=1024)
spectrum = utils.spectrogram(x)
รูปแบบของอาร์กิวเมนต์เหมือนกับ fft() คืออาร์เรย์จริงหนึ่งอาร์เรย์ หรือคู่ (real, imag) เมื่ออินพุตมีส่วนจินตภาพ
คีย์เวิร์ดสามตัวช่วยในการจัดสรรหน่วยความจำ:
scratchpad=None-- อาร์เรย์ float แบบหนาแน่น 1 มิติที่มีความยาว2 * len(signal)ซึ่งspectrogram()ใช้เป็นพื้นที่ทำงานout=None-- อาร์เรย์ float 1 มิติสำหรับเขียนผลลัพธ์log=False-- เมื่อเป็นTrueให้ใช้log()กับขนาดก่อนคืนค่า โดยรวมไว้ในการเรียกเดียวกัน
รูปแบบการสตรีมคือการจัดสรรทุกอย่างเพียงครั้งเดียวและไม่จัดสรรซ้ำอีก:
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 ...
เปรียบเทียบกับเวอร์ชันที่ชัดเจนแต่สิ้นเปลือง:
while True:
signal = read_samples(N)
spectrum = np.log(utils.spectrogram(signal)) # two allocations
ทั้งสองให้ตัวเลขเดียวกัน แต่เวอร์ชันแรกไม่จัดสรรหน่วยความจำภายในลูป กล้องใช้หน่วยความจำเดิมในทุกรอบการทำงาน และลูปทำงานได้เร็วขึ้น
6.15.3. บัฟเฟอร์อุปกรณ์ต่อพ่วงที่กว้างกว่า 16 บิต¶
frombuffer() รองรับเฉพาะ dtype ที่ numpy กำหนดเอง (uint8 / int8, uint16 / int16, float) เมื่ออุปกรณ์ต่อพ่วงผลิตตัวอย่างจำนวนเต็ม 32 บิต เช่น ADC 24 หรือ 32 บิต หรือไมโครโฟนความละเอียดสูง ulab.utils จะเปิดเผยฟังก์ชันช่วยเหลือการแปลงที่ชัดเจน:
แต่ละตัวรับบัฟเฟอร์ที่คล้ายไบต์และคืนค่า ndarray แบบ float:
from ulab import utils
buf = bytearray([1, 1, 0, 0, 0, 0, 0, 255])
utils.from_uint32_buffer(buf)
# array([257.0, 4278190080.0])
ฟังก์ชันเหล่านี้รับตัวควบคุมการประหยัดการจัดสรรเดียวกันกับ spectrogram():
count=และoffset=เพื่อข้ามส่วนหัวหรือจำกัดการอ่านout=เพื่อเขียนลงในอาร์เรย์ float ที่จัดสรรล่วงหน้าbyteswap=Trueเมื่ออุปกรณ์ต่อพ่วงไม่ตรงกับ MCU ในเรื่องลำดับไบต์
รูปแบบรวม การเรียก from_int32_buffer() หนึ่งครั้งตรงไปยังการเรียก spectrogram() หนึ่งครั้ง ทั้งคู่ใช้บัฟเฟอร์ out= จากภายนอกลูป เป็นเทมเพลตที่ถูกต้องสำหรับเครื่องวิเคราะห์สเปกตรัมแบบสตรีมที่ทำงานบนไมโครโฟนความละเอียดสูง