1.DDC(Direct Digital Controller)

​ DDC即在数字系统中对信号进行下变频,实现从射频(中频)信号到基带信号的转变。模拟上下变频的系统框图如下:

对于QAM等调制信号,通常有同相和正交两路基带信号,对应正弦和余弦两路同频载波,其模拟上下变频的系统框图如下:

上图描述的过程可用的数学表达如下:
s ( t ) = I ( t ) cos ⁡ ( 2 π f c t ) − Q ( t ) sin ⁡ ( 2 π f c t ) I 路 : s ( t ) cos ⁡ ( 2 π f c t ) = I ( t ) cos ⁡ 2 ( 2 π f c t ) − Q ( t ) cos ⁡ ( 2 π f c t ) sin ⁡ ( 2 π f c t ) = I ( t ) 1 + cos ⁡ ( 2 π ∗ 2 f c t ) 2 − Q ( t ) sin ⁡ ( 2 π 2 ∗ f c t ) 2 = = L P F I ( t ) 2 Q 路 : s ( t ) ( − sin ⁡ ( 2 π f c t ) ) = I ( t ) cos ⁡ ( 2 π f c t ) sin ⁡ ( 2 π f c t ) + Q ( t ) sin ⁡ 2 ( 2 π f c t ) = I ( t ) sin ⁡ ( 2 π 2 ∗ f c t ) 2 + Q ( t ) 1 − cos ⁡ ( 2 π ∗ 2 f c t ) 2 = = L P F Q ( t ) 2 s(t)=I(t)\cos(2\pi f_ct)-Q(t)\sin(2\pi f_ct)\\ I路:s(t)\cos(2\pi f_ct)=I(t)\cos^2(2\pi f_ct)-Q(t)\cos(2\pi f_ct)\sin(2\pi f_ct)\\=I(t)\frac{1+\cos (2\pi*2f_ct)}{2}-Q(t)\frac{\sin(2\pi 2*f_ct)}{2}\overset{LPF}{==}\frac{I(t)}{2}\\ Q路:s(t)(-\sin(2\pi f_ct))=I(t)\cos(2\pi f_ct) \sin (2\pi f_ct)+Q(t)\sin^2(2\pi f_ct)\\=I(t)\frac{\sin(2\pi 2*f_ct)}{2}+Q(t)\frac{1-\cos (2\pi*2f_ct)}{2}\overset{LPF}{==}\frac{Q(t)}{2} s(t)=I(t)cos(2πfct)Q(t)sin(2πfct)Is(t)cos(2πfct)=I(t)cos2(2πfct)Q(t)cos(2πfct)sin(2πfct)=I(t)21+cos(2π2fct)Q(t)2sin(2π2fct)==LPF2I(t)Qs(t)(sin(2πfct))=I(t)cos(2πfct)sin(2πfct)+Q(t)sin2(2πfct)=I(t)2sin(2π2fct)+Q(t)21cos(2π2fct)==LPF2Q(t)
若使用复信号表述该过程,则有:

