2026年7月1日水曜日

ESP32S3 - PCM1808 > フィルタ > PCM5102

Tj Lab「ESP32-S3 AF信号処理ボード 」のプログラムを使用してI2SによるFIR・IIRフイルタの特性確認を行いました。
信号発生ソフトWaveGene→PCM1808モジュール(ADC入力)→FIR・IIRフイルタ→PCM5102モジュール(DAC出力)→WaveSpectraでFIR・IIRフイルタ周波数特性を確認。





①FIR・IIRフイルタ(カットオフ3KHz)の周波数特性測定【ESP32 FFT - FIRフィルタ 特性確認】【ESP32 FFT  -  IIRフィルタ 特性確認
②FIR Filter Design使いカットオフ3KHzの係数を使ったFIRフィルタの周波数特性。








参考サイト
回路図



























ESP32-S3 開発ボード
アマゾン購入
5Vピン → 5V出ない(入力ピン)?
(赤い線材)三端子レギュレータから直接5Vを取出しPCM1808のアナログ電圧(5V)に供給。(自己責任で)







PCM5102A - 32ビットDAC
アマゾン購入
【SCK】ブリッジ(内部クロック)












【H1L】(FLT)      L側 ブリッジ
【H2L】(DEMP) L側 ブリッジ
【H3L】(XSMT) H側 ブリッジ
【H4L】(FMT)    L側 ブリッジ








PCM1808 - 24ビットADC
アマゾン購入
回路不明
IC周辺にコンデンサー・抵抗がついているので外付け必要ない?
SCK ー MCLK(マスタークロック)プログラムで変更可能







●I2S・24ビット

 FMT - GND

●スレーブ・モード
 MD1 - GND
 MD0 - GND










WaveGene スイープ信号出力






















WaveSpectra - フィルタ無














WaveSpectra - IIRフィルタ














WaveSpectra - FIRフィルタ①














WaveSpectra - FIRフィルタ②













































ボードマネージャ














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


ライブラリマネージャー








●ESP32-audioI2S-master 
 所定のlibrariesに貼付

【i2s】
【バージョン3.2.1】インストール


プログラム Arduino IDE【ボード:ESP32S3 Dev Module
#include <driver/i2s.h>
#define fsample 48000
#define BLOCK_SAMPLES 64

//buffers
int rxbuf[BLOCK_SAMPLES*2], txbuf[BLOCK_SAMPLES*2];
float Lch_in[BLOCK_SAMPLES], Rch_in[BLOCK_SAMPLES];
float Lch_out[BLOCK_SAMPLES], Rch_out[BLOCK_SAMPLES];

#define MUTE 40 // MUTE control (LOW: Mute)


//FIR Cutoff-3KHz LPF
// https://github.com/JR3XNW/pico-Program-Lab/blob/main/Filter_sweep_test_SpectrumDisplay_FIR.inoD
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 */
float firCoeffs[filterLength] = { //FIR Filter Design
0.000055,
-0.000318,
-0.001401,
-0.003333,
-0.005827,
-0.007995,
-0.008335,
-0.004991,
0.003764,
0.018906,
0.040112,
0.065486,
0.091722,
0.114710,
0.130454,
0.136054,
0.130454,
0.114710,
0.091722,
0.065486,
0.040112,
0.018906,
0.003764,
-0.004991,
-0.008335,
-0.007995,
-0.005827,
-0.003333,
-0.001401,
-0.000318,
0.000055
};

int bufferIndex = 0;

// Update to FIR filter function
float firFilter(float input) {
  filterBuffer[bufferIndex] = input;
  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;
}


//IIR Cutoff-3KHz LPF
//https://github.com/JR3XNW/pico-Program-Lab/blob/main/Filter_sweep_test_SpectrumDisplay_IIR.ino
// フィルターの係数 (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

double filterBufferX[filterOrder + 1] = {0.0};
double filterBufferY[filterOrder + 1] = {0.0};

// 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;
}


/*-----------------------------------------------------------------------------------------------
  Setup
-------------------------------------------------------------------------------------------------*/
void setup(void) {

  Serial.begin(115200);
  delay(50);

  pinMode(MUTE, OUTPUT);
  digitalWrite(MUTE, HIGH); // unmute

  // I2S setup ------------------------------------------------------------
  i2s_config_t i2s_config = {
    .mode =  (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX  | I2S_MODE_RX), //I2S作業モード
    .sample_rate = fsample, //I2Sサンプルレート
    .bits_per_sample = (i2s_bits_per_sample_t)32, //サンプルあたりのI2Sビット
    .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //I2Sチャネルフォーマット
    .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S), //I2S通信フォーマット
    .intr_alloc_flags = 0, //割り込みを割り当てるために使用されるフラグ
    .dma_buf_count = 6, //I2S DMAバッファ数
    .dma_buf_len = BLOCK_SAMPLES*4, //I2S DMAバッファ長
    .use_apll = false, //2SはAPLLをメインI2Sクロックとして使用し、正確なクロックを取得
    .tx_desc_auto_clear = true, //データが利用できない場合にノイズを回避
    .fixed_mclk = 0, //固定MCLK出力を使用するI2S
  };
  i2s_driver_install( I2S_NUM_0, &i2s_config, 0, NULL); //I2S ドライバーをインストールして起動

  i2s_pin_config_t pin_config = {
        .bck_io_num = 42,  //BCK
        .ws_io_num = 2,    //LRC,LCK
        .data_out_num = 41, //DIN
        .data_in_num = 1    //OUT                                                  
    };
  i2s_set_pin( I2S_NUM_0, &pin_config);

}


/*-----------------------------------------------------------------------------------------------
  Signal Process Loop
-------------------------------------------------------------------------------------------------*/
void loop(void) {
  size_t readsize = 0;  
  //Input I2S DMA 受信バッファからデータを読み取り
  esp_err_t res = i2s_read(I2S_NUM_0, &rxbuf[0], BLOCK_SAMPLES*2*4, &readsize, portMAX_DELAY);
  if (res == ESP_OK && readsize==BLOCK_SAMPLES*2*4) {
    int j=0;
    for (int i=0; i<BLOCK_SAMPLES; i++) {
      Lch_in[i] = (float) rxbuf[j];          
      Rch_in[i] = (float) rxbuf[j+1];
      j+=2;
         
    }  
     
    //-------Signal process -------------------------------
    for (int i=0; i<BLOCK_SAMPLES; i++) {  
      Lch_in[i] = firFilter( Lch_in[i]); //firフィルタ
      //Lch_in[i] = iirFilter( Lch_in[i]); //iirフィルタ          
      Lch_out[i] = Lch_in[i];
      Rch_out[i] = Rch_in[i];          
    }
     
    //------------------------------------------------------

    //Output
    j=0;
    for (int i=0; i<BLOCK_SAMPLES; i++) {
      txbuf[j]   = (int) Lch_out[i];
      txbuf[j+1] = (int) Rch_out[i];
      j+=2;
    }
    //I2S DMA送信バッファにデータを書き込み
    i2s_write( I2S_NUM_0, &txbuf[0], BLOCK_SAMPLES*2*4, &readsize, portMAX_DELAY);

  }

}

0 件のコメント:

コメントを投稿

ESP32S3 - SDR受信 PCM1808 > フィルタ > PCM5102 

 Tj Lab「 ESP32-S3 AF信号処理ボード 」プログラムを使用してI2SによるIIR・FIRフィルタSSB受信テストを行いました。 Si5351A 7MHz VFO→直交ミキサ→PCM1808モジュール(ADC入力)→ 復調・IIR・FIRフィルタ→PCM1808モジ...