github.com/JR3XNW 【Filter_sweep_test_SpectrumDisplay_FIR.ino】プログラムを使用してESP32によるFIRフィルタ 係数31タップ(カットオフ周波数3kHz)特性確認をしました。
スイープ信号
フイルタを通さない100Hz~10KHzスイープ信号のFFT表示FIR ローパスフィルタ
FIRフィルタ 係数31タップ(カットオフ周波数3kHz)ローパスフィルタを通したスイープ信号のFFT表示
参考サイト
●github.com/JR3XNW
Esp32-devkitc-32e 開発ボード
●Esp32-devkitc-32e 開発ボード
※アマゾンの写真には技適マークがありますが、送られた製品は技適マーク無し(証明書無)
係数計算(参考)
FIR Filter Design【https://www.arc.id.au/FilterDesign.html】
タップ数とFIRリスト貼付
const int filterLength = 31; // Number of filter taps.
float filterBuffer[filterLength] = {0.0};
float firCoeffs[filterLength] = {
-0.000000,
-0.001026,
-0.001240,
0.002142,
0.005542,
-0.000000,
-0.012229,
-0.010697,
0.014843,
0.032960,
-0.000000,
-0.062887,
-0.056238,
0.089366,
0.299299,
0.400000,
0.299299,
0.089366,
-0.056238,
-0.062887,
-0.000000,
0.032960,
0.014843,
-0.010697,
-0.012229,
-0.000000,
0.005542,
0.002142,
-0.001240,
-0.001026,
-0.000000
};
プログラム Arduino IDE【ボード:ESP32 Dev Module】
FIRフィルタ 係数31タップ(カットオフ周波数3kHz)
// https://github.com/JR3XNW/pico-Program-Lab/blob/main/Filter_sweep_test_SpectrumDisplay_FIR.inoD
#include <Arduino.h>
#include <U8g2lib.h>
#include <arduinoFFT.h> // v2.0.2
#include <Wire.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0); //ディスプレイ設定
ArduinoFFT<double> FFT; // v2.0.2 Explicit data types using templates
//FIR Cutoff-3KHz LPF
const int filterLength = 31; // Number of filter taps.
float filterBuffer[filterLength] = {0.0};
float firCoeffs[filterLength] = { // Put the FIR filter coefficients here.
0.001695,0.001201,-0.000905,-0.004228,-0.005427,0.0,
0.011365,0.018584,0.00825,-0.021236,-0.048939,-0.03959,
0.029858,0.145107,0.254511,0.299507,0.254511,0.145107,
0.029858,-0.03959,-0.048939,-0.021236,0.00825,0.018584,
0.011365,0.0,-0.005427,-0.004228,-0.000905,0.001201,0.001695
};
int bufferIndex = 0;
const int samples = 128; // Number of FFT samples.
const float startFrequency = 100.0; // Start frequency (Hz)
const float endFrequency = 10000.0; // End frequency (Hz)
// Update to FIR filter function
float firFilter(float input) {
filterBuffer[bufferIndex] = input; //sweep信号
bufferIndex = (bufferIndex + 1) % filterLength;
float sum = 0.0;
for (int i = 0; i < filterLength; i++) {
int index = (bufferIndex - i + filterLength) % filterLength;
sum += filterBuffer[index] * firCoeffs[i];
}
return sum;
}
// frequency sweep function.
void frequencySweep(double *vReal, double *vImag) {
float frequencyStep = (endFrequency - startFrequency) / samples;
for (int i = 0; i < samples; i++) {
float currentFrequency = startFrequency + (i * frequencyStep);
//sin波 sin*2*π*f*t
float signal = sin(2 * PI * currentFrequency * millis() / 256.0);
float filteredSignal = firFilter(signal); //sweep信号→firフィルタ
//float filteredSignal = signal/2; //sweep信号のみ
vReal[i] = filteredSignal;
vImag[i] = 0;
}
}
// FFT and OLED display functions (line graph display).
void displayFFT(double *vReal, double *vImag) {
FFT.windowing(vReal, samples, FFTWindow::Hamming, FFTDirection::Forward); //vReal 窓関数
FFT.windowing(vImag, samples, FFTWindow::Hamming, FFTDirection::Forward); //vImag 窓関数
FFT.compute(vReal, vImag, samples, FFTDirection::Forward); //FFT処理(複素数で計算)
FFT.complexToMagnitude(vReal, vImag, samples); //複素数を実数に変換
// Clear graph drawing area (overwrite with background color).
// Here, the graph area is overwritten with a black rectangle.
u8g2.setDrawColor(0); // Set background color (usually black).
u8g2.drawBox(0, 0, 128, 52); // Clear graph area.■(始点のX座標, 始点のY座標, 幅, 高さ)
u8g2.setDrawColor(1); // Re-set the drawing color (white).
// Drawing FFT results.
for (int i = 1; i < (samples / 2); i++) {
int x = map(i, 1, samples / 2, 0, 128); //周波数軸(現数値,現下限,現上限,変換下限,変換上限)
int y = map(vReal[i], 0, 14, 53, 0); //信号強度(現数値,現下限,現上限,変換下限,変換上限)
u8g2.drawLine(x, 53, x, y); //スペクトラム表示(始点X座標, 始点Y座標, 終点X座標, 終点Y座標)
}
// Send buffer to update screen.
u8g2.sendBuffer();
}
void setup() {
Wire.begin();
u8g2.begin();
// Redraw the static content (lines and texts) each time to prevent flickering
u8g2.drawFrame(0, 0, 128, 54); //周波数軸:□(座標X,座標Y,幅,高さ)
for (int xl = 10; xl < 128; xl += 13) {
u8g2.drawLine(xl, 53, xl, 55); //周波数目盛(始点X座標, 始点Y座標, 終点X座標, 終点Y座標)
}
u8g2.setFont(u8g2_font_micro_tr); // Set the font for the numbers
u8g2.drawStr(10, 64, "1k"); //(X座標, Y座標, 文字列)
u8g2.drawStr(23, 64, "2k");
u8g2.drawStr(36, 64, "3k");
u8g2.drawStr(49, 64, "4k");
u8g2.drawStr(62, 64, "5k");
u8g2.drawStr(75, 64, "6k");
u8g2.drawStr(88, 64, "7k");
u8g2.drawStr(101, 64, "8k");
u8g2.drawStr(114, 64, "9k");
}
void loop() {
double vReal[samples];
double vImag[samples] = {0}; // Imaginary part is initialized to 0.
frequencySweep(vReal, vImag);
displayFFT(vReal, vImag); // Call a function to display FFT results.
}
0 件のコメント:
コメントを投稿