上述过程的数学表达如下:
s ( t ) = ( I + j Q ) e j 2 π f c t = ( I + j Q ) ( cos ⁡ ( 2 π f c t ) + j sin ⁡ ( 2 π f c t ) ) = I cos ⁡ ( 2 π f c t ) + j I sin ⁡ ( 2 π f c t ) + j Q cos ⁡ ( 2 π f c t ) − Q sin ⁡ ( 2 π f c t ) 取 其 实 部 , 则 有 s t x ( t ) = I cos ⁡ ( 2 π f c t ) − Q sin ⁡ ( 2 π f c t ) 恢 复 过 程 : s t x ( t ) e − j 2 π f c t = ( I cos ⁡ ( 2 π f c t ) − Q sin ⁡ ( 2 π f c t ) ) ( cos ⁡ ( 2 π f c t ) − j sin ⁡ ( 2 π f c t ) ) = I ( cos ⁡ 2 ( 2 π f c t ) ) − j I ( cos ⁡ ( 2 π f c t ) sin ⁡ ( 2 π f c t ) ) − Q ( sin ⁡ ( 2 π f c t ) cos ⁡ ( 2 π f c t ) ) + j Q ( sin ⁡ 2 ( 2 π f c t ) ) = I 1 + cos ⁡ ( 2 π 2 ∗ f c t ) 2 − j I sin ⁡ ( 2 π 2 ∗ f c t ) 2 − Q sin ⁡ ( 2 π 2 ∗ f c t ) 2 + j Q 1 − cos ⁡ ( 2 π 2 ∗ f c t ) 2 = = L P F I + j Q s(t)=(I+jQ)e^{j2\pi f_ct}=(I+jQ)(\cos(2\pi f_ct)+j\sin(2\pi f_ct))\\=I\cos(2\pi f_ct)+jI\sin(2\pi f_ct)+jQ\cos(2\pi f_ct)-Q\sin(2\pi f_ct)\\取其实部,则有s_{tx}(t)=I\cos(2\pi f_ct)-Q\sin(2\pi f_ct)\\恢复过程:s_{tx}(t)e^{-j2\pi f_ct}=(I\cos(2\pi f_ct)-Q\sin(2\pi f_ct))(\cos(2\pi f_ct)-j\sin(2\pi f_ct))\\=I(\cos^2(2\pi f_c t))-jI(\cos(2\pi f_ct)\sin(2\pi f_ct))-Q(\sin(2\pi f_ct)\cos(2\pi f_ct))+jQ(\sin^2(2\pi f_ct))\\=I\frac{1+\cos(2\pi 2*f_c t)}{2}-jI\frac{\sin(2\pi 2*f_c t)}{2}-Q\frac{\sin(2\pi 2*f_c t)}{2}+jQ\frac{1-\cos(2\pi 2*f_c t)}{2}\overset{LPF}{==}I+jQ s(t)=(I+jQ)ej2πfct=(I+jQ)(cos(2πfct)+jsin(2πfct))=Icos(2πfct)+jIsin(2πfct)+jQcos(2πfct)Qsin(2πfct)stx(t)=Icos(2πfct)Qsin(2πfct):stx(t)ej2πfct=(Icos(2πfct)Qsin(2πfct))(cos(2πfct)jsin(2πfct))=I(cos2(2πfct))jI(cos(2πfct)sin(2πfct))Q(sin(2πfct)cos(2πfct))+jQ(sin2(2πfct))=I21+cos(2π2fct)jI2sin(2π2fct)Q2sin(2π2fct)+jQ21cos(2π2fct)==LPFI+jQ
为什么使用复信号?

复信号的引入已有几十年的历史。无线通信中,往往使用一对正交的信号传输信息,以提高带宽利用率,有效的减少带内和带外干扰。为了简单明了的描述这对信号,这些系统常被描述为一个复信号,系统的传递函数也用复数描述。使用复信号的好处有:

it often allows for image-reject architectures to be described more compactly and simply; it leads to a graphical or signal-flflow graph (SFG) description of signal-processing systems providing insight, and it often leads to the development of new systems where the use of high-frequency highly selective image-reject fifilters is minimized. The result is more highly integrated systems using less power and requiring less physical space[1].

即,使用复信号可以使得消除镜像频谱的结构的描述变得更简洁;使得描述信号处理系统的信号流图变得更为直观;在开发新系统时,减少高频高选择性的镜频滤波器的使用;最终使得系统的集成度更高,有更小的体积和更少的功耗。

但该论文的题目《Complex Signal Processing is Not Complex》[1]亦指出,复信号的处理并不是复数(复杂)的,在论文中,作者给每一幅复数信号流图都配上了对应的等价实数信号流图。如下:

在实际处理中,还是使用实数信号流图对应的物理结构,如ADI公司在一个回复当利用ADC内部数字下变频(DDC)处理进行抽取时,我的单音实数输入信号丢失了6 dB功率的问题时中提及的处理框图如下:

Matlab根据波形生成.coe文件代码:

f  = 115e6; %中频125MHz,则f0 = 115MHz 115-135MHz
t_p = 50e-6; %脉宽50us
b = 20e6; %带宽20MHz
beta = b/t_p; %调频斜率
f_s =100e6;  %采样率 100MHz
t = 0: 1/f_s:20480/f_s;

chrip_s = cos(2*pi*f.*t+beta.*(t).^2); %ADC采集的实信号
gencoeInitialROM(16,8192,chrip_s,'BRAM.coe');
%将任意信号转为对应位宽,长度的Xilinx ROM初始化格式,并写入文件
%input:  width,ROM数据位宽;  depth,ROM数据深度; signal,待写入信号; filepath,文件路径及文件名
%output: 无,直接查看转化后文件
function gencoeInitialROM(width,depth,signal,filepath)
    signal = signal(1:depth);  %取信号的前depth位
    signal=floor(signal*(2^(width-1)-1));  % 转换成对应位宽的整数
    figure;
    plot(signal);  %查看转换结果
    fid=fopen(filepath,'w');  %创建.coe文件
    start_line1 = 'memory_initialization_radix=10;';
    start_line2 = 'memory_initialization_vector =';
    fprintf(fid,'%s \n',start_line1);
    fprintf(fid,'%s \n',start_line2);
    fprintf(fid,'%d,\n',signal);  %向.coe文件中写入数据
    fseek(fid,-2, 'eof'); %将文件指针移至最后一个逗号处
    fwrite(fid,';') %将最后一个逗号改为分号
    fclose(fid);  %关闭.coe文件
