ESP32-S3 AF信号処理ボード(全モード復調)

AM,FMの復調処理を加えて,クラシックなすべてのモードの復調ができるようにした.前の記事と重複する内容があるがあらためて記載する.

まず,デシメーションまでの構成は下図のとおり.

DeMod. のブロックに各モードの復調処理が入る.内容は以下のとおり.

SSBの復調は以下のようなコードとなる.(前の記事と同じ)

     // USB
      dsps_fir_f32(&sfirRe, Lch_in, Lch_out, BLOCK_SAMPLES/DOWN_SAMPLE);
      dsps_fir_f32(&sfirIm, Rch_in, Rch_out, BLOCK_SAMPLES/DOWN_SAMPLE);
      for(int i=0; i<BLOCK_SAMPLES/DOWN_SAMPLE; i++){
        Lch_in[i] =Lch_out[i] - Rch_out[i];
      }
      
      // LSB
      dsps_fir_f32(&sfirRe, Lch_in, Lch_out, BLOCK_SAMPLES/DOWN_SAMPLE);
      dsps_fir_f32(&sfirIm, Rch_in, Rch_out, BLOCK_SAMPLES/DOWN_SAMPLE);
      for(int i=0; i<BLOCK_SAMPLES/DOWN_SAMPLE; i++){
        Lch_in[i] = Lch_out[i] + Rch_out[i]; 
      }
      

複素係数フィルタをとおして,実部と虚部を加算するだけなので非常にシンプル.

AMの復調は以下のとおり.

      // AM
      dsps_fir_f32(&sfirAMRe, Lch_in, Lch_out, BLOCK_SAMPLES/DOWN_SAMPLE);
      dsps_fir_f32(&sfirAMIm, Rch_in, Rch_out, BLOCK_SAMPLES/DOWN_SAMPLE);
      for(int i=0; i<BLOCK_SAMPLES/DOWN_SAMPLE; i++){
        Re=Lch_out[i];
        Im=Rch_out[i];
        float Demod_AM = sqrt(Re*Re+Im*Im); 
        Rch_in[i] = Demod_AM*0.003 + zDC*0.997; // DC component
        zDC = Rch_in[i];                        // DC component
        Lch_in[i] = 3.0f*(Demod_AM - zDC);
      }

複素係数フィルタの代わりに実部,虚部を同じ特性のLPFにとおし(デシメーションフィルタがあるのでこれはなくてもよい),その振幅 Demod_AM を求めている. Demod_AM にはキャリアに相当するDC成分が含まれているのでそれをカットし出力としている.
zDC は float のグローバル変数.

FMの復調は,一般的には信号の位相を求めてそれを微分する.微分は1サンプル前のデータの位相との差をとればよい.その通りやればいいのだが「微分=ノイズ増長」というイメージがあってやりたくなかったので別の方法でFM復調をすることにした.

具体的には上の図にあるように,1サンプル前のデータの複素共役を掛けてその偏角を求める.複素数同士の乗算ではその偏角は加算されるが,複素共役をとった場合は偏角は差分( ≃ 微分)となる.これによって差分や除算なしにFMの復調処理ができた.一般的な方法と比べてどれほどの効果があるかは確認していない.コードは以下のとおり.

      // FM
      for(int i=0; i<BLOCK_SAMPLES/DOWN_SAMPLE; i++){
        Re = Lch_in[i]*zRe + Rch_in[i]*zIm;
        Im = Rch_in[i]*zRe - Lch_in[i]*zIm;
        zRe = Lch_in[i];
        zIm = Rch_in[i];
        Lch_in[i] = 1e5 * atan2(Im, Re) * (float)(fsample/DOWN_SAMPLE);
      }

zRE,zIm は,float のグローバル変数.