2025年9月1日月曜日

ESP32 FFT - IIRフィルタ 特性確認

  github.com/JR3XNW【Filter_sweep_test_SpectrumDisplay_IIR.ino】プログラムを使用してESP32によるIIRフィルタ(LPF)周波数特性の確認を行いました。    





カットオフ3KHz










SSD1306 OLED
結線
OLED     ESP32
SDA   -   GP21
SCL   -   GP22
VCC   -   3V3
GND   -   GND







Esp32-devkitc-32e 開発ボード
●Esp32-devkitc-32e 開発ボード
※アマゾンの写真には技適マークがありますが、送られた製品は技適マーク無し(証明書無)





ESP32ボードマネージャ変更














追加ボードマネージャーURLを変更
【https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json】
【esp 32】
【バージョン3.2.0】インストール



係数計算(参考)
デジタルフィルタアナライザ - DIGITALFILTER.COM
【dfalz1】ZIPをダウンロードして展開・実行する

















【Design】
【カットオフ周波数指定】























【Coefficients】
 → 係数出力

LPF(ローパスフィルター)




































double b[filterOrder + 1]  = {a0,a1,a2};
double a[filterOrder + 1] = {1,b1,b2};
       ↓
double b[filterOrder + 1] = {0.262842002,0.525684003,0.262842002};
double a[filterOrder + 1] = {1,-0.197631520,0.248999526};












プログラム Arduino IDE【ボード:ESP32 Dev Module
IIR filter 2次3KHz
//https://github.com/JR3XNW/pico-Program-Lab/blob/main/Filter_sweep_test_SpectrumDisplay_IIR.ino
#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

//IIR Cutoff-3KHz LPF
// フィルターの係数 (2次のバターワースフィルター)
const int filterOrder = 2;
double b[filterOrder + 1] = { 0.03478604, 0.06957207, 0.03478604 }; // 係数b
double a[filterOrder + 1] = { 1.0, -1.40750534, 0.54664949 }; // 係数a

//IIR Cutoff-3.5KHz LPF
//double b[filterOrder + 1] = {0.262842002,0.525684003,0.262842002};
//double a[filterOrder + 1] = {1,-0.197631520,0.248999526};

double filterBufferX[filterOrder + 1] = {0.0}; //filterBufferX初期化
double filterBufferY[filterOrder + 1] = {0.0}; //filterBufferY初期化

const int samples = 128; // Number of FFT samples.
const float startFrequency = 100.0;  // Start frequency (Hz)
const float endFrequency = 10000.0;  // End frequency (Hz)

// IIRフィルターの実装
double iirFilter(double input) {
  // 入力をバッファに追加
  for (int i = filterOrder; i > 0; i--) {
    filterBufferX[i] = filterBufferX[i - 1];
    filterBufferY[i] = filterBufferY[i - 1];
  }
  filterBufferX[0] = input;

  // フィルター出力の計算
  double output = 0.0;
  for (int i = 0; i <= filterOrder; i++) {
    output += b[i] * filterBufferX[i];
    if (i > 0) {
      output -= a[i] * filterBufferY[i];
    }
  }
  filterBufferY[0] = output;

  return output;
}

// 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);
    float signal = sin(2 * PI * currentFrequency * millis() / 256.0);
    double filteredSignal = iirFilter(signal); //sweep信号→iirフィルタ
    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);  // Use new enum types instead of FFT_WIN_TYP_HAMMING and FFT_FORWARD
  FFT.windowing(vImag, samples, FFTWindow::Hamming, FFTDirection::Forward);
  FFT.compute(vReal, vImag, samples, FFTDirection::Forward);  // Change FFT_REVERSE to FFTDirection::Reverse
  FFT.complexToMagnitude(vReal, vImag, samples);  // No change

  // 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); //周波数軸(現数値,現下限,現上限,変換下限,変換上限)
    // Scaling of spectral intensity, changing the third argument (now 14) of the map function
    int y = map(vReal[i], 0, 24, 53, 0); //信号強度(現数値,現下限,現上限,変換下限,変換上限)
    u8g2.drawLine(x, 53, x, y); //スペクトラム表示(始点X座標, 始点Y座標, 終点X座標, 終点Y座標)
  }

  // Display the text "IIR filter 2nd order 3kHz"
  char str[30] = "IIR filter 2nd order 3kHz";
  byte x = u8g2.getStrWidth(str);
  u8g2.setFont(u8g2_font_micro_tr); // Set the font for the numbers
  u8g2.drawStr(128 - x, 5, str);

  // Send buffer to update screen.
  u8g2.sendBuffer();
  delay(20);
}

void setup() {  
  Wire.begin();
  u8g2.begin();  
  // Redraw the static content (lines and texts) each time to prevent flickering
  u8g2.drawLine(0, 53, 128, 53); //周波数軸:□(座標X,座標Y,幅,高さ)
 
  for (int xl = 10; xl < 127; 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(8, 64, "1k");  //(X座標, Y座標, 文字列)
  u8g2.drawStr(21, 64, "2k");
  u8g2.drawStr(34, 64, "3k");
  u8g2.drawStr(47, 64, "4k");
  u8g2.drawStr(60, 64, "5k");
  u8g2.drawStr(73, 64, "6k");
  u8g2.drawStr(86, 64, "7k");
  u8g2.drawStr(99, 64, "8k");
  u8g2.drawStr(112, 64, "9k");
}

void loop() {
  double vReal[samples];

0 件のコメント:

コメントを投稿

ESP32 SDR - FIR・IIRフィルタ 受信テスト

github.com/JR3XNW FIR・IIRフイルタを使用してESP32開発ボードによる、Si5351A 7MHz VFO→直交ミキサ→ADC入力→SSB検波【demod = adc_I - adc_Q】→FIR・IIRフイルタ→内蔵DAC出力→スピーカー  7MHzの受信...