end

带通信号经过带通采样,再经DDC变换到基带的MATLAB代码如下:

`

clear;
close all;
clc;

f  = 115e6; %中频125MHz,则f0 = 115MHz 115-135MHz
t_p = 50e-6; %脉宽50us
b = 20e6; %带宽20MHz
beta = b/t_p; %调频斜率
f_s =100e6;  %采样率 100MHz
f_l = 25e6;     %NCO 25MHz
t = 0: 1/f_s:16383/f_s;

 NCO = exp(-1i.*2.*pi.*f_l.*t); %复本振
 figure;plot3(t(1:200),real(NCO(1:200)),imag(NCO(1:200)));title('复本振时域波形');xlabel('时间');ylabel('实部');zlabel('虚部');
 fft_plot(NCO,f_s,'复本振信号');  
G = rectpuls(t-t_p/2,t_p);
chrip_bs = G.*exp(1i.*pi.*beta.*t.^2); %发送的复基带信号
IF  = exp(1i.*2.*pi.*f.*t);   %复中频载波
chrip = chrip_bs.*IF;
fft_plot(chrip,f_s,'待发射复基带信号');  %复信号频谱
chrip_tx = real(chrip);  %发射中频的实部,也是ADC采集进入进行下变频的信号
fft_plot(chrip_tx,f_s,'发射实信号'); %ADC采集的信号的频谱
chrip_LO = chrip_tx.*NCO;
fft_plot((chrip_LO),f_s,'乘以复本振后信号'); %乘以复本振后信号频谱
[b,a] = fir1(50,15e6*2/f_s);
 [H,W] = freqz(b,a);
 Hf=abs(H);  %取幅度值实部
Hx=angle(H);  %取相位值对应相位角
figure;
plot(W,20*log(Hf))  %幅值变换为分贝单位
title('滤波器系统幅频特性曲线')
figure;
plot(W,Hx)
title('滤波器系统相频特性曲线')
chrip_b = filter(b,a,chrip_LO);
fft_plot((chrip_b),f_s,'低通滤波后信号'); 
chrip_fake_d = fake_decimation(chrip_b,4); %假4倍抽取
fft_plot((chrip_fake_d),f_s,'假的4倍抽取后信号'); 
chrip_bD = resample(chrip_b,f_s/2,f_s);%信号降采样以降低数据率
fft_plot((chrip_bD),f_s/4,'4倍抽取后信号'); 
figure;
plot(t(1:2:4000),real(chrip_bD(1:2000)));
title('I');xlabel('时间');
figure;
plot(t(1:2:4000),imag(chrip_bD(1:2000)));
title('Q');xlabel('时间');


%% 虚假的抽取,只是隔位置零,采样率不变,以获取周期延拓
%% input:x,待抽取信号;n,抽取倍数
%% output: 抽取后信号
function yn=  fake_decimation(x,n)
    yn = zeros(1,length(x));
    for i = 1 : length(x)
        if mod(i,n)== 1
         yn(i) = x(i);
        else
            x(i) = 0;
        end
    end
end
%% 对信号做FFT,并画图
%% input: y,待分析信号;fs,采样率;s_name,信号名字
function fft_plot(y,fs,s_name)
    L_i = length(y)*2;
    s_i_fft = fft(y,L_i);
    s_i_fftshfit = fftshift(s_i_fft);
    P = abs(s_i_fftshfit/L_i);
    fshift = (-L_i/2:L_i/2-1)*(fs/L_i);
    figure;
    plot(fshift,P);
    title([s_name,'的双边谱 ']);
    xlabel('f (Hz)');
    ylabel('|P(f)|');
end

信号处理过程中的频谱如下:

只有正频率

发射时只有取实部,实信号有对称的双边谱

乘以复本振,被单向搬移(由于是带通采样,有频谱周期延拓,且FFT仅能绘制[-Fs/2,Fs/2]区间的频谱)

低通滤波,取基带部分信号

4倍抽取的中间过程

4倍抽取,以降低后续数据量

I路基带信号时域

Q路基带时域

FPGA处理流程,及波形

FPGA实现过程基于实数形式的信号流图,主要涉及到DDS产生两路正交本振,ROM存储待下变频信号,乘法模块,FIR滤波,时域抽取等。大部分有现成IP核可供调用。

代码:

module DDC(
	  input clk,
	  input en,
	  input rst,
	  output [55:0] i_d4,
	  output [55:0] q_d4,
	  output [55:0] i_data,
	  output [55:0] q_data,
	  output [15:0] sin,
	  output [15:0] cos,
	  output [15:0] LFM,
	  output [31:0] i_cos,
	  output [31:0] q_sin
);
wire [15:0] douta;
wire [31:0]m_axis_data_tdata;
wire [31:0]m_axis_phase_tdata;
wire [31:0] P_i;
wire [31:0] P_q;
reg [12:0]addra;

always @(posedge clk or posedge rst) begin
	if (rst) begin
addra <= 1'b0;
	end
	else begin
addra <= addra + 1'b1;
	end
end

assign LFM = douta;
assign sin = m_axis_data_tdata[15:0];
assign cos = m_axis_data_tdata[31:16];
assign i_cos= P_i;
assign q_sin= P_q;
blk_mem_gen_0 LFMWAVE (
  .clka(clk),    // input wire clka
  .addra(addra),  // input wire [12 : 0] addra
  .douta(douta)  // output wire [15 : 0] douta
);

LO sin_cos (
  .aclk(clk),                                // input wire aclk
  .m_axis_data_tvalid(),    // output wire m_axis_data_tvalid
  .m_axis_data_tdata(m_axis_data_tdata),      // output wire [31 : 0] m_axis_data_tdata
  .m_axis_phase_tvalid(),  // output wire m_axis_phase_tvalid
  .m_axis_phase_tdata(m_axis_phase_tdata)    // output wire [31 : 0] m_axis_phase_tdata
);

mult_i mult_i (
  .CLK(clk),  // input wire CLK
  .A(douta),      // input wire [15 : 0] A
  .B(m_axis_data_tdata[15:0]),      // input wire [15 : 0] B
  .P(P_i)      // output wire [31 : 0] P
);
mult_i mult_q (
  .CLK(clk),  // input wire CLK
  .A(douta),      // input wire [15 : 0] A
  .B(m_axis_data_tdata[31:16]),      // input wire [15 : 0] B
  .P(P_q)      // output wire [31 : 0] P
);

fir_compiler_0 fir_i (
  .aclk(clk),                              // input wire aclk
  .s_axis_data_tvalid(en),  // input wire s_axis_data_tvalid
  .s_axis_data_tready(),  // output wire s_axis_data_tready
  .s_axis_data_tdata(P_i),    // input wire [31 : 0] s_axis_data_tdata
  .m_axis_data_tvalid(),  // output wire m_axis_data_tvalid
  .m_axis_data_tdata(i_data)    // output wire [55 : 0] m_axis_data_tdata
);

fir_compiler_0 fir_q (
  .aclk(clk),                              // input wire aclk
  .s_axis_data_tvalid(en),  // input wire s_axis_data_tvalid
  .s_axis_data_tready(),  // output wire s_axis_data_tready
  .s_axis_data_tdata(P_q),    // input wire [31 : 0] s_axis_data_tdata
  .m_axis_data_tvalid(),  // output wire m_axis_data_tvalid
  .m_axis_data_tdata(q_data)    // output wire [55 : 0] m_axis_data_tdata
);


		decimation#(
			.NDEC(56)
		) inst_decimation_i (
			.clk   (clk),
			.rst  (rst),
			.en    (en),
			.din   (i_data),
			.valid (),
			.dout  (i_d4)
		);
		decimation#(
			.NDEC(56)
		) inst_decimation_q (
			.clk   (clk),
			.rst  (rst),
			.en    (en),
			.din   (q_data),
			.valid (),
			.dout  (q_d4)
		);


endmodule

抽取模块代码:

module  decimation
    #(parameter NDEC = 56)
    (
     input                clk,
     input                rst,
     input                en,
     input [NDEC-1:0]     din,
     output               valid,
     output [NDEC-1:0]    dout);

    reg                  valid_r ;
    reg [2:0]            cnt ;
    reg [NDEC-1:0]       dout_r ;

    //counter
    always @(posedge clk or posedge rst) begin
        if (rst) begin
            cnt <= 3'b0;
        end
        else if (en) begin
            if (cnt==3) begin
                cnt <= 'b0 ;
            end
            else begin
                cnt <= cnt + 1'b1 ;
            end
        end
    end

    //data, valid
    always @(posedge clk or posedge rst) begin
        if (rst) begin
            valid_r        <= 1'b0 ;
            dout_r         <= 'b0 ;
        end
        else if (en) begin
            if (cnt==3) begin
                valid_r     <= 1'b1 ;
                dout_r      <= din;
            end
            else begin
                valid_r     <= 1'b0 ;
            end
        end
    end
    assign dout          = dout_r ;
    assign valid         = valid_r ;

endmodule

FPGA仿真波形

综合RTL视图:

可见,与实数信号流图描述结构相同。