1.FM的模擬調製過程
FM訊號是一種頻率調製訊號,其攜帶的資訊儲存在其訊號的頻率中,透過改變載波的頻率來實現基帶資料的傳輸。
其函式表示式如下:
\[s(t) = A*cos(w_c*t + K_f*\int m(\tau) d\tau)
\]
其中:
\(A\):表示載波幅度。
\(m(\tau)\):表示基帶訊號。
\(w_c\):表示載波訊號角度增量。
\(K_f`\):是調頻靈敏度。
正交調製法公式如下:
\[I(t) = cos(K_f*\int m(\tau) d\tau) \\
Q(t) = sin(K_f*\int m(\tau) d\tau) \\
s(t) = A*(I(t)*cos(w_c*t) - Q(t)*sin(w_c*t))
\]
2.FM的數字正交解調
原理:
對於I路,其中\(\varphi\)表示調製載波與解調載波的相位差:
\[\begin{array}{flalign}
I(n) & = LPF(s(n)*cos(w_c*n + \varphi)) \\
& = \frac{cos(K_f*\sum m(n))*cos(\varphi) + sin(K_f*\sum m(n))*sin(\varphi)}{2} \\
& = \frac{1}{2}*cos(K_f*\sum m(n) - \varphi)
\end{array}
\]
對於Q路:
\[\begin{array}{flalign}
Q(n) & = LPF(s(n)*sin(w_c*n + \varphi)) \\
& = \frac{cos(K_f*\sum m(n))*sin(\varphi) - sin(K_f*\sum m(n))*cos(\varphi)}{2} \\
& = \frac{1}{2}*sin(K_f*\sum m(n) - \varphi)
\end{array}
\]
同時:
\[\begin{array}{flalign}
&\ \frac{Q(n)}{I(n)} = \frac{sin(K_f*\sum m(n)- \varphi)}{cos(K_f*\sum m(n)- \varphi)} = tan(K_f*\sum m(n) - \varphi) \\
&\ SUM(n) = arctan(\frac{Q(n)}{I(n)}) = K_f*\sum m(n) - \varphi\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space
(\frac{Q(n)}{I(n)}) \in (-\pi/2\space\space\space\space\pi/2) \\
&\ M(n) = SUM(n) - SUM(n-1) = K_f* m(n) \\
\end{array}
\]
注:上式推算中使用了arctan
函式,其中arctan
的輸入範圍\((-\pi/2\space\space\space\space\pi/2)\)。當範圍超過將計算錯誤。所以將使用MATLAB的atan2
函式進行計算。
\[\begin{array}{equation}
SUM(n) = atan2(Q(n),I(n)) = K_f*\sum m(n) - \varphi \\
M(n) = SUM(n) - SUM(n-1) = K_f* m(n)
\end{array}
\]
3.MATLAB模擬
模擬程式碼:
fs = 20000;%取樣率
l = 1E3;%基帶訊號點數
f = 100;%基帶訊號
f_c = 2000;%載波訊號
t = 0:1/fs:(l-1)/fs;
mt = cos(2*pi*f*t);
kf = fs * 0.4;
%% IQ訊號
I = cos(kf*cumtrapz(t,mt));
Q = sin(kf*cumtrapz(t,mt));
%% 調製資料
mod_data = I.*cos(2*pi*f_c*t) - Q.*sin(2*pi*f_c*t);
%% 解調
mmm = atan2(Q,I);
demod = zeros(1,length(mmm));
for i = 2:1:length(demod)
demod(i) = mmm(i) - mmm(i-1);
if(demod(i) >= pi)
demod(i) = demod(i) - pi*2;
elseif(demod(i) <= -pi)
demod(i) = demod(i) + pi*2;
else
demod(i) = demod(i);
end
end
%% 儲存IQ資料FPGA使用模擬
fid = fopen('FM.txt','w');
for i = 1:l
fprintf(fid,'%d %d\n',floor(I(i)* (2^13)),floor(Q(i)* (2^13)));
end
fclose(fid);
%% 繪製
figure
time = 3;
subplot(time,1,1);
plot(mt);
title('基帶資料');
subplot(time,1,2);
plot(mod_data);
title('調製資料');
subplot(time,1,3);
plot(demod);
title('解調資料');
結果:
4.FPGA解調
邏輯程式碼:
module fm_demod(
input clk ,
input rst ,
//解調引數
input i_valid ,
input [15:0] i_data_i ,
input [15:0] i_data_q ,
output reg o_rdy ,
output reg [15:0] o_data
);
wire fm_valid ;
wire [23:0] fm_i ;
wire [23:0] fm_q ;
wire fm_rdy ;
wire [47 : 0] m_axis_dout_tdata ;
wire [15:0] fm_phase ;
//AM 解調
assign fm_valid = i_valid ;
assign fm_i = {{8{i_data_i[15]}},i_data_i} ;
assign fm_q = {{8{i_data_q[15]}},i_data_q} ;
cordic_translate cordic_translate (
.aclk (clk ), // input wire aclk
.s_axis_cartesian_tvalid (fm_valid ), // input wire s_axis_cartesian_tvalid
.s_axis_cartesian_tdata ({fm_i,fm_q} ), // input wire [47 : 0] s_axis_cartesian_tdata
.m_axis_dout_tvalid (fm_rdy ), // output wire m_axis_dout_tvalid
.m_axis_dout_tdata (m_axis_dout_tdata ) // output wire [47 : 0] m_axis_dout_tdata
);
reg [15:0] fm_phase_d;
assign fm_phase = m_axis_dout_tdata[24 +:16];
always @(posedge clk)begin
if(rst)begin
o_rdy <= 0;
o_data <= 0;
o_data <= 0;
end
else begin
o_rdy <= fm_rdy;
fm_phase_d <= fm_phase[15:0];
o_data <= fm_phase[15:0] - fm_phase_d;
end
end
endmodule
模擬程式碼:
module tb_fm_demod();
reg clk;
reg rst;
initial begin
clk <= 0;
rst <= 1;
#300
rst <= 0;
end
always #(100/2) clk <=~clk;
reg valid;
reg [15:0] din_i;
reg [15:0] din_q;
wire o_rdy ;
wire [15:0] o_data ;
fm_demod fm_demod(
.clk (clk),
.rst (rst),
.i_valid (valid),
.i_data_i (din_i),
.i_data_q (din_q),
.o_rdy (o_rdy ),
.o_data (o_data )
);
integer file_rd; //定義資料讀指標
integer flag;
initial begin //開啟讀取和寫入的檔案,這裡的路徑要對
file_rd = $fopen("FM.txt","r");
end
reg [15:0] cnt;
always @(posedge clk)begin
if(rst)begin
din_i <= 0;
din_q <= 0;
cnt <= 0;
valid <= 0;
end
else if(cnt <= 1000)begin
valid <= 1;
flag = $fscanf(file_rd,"%d %d",din_i,din_q);
cnt <= cnt + 1;
end
else begin
$fclose(file_rd);
$stop();
end
end
endmodule
模擬結果: