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 のグローバル変数.