FPGA

    技术2022-07-13  86

    1 DDS简介

    DDS技术最初是作为频率合成技术提出的,由于其易于控制,相位连续,输出频率稳定度高,分辨率高, 频率转换速度快等优点,现在被广泛应用于任意波形发生器(AWG)。基于DDS技术的任意波形发生器用高速存储器作为查找表,通过高速D/A转换器来合成出存储在存储器内的波形。所以它不仅能产生正弦、余弦、方波、三角波和锯齿波等常见波形,而且还可以利用各种编辑手段,产生传统函数发生器所不能产生的真正意义上的任意波形。

    直接频率合成(Direct Dgital Sythesizer, DDS) 是种把-系列数字信号通过数字模拟转换器(igital to Analog Converter, DAC) 转换为模拟信号的新型频率合成技术。其优点有频率切换时间短,频率分析率高,输出信号的频率和相位可以快速切换,输出相位连续,并且很容易地实现信号频率、相位和幅度的控制。

     

                                  输出频率与控制字和时钟的关系:        

                                                                    频率分辨率:

                                                                    N为控制字K的位宽。

    2 利用matlab生成ROM初始化文件mif

    要注意的是,如果采样点的幅度需要M位数据宽度的话,那么ROM的数据宽度至少M+1位宽度。因为需要额外的符号位。

    N=512; %N为采样点数 s_p=0:N-1;%正弦波一个周期的采样点数 sin_data=sin(2*pi*s_p/N); %sin_data是初步采样值,浮点数% 编写到这里,大家可以在任务行中显示此时的波形 fix_p_sin_data=fix(sin_data*255); %定点化 fix()函数可以直接去除小数点后的值,使之成为整数 plot(fix_p_sin_data); for i=1:N if fix_p_sin_data(i)<0 fix_p_sin_data(i)=N+fix_p_sin_data(i); else fix_p_sin_data(i)=fix_p_sin_data(i); end end%下面是mif文件固定格式,不可更改 fid=fopen('sp_ram_512x9.mif','w+'); fprintf(fid,'WIDTH=9;\n'); fprintf(fid,'DEPTH=512;\n'); fprintf(fid,'ADDRESS_RADIX=UNS;\n'); fprintf(fid,'DATA_RADIX=UNS;\n'); fprintf(fid,'CONTENT BEGIN \n'); for i=1:N fprintf(fid,'%d:%d; \n',i-1,fix_p_sin_data(i)); end fprintf(fid,'END; \n'); fclose(fid); %好了到此为止,我们就编写完并生成了初始化**mif文件了,下面可以开始verilog编写了,噢,不对,咱们先来利用quartus

    3 相位累加器

    截取相位累计器的高9位作为ROM的地址线。至于截止多少位,采样点的数量有关,采样点的数量决定了ROM的大小和地址线宽度。

    module DDS ( clk, rst, addr_out ); input clk,rst; output [8:0] addr_out; reg [31:0] fct; parameter K = 85899345; // Fout = (clk*K)/2^N always@(posedge clk or negedge rst) begin if(!rst) fct <= 32'd0; else fct <= fct + K; end assign addr_out = fct[31:23]; endmodule

    4 顶层模块

    my_rom为调用的IP核,深度为512,宽度为9

    module TEST_MODULE ( clk, rst, sin_out ); input clk,rst; output [8:0] sin_out; wire [8:0] addr; DDS U_DDS ( .clk(clk), .rst(rst), .addr_out(addr) ); my_rom u_my_rom( .address(addr), .clock(clk), .q(sin_out) ); endmodule

    5 结果

    6 优化 

    利用正弦波的对称性,只存储1/4的采样数据,然后根据象限调整数据的符号也是可以的。先修改上面的matlab文件生成一个0-π/2的采样数据。宽度同样为9,采样点为128。

    N=128; %N为采样点数 s_p=0:N-1;%正弦波一个周期的采样点数 sin_data=sin(0.5*pi*s_p/N); %sin_data是初步采样值,浮点数% 编写到这里,大家可以在任务行中显示此时的波形 fix_p_sin_data=fix(sin_data*255); %定点化 fix()函数可以直接去除小数点后的值,使之成为整数 plot(fix_p_sin_data); for i=1:N if fix_p_sin_data(i)<0 fix_p_sin_data(i)=N+fix_p_sin_data(i); else fix_p_sin_data(i)=fix_p_sin_data(i); end end%下面是mif文件固定格式,不可更改 fid=fopen('sp_ram_128x9.mif','w+'); fprintf(fid,'WIDTH=9;\n'); fprintf(fid,'DEPTH=512;\n'); fprintf(fid,'ADDRESS_RADIX=UNS;\n'); fprintf(fid,'DATA_RADIX=UNS;\n'); fprintf(fid,'CONTENT BEGIN \n'); for i=1:N fprintf(fid,'%d:%d; \n',i-1,fix_p_sin_data(i)); end fprintf(fid,'END; \n'); fclose(fid); %好了到此为止,我们就编写完并生成了初始化**mif文件了,下面可以开始verilog编写了,噢,不对,咱们先来利用quartus

    6.1 再创建一个128*9大小的ROM,导入修改后的mif文件

    6.2 修改的相位累加器

    module DDS ( clk, rst, addr_out, addr_short, sign_out ); input clk,rst; output reg sign_out;//符号位 output [8:0] addr_out; output reg [6:0] addr_short; reg [31:0] fct; parameter K = 85899345; //1M正弦波 // Fout = (clk*K)/2^N always@(posedge clk or negedge rst) begin if(!rst) begin fct <= 32'd0; addr_short <= 7'd0; sign_out <=1'b0; end else begin fct <= fct + K; if(fct[31:23]<=8'd127)//第一象限 begin addr_short <= fct[29:23]; sign_out <=1'b0; end else if(fct[31:23]>9'd127&&fct[31:23]<9'd256)//第二象限 begin addr_short = 8'd255-fct[31:23]; sign_out <=1'b0; end else if(fct[31:23]>=9'd256&&fct[31:23]<9'd384)//第三象限 begin addr_short = fct[31:23] - 8'd255; sign_out <=1'b1; end else if(fct[31:23]>=9'd384)//第四象限 begin addr_short = 9'd511 - fct[31:23]; sign_out <=1'b1; end end end assign addr_out = fct[31:23]; endmodule

    6.3 修改的顶层模块

    module TEST_MODULE ( clk, rst, sin_out, sin_out_one, ); input clk,rst; output [8:0] sin_out,sin_out_one; wire [8:0] reg_sin_out_one; wire [8:0] addr; wire [8:0] addr_short; wire sign_out; DDS U_DDS ( .clk(clk), .rst(rst), .addr_out(addr), .addr_short(addr_short), .sign_out(sign_out) ); //512个正弦波采样点 my_rom u_my_rom( .address(addr), .clock(clk), .q(sin_out) ); //128个正弦波采样点 my_rom_one u_my_rom_one ( .address(addr_short), .clock(clk), .q(reg_sin_out_one) ); assign sin_out_one = sign_out? ~reg_sin_out_one+1:reg_sin_out_one;//根据符号调整正负,正数不变,负数取补码 endmodule

    6.4 结果

    上面波形为512个采样点一个周期的

    下面为128个采样点1/4周期,利用对称性恢复成完整波形的

    Processed: 0.026, SQL: 10