記事中のプログラムは,Arduino IDE 2.1.1, Board Manager esp32 ver. 2.0.9 で動作確認しています.
Teensy4はデシメーションの必要がないくらい処理性能が高いが,ESP32-S3はTeensy4に比べて非力なので,デシメーションが必要となるケースが多いかもしれない.
ライブラリには Decimation FIR filter が用意されているので試してみた.デシメーションフィルタは普通のFIRフィルタに比べ,同じタップ数でもダウンサンプル比をNとすれば,ポリフェーズ分解によってフィルタ処理自体も理想的には1/Nになる.またサンプリング周波数も以降は1/Nとなるのであとの処理も軽くなる.
以下のコードを実行させて,ダウンサンプル比4のデシメーションフィルタと通常のFIRフィルタの処理時間と入出力信号を確認した.タップ数はいずれも1024.
#include <esp_dsp.h>
#define BLOCK_SAMPLES 64
#define Ndec 1024
fir_f32_t fir_dec;
float coeffs_fir_dec[Ndec];
float z_fir_dec[Ndec];
void setup(void) {
Serial.begin(115200);
delay(50);
digitalWrite(48, LOW);
pinMode(48, OUTPUT);
digitalWrite(48, LOW);
float si[BLOCK_SAMPLES]; // Input signal
float so[BLOCK_SAMPLES]; // Output of FIR
float sod[BLOCK_SAMPLES]; // Output of Decimation FIR
// 入力信号(SIN波)
for(int i; i<BLOCK_SAMPLES; i++){
si[i] = sin(2.0f*2.0f*M_PI*(float)i/BLOCK_SAMPLES);
}
// FIR 係数(入力を2倍にするフィルタ)
dsps_d_gen_f32(coeffs_fir_dec, Ndec, 0);
coeffs_fir_dec[0] =2.0f;
// fir_dec をデシメーションフィルタとして初期化
//(ダウンサンプル比4)
dsps_fird_init_f32(&fir_dec, coeffs_fir_dec, z_fir_dec, Ndec, 4, 0);
digitalWrite(48, HIGH);
dsps_fird_f32(&fir_dec, si, sod, BLOCK_SAMPLES);
digitalWrite(48, LOW);
// fir_dec を通常のFIRフィルタとして初期化
dsps_fir_init_f32(&fir_dec, coeffs_fir_dec, z_fir_dec, Ndec);
digitalWrite(48, HIGH);
dsps_fir_f32(&fir_dec, si, so, BLOCK_SAMPLES);
digitalWrite(48, LOW);
for(int i; i<BLOCK_SAMPLES; i++){
Serial.printf("%f %f %f;\n",si[i], so[i], sod[i] );
}
}
void loop(void) {
}
実行時間は下図のとおり,デシメーションフィルタは通常のフィルタに比べおよそ1/3の処理時間になった.1/4でないのはオーバーヘッドなどを考えれば当然かと思うが,デシメーションFIRフィルタによってダウンサンプルを同時に行えば,処理時間をかなり減らすことができそう.もちろん信号帯域は狭くなるが.

入出力信号は下図のようになった.サンプル数が64 から1/4 の16に減少しているのがわかる(17個目以降はゴミ).フィルタ処理としては通常のFIRと同じ処理が行われている(2倍).
