2025年10月1日水曜日

Pico FFT - IIRFilter.h 特性確認

Raspberry Pi Pico  
による IIRフィルタ(カットオフ周波数3.5kHz)を下記サイトのライブラリ#include <IIRFilter.h>を使用してIIRフィルタの周波数特性確認を行いました。   



 



参考サイト
●デジタルフィルタアナライザ - DIGITALFILTER.COM【https://digitalfilter.com/products/dfalz/jpdfalz.html
●双一次変換によるIIRフィルタ設計【https://nettyukobo.com/bilinear_transform/
●IIR フィルタ設計の一般的手法【https://ameblo.jp/an-engineer2019/entry-12502847534.html

結線
OLED  Pico
SDA   -   GP16
SCL   -   GP17
VCC   -   3V3
GND   -   GND






tttapa/Filters
【Filters-master】ZIPをダウンロードしてArdunoのライブラリにコピーする。
※計算式はFilters-masterから引用

IIR

IIRフィルタの差分方程式は次のように与えられる。
IIR差分方程式

const double b_coefficients[] = { b_0, b_1, b_2, ... , b_P };
const double a_coefficients[] = { a_0, a_1, a_2, ... , a_Q };
IIRFilter iir(b_coefficients, a_coefficients);
IIR フィルタ設計の一般的手法
ブロック図と計算式は上記サイトから引用

















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

















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























【Coefficients】
 →係数出力

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


































const double b_lp[] = {a0,a1,a2};
const double a_lp[] = {1,b1,b2};
         ↓
const double b_lp[] = {0.262842002,0.525684003,0.262842002};
const double a_lp[] = {1,-0.197631520,0.248999526};
IIRFilter lp(b_lp, a_lp);
lp.filter(入力データ); //入力データ → IIRフィルタ →


HPF(ハイパスフィルタ)







































const double b_lp[] = {a0,a1,a2};
const double a_lp[] = {1,b1,b2};
         ↓
const double b_lp[] = {0.116432507, -0.232865015,0.116432507};
const double a_lp[] = {1,0.906843365,0.372573394};
IIRFilter lp(b_lp, a_lp);
lp.filter(入力データ); //入力データ → IIRフィルタ →














プログラム  Arduino IDE【ボード:Raspberry Pi Pico】

#include <Arduino.h>
#include <U8g2lib.h>
#include <arduinoFFT.h> // v2.0.2
#include <Wire.h>
#include <IIRFilter.h>

//IIR Cutoff-3KHz LPF
//https://github.com/JR3XNW/pico-Program-Lab/blob/main/Filter_sweep_test_SpectrumDisplay_IIR.ino
const double b_lp[] = {0.03478604, 0.06957207, 0.03478604};
const double a_lp[] = {1.0, -1.40750534, 0.54664949};

// 3500Hz LPF IIR
//const double b_lp[] = {0.262842002,0.525684003,0.262842002};
//const double a_lp[] = {1,-0.197631520,0.248999526};

// 8000Hz HPF IIR
//const double b_lp[] = {0.116432507, -0.232865015,0.116432507};
//const double a_lp[] = {1,0.906843365,0.372573394};

IIRFilter lp(b_lp, a_lp);

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0); //ディスプレイ設定
ArduinoFFT<double> FFT;  // v2.0.2 Explicit data types using templates

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

// 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 = lp.filter(signal); //sweep(signal)→iirフィルタ
    //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.setSDA(16);  //SDA
  Wire.setSCL(17);  //SCL
  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 件のコメント:

コメントを投稿

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

github.com/JR3XNW FIR・IIRフイルタ及びライブラリFIR・IIRフイルタを使用しRaspberry Pi Picoによる、Si5351A 7MHz VFO→直交ミキサ→ADC入力→SSB検波【demod = adc_I - adc_Q】→FIR・IIRフィル...