平臺:matlab r2021b,vivado2023.1
本文知識內容摘自《軟件無線電原理和應用》
調頻(FM)是載波的瞬時頻率隨調制信號成線性變化的一種調制方式,音頻調頻信號的數學表達式可以寫為:
Fm頻率調制,載波的幅度隨著調制波形的幅度變化而變化。
其中為載波頻率,
為調制信號,
為調制角頻率。
下面是FM調制的matlab實現
clc;
clear;
% 設置參數
fs = 312.5e6; % 采樣率
fc = 20e6; % 載波頻率
fm = 1e6; % 調制信號頻率,內調制最大3mhz
t1 = 0:1/fs:2; % 時間序列,1微秒
t = t1(1:5000); %RW需要取整數計算出的頻率是真實
% 生成調制信號
m = cos(2*pi*fm*t);%正弦波
% m = square(2*pi*fm*t);%方波
% m = sawtooth(2*pi*fm*t, 0.5);%三角波
% m = sawtooth(2*pi*fm*t);% 鋸齒波
% 例如,y=x^2;t=1-5;
% Q=cumtrapa(t,y);
% q0=0;
% q1=0.5*(4+1)+0=2.5;
% q2=0.5*(9+3)+2.5=9;
% q3=0.5*(16+9)+9=21.5;
% q4=0.5*(25+16)+21.5=42;
% 計算積分累計積分結果,返回一個向量
integral_term = cumtrapz(t, m);% 生成載波信號
c = cos(2*pi*fc*t);
% FM調制,
kf = 100e6; % 調頻系數
k = 2*pi*fc*t;
k1= kf*integral_term;
s = cos(2*pi*fc*t + kf*integral_term);
% 繪制時域波形
figure(1);
subplot(3,1,1);
plot(t*1e6, m);
title('調制信號');
xlabel('時間 (μs)');
ylabel('幅度');subplot(3,1,2);
plot(t*1e6, c);
title('載波信號');
xlabel('時間 (μs)');
ylabel('幅度');subplot(3,1,3);
plot(t*1e6, s);
title('調制后信號');
xlabel('時間 (μs)');
ylabel('幅度');figure(2);
subplot(1,1,1);
plot(t*1e6, c, 'r', 'LineWidth', 2); % 使用紅色繪制載波信號,線條寬度為2
title('載波信號');
xlabel('時間 (μs)');
ylabel('幅度');
hold on;plot(t*1e6, s, 'k', 'LineWidth', 2); % 使用黑色繪制調制后信號,線條寬度為2
title('調制后信號');
xlabel('時間 (μs)');
ylabel('幅度');% 繪制頻域波形
figure(3);
% 計算頻譜
N = length(t);
f = (-fs/2:fs/N:fs/2-fs/N); % 頻率向量
M = fftshift(fft(m));
C = fftshift(fft(c));
S = fftshift(fft(s));subplot(3,1,1);
plot(f, abs(M)/N,'b');
title('調制信號頻譜');
xlabel('頻率 (GHz)');
ylabel('幅度');subplot(3,1,2);
plot(f, abs(C)/N,'g');
title('載波信號頻譜');
xlabel('頻率 (GHz)');
ylabel('幅度');subplot(3,1,3);
plot(f, abs(S)/N,'r');
title('調制后信號頻譜');
xlabel('頻率 (GHz)');
ylabel('幅度');
調制波為余弦波時時域和頻域圖像
當調制信號為方波時。
為鋸齒波時
FPGA的實現
當我們的調制波是一個余弦波時。
可以看到我們的調制波形是一個余弦波。載波也是一個余弦波,調制波的頻率隨著調制波形的積
分變化而變化。其變化規律如下。
余弦波時,積分量在0,pi和2pi時最小,對應著在0時頻偏最小,在pi/2時頻率與載波相同,在pi時
頻偏正向最大。在3*pi/2時又與載波頻率相同。在2pi時達到了最小頻偏。
在邏輯中有幾種產生正余弦波形的方式,基于DDS的波形發生器,基于cordic的波形發生器。這里我們使用cordic來產生我們的載波和調制波。
關于cordic的頻率控制字這里說明一下。Cordic是你對其輸入一個角度,他給你計算出y(cos,sin)的一個結果。所以我們需要對頻率控制字執行一個累加的過程。其中cordic的角度范圍表示為(-pi,pi)。
關于輸出的頻率計算公式為
其中為輸出頻率,phase為相位控制字,
為采樣率。
是因為cordic將數據的范圍量化到(-pi,pi)。
所以我們需要控制cordic的累加量
其中p為頻率控制字,pi為載波的頻率控制字,po為頻偏控制字。
例如我們要載波為fi,最大頻偏為fo。假定現在的采樣率時鐘為fs。根據公式
可以算出載波的頻率控制字為
可以算出最大頻偏控制字為
所以又調制波的幅度最大為16’h4000=16’d16384表示最大為正1v。
所以po與幅度的對應關系為
所以最大頻偏和調制波幅度的關系為
其中x為調制波幅度
邏輯實現現在假定調制波為1mhz,載波為8mhz,最大頻偏為2mhz,采樣率為512mhz。
插入FPGA代碼
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/06/06 21:09:44
// Design Name:
// Module Name: vtf_cordic
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module vtf_cordic;reg aclk;
reg rst_n;
reg s_axis_phase_tvalid;
reg [15 : 0] s_axis_phase_tdata;
reg [15 : 0] s_axis_phase_tdata_0;wire m_axis_dout_tvalid;
wire [31 : 0] m_axis_dout_tdata;wire [15:0] sin ;
wire [15:0] cos ;
wire [15:0] sin0 ;
wire [15:0] cos0 ;cordic_0 u_cordic_0 (.aclk (aclk ),// input wire aclk.s_axis_phase_tvalid (s_axis_phase_tvalid ),// input wire s_axis_phase_tvalid.s_axis_phase_tdata (s_axis_phase_tdata ),// input wire [15 : 0] s_axis_phase_tdata.m_axis_dout_tvalid (m_axis_dout_tvalid ),// output wire m_axis_dout_tvalid.m_axis_dout_tdata ({sin,cos} )// output wire [31 : 0] m_axis_dout_tdata
);cordic_0 u_cordic_1 (.aclk (aclk ),// input wire aclk.s_axis_phase_tvalid (s_axis_phase_tvalid ),// input wire s_axis_phase_tvalid.s_axis_phase_tdata (s_axis_phase_tdata_0 ),// input wire [15 : 0] s_axis_phase_tdata.m_axis_dout_tvalid ( ),// output wire m_axis_dout_tvalid.m_axis_dout_tdata ({sin0,cos0} )// output wire [31 : 0] m_axis_dout_tdata
);initial
beginaclk =0;rst_n =0;#100;rst_n =1;#100;s_axis_phase_tvalid =1;endreg [15:0] wave_add;
reg [15:0] phase_tdata;
reg [15:0] phase_tdata_0;
//產生一個載波
always@(posedge aclk or negedge rst_n)
beginif(rst_n == 1'b0)beginwave_add <= 16'b0;endelse beginwave_add <= 16'd32;end
end
always@(posedge aclk or negedge rst_n)
beginif(rst_n == 1'b0)beginphase_tdata <= 16'b0;endelse beginphase_tdata <= phase_tdata + wave_add;end
end
always@(posedge aclk or negedge rst_n)
beginif(rst_n == 1'b0)beginphase_tdata_0 <= 16'b0;endelse if(phase_tdata >= 16'h0 && phase_tdata <= 16'h4000 )beginphase_tdata_0 <= phase_tdata;endelse if(phase_tdata > 16'h4000 && phase_tdata <= 16'h8000 )beginphase_tdata_0 <= phase_tdata - 16'h4000;endelse if(phase_tdata > 16'h8000 && phase_tdata <= 16'hc000 )beginphase_tdata_0 <= phase_tdata - 16'h8000;endelse if(phase_tdata > 16'hc000 && phase_tdata <= 16'hffff )beginphase_tdata_0 <= phase_tdata - 16'hc000;endelse beginphase_tdata_0 <= phase_tdata;end
end
always@(posedge aclk or negedge rst_n)
beginif(rst_n == 1'b0)begins_axis_phase_tdata <= 16'b0;endelse begins_axis_phase_tdata <= 16'he000 + phase_tdata_0;end
end//-------------------------------------------------------------------
reg [15:0] wave_add_m;
reg [15:0] phase_tdat_m;
reg [15:0] phase_tdata_0_m;wire [15:0] sinsin={sin[15],sin[15],sin[15],sin[15],sin[15],sin[15],sin[15],sin[15],sin[15:8]};
//產生一個方波
always@(posedge aclk or negedge rst_n)
beginif(rst_n == 1'b0)beginwave_add_m <= 16'b0;endelse beginwave_add_m <= sinsin + 16'd262;end
end
always@(posedge aclk or negedge rst_n)
beginif(rst_n == 1'b0)beginphase_tdat_m <= 16'b0;endelse beginphase_tdat_m <= phase_tdat_m + wave_add_m;end
end
always@(posedge aclk or negedge rst_n)
beginif(rst_n == 1'b0)beginphase_tdata_0_m <= 16'b0;endelse if(phase_tdat_m >= 16'h0 && phase_tdat_m <= 16'h4000 )beginphase_tdata_0_m <= phase_tdat_m;endelse if(phase_tdat_m > 16'h4000 && phase_tdat_m <= 16'h8000 )beginphase_tdata_0_m <= phase_tdat_m - 16'h4000;endelse if(phase_tdat_m > 16'h8000 && phase_tdat_m <= 16'hc000 )beginphase_tdata_0_m <= phase_tdat_m - 16'h8000;endelse if(phase_tdat_m > 16'hc000 && phase_tdat_m <= 16'hffff )beginphase_tdata_0_m <= phase_tdat_m - 16'hc000;endelse beginphase_tdata_0_m <= phase_tdat_m;end
end
always@(posedge aclk or negedge rst_n)
beginif(rst_n == 1'b0)begins_axis_phase_tdata_0 <= 16'b0;endelse begins_axis_phase_tdata_0 <= 16'he000 + phase_tdata_0_m;end
endalways#0.977 aclk = ~aclk;endmodule
仿真為