外乱も何もない「理想的な」BPSK変調信号をミキサにかけた後LPFという段で、前回はLPF生成関数に足をすくわれました。トホホのお約束か。まあなんとか乗り越えた(ホントか?)ように見えるので、今回は気を取り直してBPSK変調された信号にNCO(もどき)の信号を乗じたものをLPFしてみたいと思います。計算するだけなら只。
※「手習ひデジタル信号処理」投稿順 Indexはこちら
※動作確認に使用させていただいているのは、Scilab 6.1.1(Windows版)です。
当方で使用しておりますcomm_tbxは、以下のバージョンです。Scilab環境からATOMS(Scilabのライブラリ管理ツール?)でインストールをいたしたもの。
Scilab Communication Toolbox 0.3.1
補助用の関数定義2件
「計算するだけなら只(電気代が気になる昨今ですが)」ということで、各種ケースを複数計算するために以下の補助関数を追加定義いたしました。
genTESTSEQ.sci
// generate sampling signal of the test sequence // Fs: sampling frequency [Hz] // Fsym: symbol rate [baud] // b: test sequence function testseq=genTESTSEQ(Fs, Fsym, b) nSym=length(b); nLen=Fs/Fsym index = 1; for n=1:nSym for i=1:nLen testseq(index) = b(n); index = index +1; end end endfunction
plotSIG4.sci
function plotSIG4(t, tseq, tWave, sT, cT, L1, L2, L3, L4) clf(); figure(0); subplot(4, 1, 1); plot2d3(t, tseq); xlabel('TIME'); title(L1); subplot(4, 1, 2); plot(t, tWave); xlabel('TIME'); title(L2); subplot(4, 1, 3); plot(t, sT); xlabel('TIME'); title(L3); subplot(4, 1, 4); plot(t, cT); xlabel('TIME'); title(L4); endfunction
上記の追加定義に加えて、過去回で作成済の以下の自前関数も使用しております。
-
- genBPSK.sci
- genNCO.sci
実験用のBPSK変調された入力信号発生
以前の回で生成したのとほぼほぼ同じ信号です。後で波形プロットしやすいように短い20ビットのテストシーケンスを発生したもの。
Fs = 10e5 Fc = 4e3 Fsym = 1e3 Fc2 = 2e3 nLEN = 20 nSYM = Fs/Fsym t0SEQ = prbs(nLEN); tWave = genBPSK(Fs, Fc, Fsym, t0SEQ); t1SEQ = genTESTSEQ(Fs, Fsym, t0SEQ);
ここで、
-
- Fs、サンプリング周波数
- Fc、搬送波周波数
- Fsym、シンボルレート
- Fc2、後で使う中間周波数
です。生成された(変調された)信号波形は tWave に格納されています。
なんちゃってNCOでミキサ
上記のtWave信号に、なんちゃってNCO生成のSIN波、COS波を乗じてミキサしていくのですが、「計算するだけなら只(電気代が気になる昨今ですが)」ということで複数のケースを計算してます。
-
- Fc2(搬送波周波数Fcより低い)を乗じて中間周波数に落とす想定のもの
- Fcを乗じてマイナス方向は「Fc無?」まで一気に落とす想定のもの
また「なんちゃってNCO」生成の信号は、何も言わないとピッタンコで入力信号と位相があってしまっているので、以下のように位相をずらしたものも計算してみました。
-
- 0度
- 30度
- 45度
- 60度
2x4ケースで合計8種類とな。
中間周波数Fc2を使うものが以下に。
[t, swave0, cwave0]=genNCO(Fs, Fc2, nSYM*nLEN, 0); [t, swave30, cwave30]=genNCO(Fs, Fc2, nSYM*nLEN, 30); [t, swave45, cwave45]=genNCO(Fs, Fc2, nSYM*nLEN, 45); [t, swave60, cwave60]=genNCO(Fs, Fc2, nSYM*nLEN, 60); sT0 = swave0' .* tWave; cT0 = cwave0' .* tWave; sT30 = swave30' .* tWave; cT30 = cwave30' .* tWave; sT45 = swave45' .* tWave; cT45 = cwave45' .* tWave; sT60 = swave60' .* tWave; cT60 = cwave60' .* tWave;
ダイレクトにFc使うものが以下に。
[t, swaveC0, cwaveC0]=genNCO(Fs, Fc, nSYM*nLEN, 0); [t, swaveC30, cwaveC30]=genNCO(Fs, Fc, nSYM*nLEN, 30); [t, swaveC45, cwaveC45]=genNCO(Fs, Fc, nSYM*nLEN, 45); [t, swaveC60, cwaveC60]=genNCO(Fs, Fc, nSYM*nLEN, 60); sTC0 = swaveC0' .* tWave; cTC0 = cwaveC0' .* tWave; sTC30 = swaveC30' .* tWave; cTC30 = cwaveC30' .* tWave; sTC45 = swaveC45' .* tWave; cTC45 = cwaveC45' .* tWave; sTC60 = swaveC60' .* tWave; cTC00 = cwaveC60' .* tWave;
上記結果のうちFc2を使った場合の波形プロットが以下です。
plotSIG4(t, t1SEQ, tWave, sT0, cT0, 'TEST SEQ', 'BPSK', 'BPSK.*SIN0', 'BPSK.*COS0');
位相の違うやつらの波形を比べたものが以下に。
plotSIG4(t, sT0, sT30, sT45, sT60, 'BPSK.*SIN0', 'BPSK.*SIN30','BPSK.*SIN45','BPSK.*SIN60');
そしてスペクトル密度が以下に。
clf(); plot_psd(sTC0, Fs, 0 , Fc*4);
ダイレクトFcの方の波形が以下に。
plotSIG4(t, t1SEQ, tWave, sTC0, cTC0, 'TEST SEQ', 'BPSK', 'BPSK.*SINC0', 'BPSK.*COSC0');
この時点でテストシーケンスが読めそうですな。
位相を比較したものが以下に。
plotSIG4(t, sTC0, sTC30, sTC45, sTC60, 'BPSK.*SINC0', 'BPSK.*SINC30','BPSK.*SINC45','BPSK.*SINC60');
スペクトル密度が以下に。
clf(); plot_psd(sTC0, Fs, 0 , Fc*4);
なんちゃってLPF(ローパスフィルタ)
まずはFc2側のI/Q波形にLPF。PSDプロットからカットオフ周波数は3kHzに設定っす。波形プロットまで一気に。
[wft, wfm, fr] = wfir('lp', 500, [0.003 0.0036], 'hm',[0 0]); [sz0, szf] = filter(wft, 1, sT0); [cz0, czf] = filter(wft, 1, cT0); plotSIG4(t, t1SEQ, tWave, sz0, cz0, 'TEST SEQ', 'BPSK', 'SIN0 LPF', 'COS0 LPF');
この状態でのパワースペクトル密度が以下に。
sigZ = complex(cz0, sz0); clf(); plot_psd(sigZ, Fs, 0, Fc*4)
一方、ダイレクトFc側のLPF通過後波形が以下に。LPFのカットオフ周波数は2kHzに設定。
[wft, wfm, fr] = wfir('lp', 500, [0.002 0.003], 'hm',[0 0]); [szC0, szf] = filter(wft, 1, sTC0); [czC0, czf] = filter(wft, 1, cTC0); plotSIG4(t, t1SEQ, tWave, szC0, czC0, 'TEST SEQ', 'BPSK', 'SINC0 LPF', 'COSC0 LPF');
上記のSINC0_LPF波形みると、この時点で「復調」できている風、なんちゃって。
パワースペクトル密度が以下に。
sigCZ = complex(czC0, szC0); clf(); plot_psd(sigCZ, Fs, 0, Fc*4)
「計算するだけなら只(電気代が気になる昨今ですが)」ということで、計算しまくった今回でした。