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,可以在频谱仪上看到了预期的波形,如下图。