1. 概述
DPSK调制在AD9361上的实现思路是这样的:首先在Matlab中验证DPSK调制后的频谱,然后在FPGA中采用伪随机序列作为原始数据,经上采样、成形滤波后送入AD9361,由AD9361完成IQ调制并最终发射出去。在本文中,最终的已调DPSK信号,其物理层速率是2Mbps,占用带宽为2.5MHz,物理层与占用带宽是联动的关系。
2. DPSK在Matlab中的实现
读入《成形滤波器的研究与设计》一文中生成的随机序列,进行4倍上采样,然后使用filter函数对上采样后的序列进行成形滤波,滤波器系数也是在《成形滤波器的研究与设计》一文中生成的,成形滤波后输出的数据与载波相乘得到DPSK调制信号,最后绘制DPSK已调信号的频谱。Matlab代码如下:
clear;clc;
ps=1*10^6; %码速率为1MHz
Fs=4*10^6; %采样速率为4MHz
fc=1*10^6; %载波频率为1MHz
N=20000; %仿真数据的长度
coe_int=importdata('D:\Temp\matlab\coe_int.txt');
s=importdata('D:\Temp\matlab\rand_data.txt');
t=0:1/Fs:(N*Fs/ps-1)/Fs; %产生长度为N,频率为fs的时间序列
%以Fs频率采样
Ads=upsample(s',Fs/ps);
rcos_Ads=filter(coe_int,1,Ads);
%产生载频信号
f0=sin(2*pi*fc*t);
%产生DPSK已调信号
dpsk=rcos_Ads.*f0;
%绘制成形滤波后信号频谱、DPSK信号频谱、DPSK信号时域波形
m_dpsk=20*log10(abs(fft(dpsk,1024)));
m_dpsk=m_dpsk-max(m_dpsk);
%m_dpsk=mean(m_dpsk,1);
%设置幅频响应的横坐标单位为MHz
x_f=[0:(Fs/length(m_dpsk)):Fs/2];x_f=x_f/10^6;
%只显示正频率部分的幅频响应
mdpsk=m_dpsk(1:length(x_f));
plot(x_f,mdpsk);
legend('DPSK已调信号频谱');
xlabel('频率(MHz)');ylabel('幅度(dB)');grid on;
最终绘制的DPSK已调信号频谱如下图,可见,信号频谱被限制在1.25MHz左右,与预期是相符的。
3. FPGA生成伪随机数
这段代码用于在FPGA中生成伪随机数作为源,事实上FPGA中不可能真的生成随机数,只是这些数的周期很长而已。有一点需要注意的是,用于DPSK调制的数字序列必须具有随机性,否则频谱会出现单独的峰。伪随机数模块的时钟速率是2MHz。代码如下:
module pn2(clk,rst,data_out);
input clk;
input rst;
output data_out;
reg [7:1] c;
//reg[15:0] cnt;
always @(posedge clk)
begin
if (rst==0)
begin
c<=8'b1010111;
end
else
begin
c[2]<=c[1];
c[3]<=c[2];
c[4]<=c[3];
c[5]<=c[4];
c[6]<=c[5];
c[7]<=c[6];
c[1]<=c[2]^c[3]^c[4]^c[7];
end
end
assign data_out = c[7];
endmodule
4. 星座映射
星座映射其实就是个简单的组合逻辑,在《认识数字基带信号》一文中,已经说明了要采用-1 1这样的序列来替代0 1序列,所以需要把FPGA生成的随机的0 1序列变为随机的-1 1序列,在这里,采用通常的二进制补码来表示-1,以便与其他模块对接。星座映射的代码如下:
module code_convert(
input code_convert_clk,
input code_convert_din,
input code_convert_rst,
output [7:0] dout
);
reg pre_code;
reg pre_code_temp;
reg [7:0] code_convert_dout;
always @(posedge code_convert_clk)
begin
if(code_convert_rst==0)
pre_code_temp <= code_convert_din;
else
begin
if (code_convert_din == pre_code_temp)
begin
code_convert_dout=8'b11111111; //Change to bi-polar code -1.
pre_code_temp <= 1'b0;
end
else
begin
code_convert_dout=8'b00000001; //Change to bi-polar code +1.
pre_code_temp <= 1'b1;
end
end
end
assign dout=code_convert_dout;
endmodule
5. 上采样与成形滤波
这部分可直接使用Vivado的FIR IP核,将其配置为4倍内插方式,并使用《成形滤波器的研究与设计》一文生成的滤波器系数,如下图
这里我们再来看看数据速率的变化。原始数字序列的速率是2Mbps,经过星座映射后仍是2Mbps,但是经过FIR的4倍内插之后,速率变为了8Mbps,由于FIR内插的都是0,在这期间不能让FIR的输入端获得有效数据,于是这里有个很重要的操作,就是保证FIR的输入端在8MHz时钟的驱动下,每4个时钟周期使能一次FIR的m_tvalid信号,这样才能保证结果的正确性。代码如下:
reg [1:0] axis_cnt=0;
always @(posedge clk_8m)
begin
if(!Hard_rstn)
axis_cnt <= 'd0;
else if(s_data_tvalid)
axis_cnt <= axis_cnt + 1'b1;
end
wire m_tvalid;
assign m_tvalid = (s_data_tvalid==1'b1) && (axis_cnt==3'd3);
6. AD9361的配置
我们都知道AD9361内部有2000多个寄存器,配置起来很繁琐,使用ADI的官方软件可以简化操作。本文配置过程重点要考虑AD9361内部的滤波器,如下图。
AD9361每一路发射通道内部集成了4个数字滤波器包括1个可编程FIR滤波器和3个半带滤波器,AD9361内部还集成了2个可编程的模拟滤波器。由于本文中成形滤波器是在FPGA上实现的,所以需要bypass AD9361的FIR滤波器,后面的3个半带滤波器则正常使用,2个模拟滤波器也正常配置。配置过程如下:
生成初始化脚本后,使用convert.exe软件,将脚本转换为verilog代码,如下图
本文中使用FPGA模拟SPI接口直接对进行AD9361配置,ADI公司还提供了no-OS代码,可以移植到单片机上或者FPGA的软核,这里就不展开叙述了。
还有二点值得注意的是:FIR的输出直接给到AD9361,位宽是不匹配的,可直接把FIR的高12位输出给到AD9361,毕竟低位数据影响不大;DPSK方式,IQ支路只用一路就好,本文代码中I路对应FIR输出的高12位,Q路始终为0。代码如下:
assign tx_i_ch1=srrc_out[16:5];
assign tx_q_ch1=12'b0;
assign tx_i_ch2=srrc_out[16:5];
assign tx_q_ch2=12'b0;
至此,已经完成了DPSK调制的所有功能模块,如下图:
使用Vivado编译完整工程,将最终得到的bitstream文件写入FPGA,可以在频谱仪上看到了预期的波形,如下图。