当前位置:   article > 正文

FPGA_DDS生成正弦波_fpga实现dds正弦波

fpga实现dds正弦波

目录

1 DDS简介

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

3 相位累加器

4 顶层模块

5 结果

6 优化 

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

6.2 修改的相位累加器

6.3 修改的顶层模块

6.4 结果


1 DDS简介

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

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

                              输出频率与控制字和时钟的关系:        f_{0} = \frac{f_{clk*K}}{2^{N}}

                                                                频率分辨率:\Delta f = \frac{f_{clk}}{2^{N}}

                                                                N为控制字K的位宽。

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

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

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

3 相位累加器

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

  1. module DDS
  2. (
  3. clk,
  4. rst,
  5. addr_out
  6. );
  7. input clk,rst;
  8. output [8:0] addr_out;
  9. reg [31:0] fct;
  10. parameter K = 85899345;
  11. // Fout = (clk*K)/2^N
  12. always@(posedge clk or negedge rst)
  13. begin
  14. if(!rst)
  15. fct <= 32'd0;
  16. else fct <= fct + K;
  17. end
  18. assign addr_out = fct[31:23];
  19. endmodule

4 顶层模块

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

  1. module TEST_MODULE
  2. (
  3. clk,
  4. rst,
  5. sin_out
  6. );
  7. input clk,rst;
  8. output [8:0] sin_out;
  9. wire [8:0] addr;
  10. DDS U_DDS
  11. (
  12. .clk(clk),
  13. .rst(rst),
  14. .addr_out(addr)
  15. );
  16. my_rom u_my_rom(
  17. .address(addr),
  18. .clock(clk),
  19. .q(sin_out)
  20. );
  21. endmodule

5 结果

6 优化 

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

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

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

6.2 修改的相位累加器

  1. module DDS
  2. (
  3. clk,
  4. rst,
  5. addr_out,
  6. addr_short,
  7. sign_out
  8. );
  9. input clk,rst;
  10. output reg sign_out;//符号位
  11. output [8:0] addr_out;
  12. output reg [6:0] addr_short;
  13. reg [31:0] fct;
  14. parameter K = 85899345; //1M正弦波
  15. // Fout = (clk*K)/2^N
  16. always@(posedge clk or negedge rst)
  17. begin
  18. if(!rst)
  19. begin
  20. fct <= 32'd0;
  21. addr_short <= 7'd0;
  22. sign_out <=1'b0;
  23. end
  24. else
  25. begin
  26. fct <= fct + K;
  27. if(fct[31:23]<=8'd127)//第一象限
  28. begin
  29. addr_short <= fct[29:23];
  30. sign_out <=1'b0;
  31. end
  32. else if(fct[31:23]>9'd127&&fct[31:23]<9'd256)//第二象限
  33. begin
  34. addr_short = 8'd255-fct[31:23];
  35. sign_out <=1'b0;
  36. end
  37. else if(fct[31:23]>=9'd256&&fct[31:23]<9'd384)//第三象限
  38. begin
  39. addr_short = fct[31:23] - 8'd255;
  40. sign_out <=1'b1;
  41. end
  42. else if(fct[31:23]>=9'd384)//第四象限
  43. begin
  44. addr_short = 9'd511 - fct[31:23];
  45. sign_out <=1'b1;
  46. end
  47. end
  48. end
  49. assign addr_out = fct[31:23];
  50. endmodule

6.3 修改的顶层模块

  1. module TEST_MODULE
  2. (
  3. clk,
  4. rst,
  5. sin_out,
  6. sin_out_one,
  7. );
  8. input clk,rst;
  9. output [8:0] sin_out,sin_out_one;
  10. wire [8:0] reg_sin_out_one;
  11. wire [8:0] addr;
  12. wire [8:0] addr_short;
  13. wire sign_out;
  14. DDS U_DDS
  15. (
  16. .clk(clk),
  17. .rst(rst),
  18. .addr_out(addr),
  19. .addr_short(addr_short),
  20. .sign_out(sign_out)
  21. );
  22. //512个正弦波采样点
  23. my_rom u_my_rom(
  24. .address(addr),
  25. .clock(clk),
  26. .q(sin_out)
  27. );
  28. //128个正弦波采样点
  29. my_rom_one u_my_rom_one
  30. (
  31. .address(addr_short),
  32. .clock(clk),
  33. .q(reg_sin_out_one)
  34. );
  35. assign sin_out_one = sign_out? ~reg_sin_out_one+1:reg_sin_out_one;//根据符号调整正负,正数不变,负数取补码
  36. endmodule

6.4 结果

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/974287
推荐阅读
相关标签
  

闽ICP备14008679号