SDRの構成要素として、DDS(Direct Digital Synthesizer)があります。 手始めにこれを作成します。
DDSは、ROMに書き込んだ波形データをクロックで読み出していくという単純な原理に基づいています。
ROMのアドレス深さは、DDSが出力できる最低周波数を決めます。 今、アドレス深さが1024で、sin波1サイクル分のデータを格納したROMを80MHzのクロックで順番に読み出していくと、12.8μsで1サイクル、78.125kHzのサイン波が出力できます。 これを、2アドレス毎に呼び出すと、156.25kHzの出力になります。 このように、アドレスの間引き方を適当に選択するとクロックの1/2の周波数までの出力を得ることができます。
アドレスを決めるカウンターのビット数をnとすると、
出力周波数 = FTW * クロック周波数 / 2のn乗
という関係になります。 FTWは、Frequency Tuning Wordで、ROMのアドレスレスカウンタに加える値です。
アドレスカウンターのビット数は、DDSの分解能から決定されます。 上の式を変形して、分解能は、
分解能 = 出力周波数 / FTW = クロック周波数 / 2のn乗
となるので、
2のn乗 = クロック周波数 / 分解能
となり、分解能を1Hzとすると、2のn乗は、80Mに近いnで、27になります。
以上を踏まえて、Basys3で実際にDDSを作成しました。
ROMは、20bit x 1024のSingele Port ROMをIPジェネレータで生成しました。 20bit幅は、10bitのsin波データと10bitのcos波データを同時に格納しています。 romデータは、coeファイルをあらかじめ準備しておき、生成する時に読み込みます。
coeファイルの一部を以下に示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
memory_initialization_radix=2; memory_initialization_vector= 01111111110000000000, 01111111110000000011, 01111111110000000110, 01111111110000001001, 01111111110000001101, 01111111110000010000, 01111111110000010011, 01111111110000010110, 01111111100000011001, 01111111100000011100, 01111111100000011111, |
ROMデータは、sin波データの0~1/2パイのデータがあれば、他の象限のデータは生成できますが、制御が面倒なのでsin、cosとも1サイクル分作成しました。
ソースファイルです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
module IQ_DDS( input ddsCLK, input ddsRST, input [26:0] ddsFREQ, output signed [9:0] ddsSIN_OUT, output signed [9:0] ddsCOS_OUT ); reg [26:0] phase = 0; wire signed [9:0] romadd; wire signed [19:0] romout; wire clk; DDS_ROM DDS_ROM(.clka(clk), .addra(romadd), .douta(romout)); assign clk = ~ddsCLK; assign ddsSIN_OUT = romout[9:0]; assign ddsCOS_OUT = romout[19:10]; assign romadd = phase[26:17]; always @(posedge ddsCLK) begin if(ddsRST) phase = 0; else phase = phase + ddsFREQ; end endmodule |
テストベンチです。 出力周波数は、800kHzに設定しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
module DDS_sim; reg clk, rst; reg [26:0] freq; wire [9:0]sin_out, cos_out; parameter STEP = 12.5; always begin clk <= 0; #(STEP/2); clk <= 1; #(STEP/2); end IQ_DDS IQ_DDS(.ddsCLK(clk), .ddsRST(rst), .ddsFREQ(freq), .ddsSIN_OUT(sin_out), .ddsCOS_OUT(cos_out)); initial begin #(STEP*5); rst <= 1; #(STEP*5); rst <= 0; freq <= 27'h147ae1; //800kHz #(STEP*1500); $finish; end endmodule |
シミュレーション結果です。
800kHzのsin波とcos波が出力されているのが確認できました。