CoreGenの設定
DDSの位相アキュムレータは32ビットにしてあります。
DDS Compilerの設定1
DDS Compilerの設定2
DDS Compilerの設定3
DDS Compilerの設定4
DDS Compiler IP Symbol
周波数設定値
D/Aコンバータの動作クロックは77.824MHzですので、基本波としてFM放送波帯の周波数を生成することはできませんが、イメージ成分なら利用できます。例えば、83.5MHzが欲しいとき、DDSで5.676MHzを生成すれば、77.824MHz ±5.676MHz のイメージが出るので83.5MHzだけをフィルタで取り出すという手法があります。
※FMトランスミッタの製作スタート時の発想は、10.7MHzを生成して外付けのアップコンでFM放送波帯に変えようというものでした。
DDSの周波数設定値に適切な重み付けをした音声信号を重畳すればFM変調できたことになります。周波数偏移は、音声のフルスケールで200%変調、すなわち±150kHzになるように合わせます。DDSの動作クロックは77.824MHz、位相アキュムレータは32ビットなので周波数設定入力のMSBから9ビット目以降に音声信号 を接続すれば77.824MHz ×(2^23 / 2^32) = 152kHzの変調度になります。このため事前に音声信号の振幅を150/152倍しておきます。(mod_level.v)
また、音声信号は2の補数形式のためストレートバイナリ形式に変換します。すると、入力信号のない無音時でも音声信号のMSBビットが立つことになり、あたかも周波数設定値にオフセットがかかったように見えます。従って周波数設定値は、このオフセット分を相殺した数値とします。
DDSの周波数設定値
測定結果
DDSで5.676MHzを発生させて、イメージの83.5MHzを見てみます。最初の2枚は、緑色がアナログ入力、黄色がデジタル入力で無音の場合です。デジタル入力の場合、ソースによってはDCオフセットがあるらしく、ぴょこっと周波数がずれてしまうことがありました。DCカット用にハイパスフィルタが必要だと思います。
3枚目は広帯域のスプリアスの様子です。77.824MHzのクロック周波数のほかイメージ成分2本が見えますが、わけのわからないノイズが多すぎます。スプリアスはフィルタを使えば取り除くことができるのでしょうが、仮に送信機のエキサイタとして利用するには素地が良くない気がしますが、チューナの試験用としてなら十分使えます。
訳のわからないノイズは、基板設計の拙さによって他のデバイスのノイズを受けてしまっているからと思っています。
83.5MHz ステレオモード(SPAN 200kHz)
83.5MHz モノラルモード(SPAN 200kHz)
スプリアス(83.5MHz、SPAN 40MHz)
次に、基本波を見てみます。最初の2枚は、緑色がアナログ入力、黄色がデジタル入力で無音の場合です。イメージよりノイズレベルが低く、コーデックのノイズがよく見えます。
3枚目は、広帯域(DC-20MHz)のスペクトラムで、目立ったスプリアスもなく良い感じです。やはりこれを所定の周波数までアップコンしたいところですね。
4枚目と5枚目は、1kHz 100%変調相当での占有周波数帯域幅です。
5.676MHz ステレオモード(SPAN 200kHz)
5.676MHz モノラルモード(SPAN 200kHz)
スプリアス(
5.676MHz、SPAN 20MHz)
5.676MHz ステレオモード占有帯域幅
5.676MHz モノラルモード占有帯域幅
fm_mod.v
module fm_mod(
mod_i, mod_o, clk, reset, mod_set
);
input [23:0] mod_i;
output [13:0] mod_o;
input clk;
input reset;
input mod_set;
wire [13:0] mod_o;
wire [31:0] mod_data;
reg [31:0] pinc_in;
// parameter [24:0] FREQ_OFFSET = 32'h22B286BC; // 10.7MHz
parameter [31:0] FREQ_OFFSET = 32'h122BCA1A; // 5.676MHz(83.5MHz)
// parameter [24:0] FREQ_OFFSET = 32'h2229E50D7; // 10.676MHz(88.5MHz)
assign mod_data = {8'b0, (mod_i[23:0] ^ 24'h800000)};
always @(posedge clk or posedge reset)
begin
if (reset)
pinc_in <= FREQ_OFFSET + 32'h00800000;
else
pinc_in <= FREQ_OFFSET + mod_data;
end
dds_mod dds_mod (
.clk(clk),
.pinc_in(pinc_in),
.sine(mod_o));
endmodule
mod_level.v
module mod_level(
ml_i, ml_o,
clk, reset, ml_thru
);
input [23:0] ml_i;
output [23:0] ml_o;
input clk; // 64fs
input reset;
input ml_thru;
reg [5:0] state64;
reg [23:0] input_reg;
reg [23:0] output_reg;
reg [23:0] ml_o;
wire latch_out;
wire ml_thru;
// State counter
always @(posedge clk or posedge reset)
begin
if (reset)
state64 <= 0;
else if (state64 == 63)
state64 <= 0;
else
state64 <= state64 + 1;
end
assign latch_out = (state64 ==7);
// Attenuation
always @(posedge clk or posedge reset)
begin
if (reset)
begin
input_reg <= 0;
output_reg <= 0;
end
else
begin
case (state64)
0: input_reg <= ml_i;
1: // GAIN * (505/512)
output_reg <= {input_reg[23], input_reg[23:1]}
+ {{2{input_reg[23]}}, input_reg[23:2]};
2: output_reg <= output_reg
+ {{3{input_reg[23]}}, input_reg[23:3]};
3: output_reg <= output_reg
+ {{4{input_reg[23]}}, input_reg[23:4]};
4: output_reg <= output_reg
+ {{5{input_reg[23]}}, input_reg[23:5]};
5: output_reg <= output_reg
+ {{6{input_reg[23]}}, input_reg[23:6]};
6: output_reg <= output_reg
+ {{9{input_reg[23]}}, input_reg[23:9]};
endcase
end
end
// output data register
always @(posedge clk or posedge reset)
begin
if (reset)
ml_o <= 0;
else if (ml_thru)
ml_o <= ml_i;
else if (latch_out)
ml_o <= output_reg;
end
endmodule
0 件のコメント:
コメントを投稿