当前位置:   article > 正文

FPGA使用查表法实现正弦和余弦函数 - 变形方法2_fpga生成余弦信号

fpga生成余弦信号

FPGA使用查表法实现正弦和余弦函数

FPGA使用查表法实现正弦和余弦函数 - 变形方法1

在前两篇文章中,设置的输入角度范围分别是[0,2*pi)[0,pi/2)。但根据三角函数公式,其实我们还可以将[0,2*pi)分成8段,这样就能将输入角度范围继续缩小到[0,pi/4)了。

1、修改matlab代码

  1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2. %% Zheng Wei, 2022/12/06
  3. %%
  4. %% 输入角度范围:[0,pi/4); 输入数据量化位数:10bit;
  5. %% 输出结果范围:[0,1]; 输出数据量化位数:16bit;
  6. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  7. clc; % 清理命令行
  8. close all; % 关闭所有图形窗口
  9. clear all; % 清理所有工作区变量
  10. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  11. %% 参数定义
  12. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  13. in_quantify_bit = 10; % 输入数据量化位数(无符号数)
  14. alpha = 0:(pi/4/2^in_quantify_bit):(pi/4-pi/4/2^in_quantify_bit); % 弧度
  15. out_quantify_bit = 16; % 输出数据量化位数(有符号数)
  16. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  17. %% 获取三角函数值
  18. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  19. cos_alpha = cos(alpha); % 获得cos函数值
  20. sin_alpha = sin(alpha); % 获得sin函数值
  21. cos_alpha_q = round(cos_alpha *(2^(out_quantify_bit-1)-1)); % 16bit量化
  22. sin_alpha_q = round(sin_alpha *(2^(out_quantify_bit-1)-1)); % 16bit量化
  23. % figure(1); subplot(2,1,1);plot(alpha,cos_alpha);subplot(2,1,2);plot(alpha,cos_alpha_q);
  24. % figure(2); subplot(2,1,1);plot(alpha,sin_alpha);subplot(2,1,2);plot(alpha,sin_alpha_q);
  25. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  26. %% 生成coe文件,第一行定义数据格式, 16代表ROM的数据格式为16进制。
  27. %% 高16bit代表sin值,低16bit代表cos值,各自最高的1bit是符号位。
  28. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  29. % 因为都是正数,所以不需要取补码
  30. % for i = 1:1:(2^in_quantify_bit)
  31. % if (cos_alpha_q(i)<0)
  32. % cos_alpha_q(i) = cos_alpha_q(i) + 2^(out_quantify_bit); % 负数用补码表示
  33. % else
  34. % cos_alpha_q(i) = cos_alpha_q(i); % 正数的补码为原码
  35. % end
  36. %
  37. % if (sin_alpha_q(i)<0)
  38. % sin_alpha_q(i) = sin_alpha_q(i) + 2^(out_quantify_bit); % 负数用补码表示
  39. % else
  40. % sin_alpha_q(i) = sin_alpha_q(i); % 正数的补码为原码
  41. % end
  42. % end
  43. cos_alpha_q = dec2hex(cos_alpha_q);
  44. sin_alpha_q = dec2hex(sin_alpha_q);
  45. % 将cos和sin拼接为32bit(各自16bit),此数据输出到FPGA
  46. fid=fopen('cos_sin_lut_3.coe','wt');
  47. fprintf( fid, 'MEMORY_INITIALIZATION_RADIX = 16;\n');
  48. fprintf( fid, 'MEMORY_INITIALIZATION_VECTOR =\n');
  49. for i = 1:1:(2^in_quantify_bit)
  50. s=strcat(sin_alpha_q(i,1),sin_alpha_q(i,2),sin_alpha_q(i,3),sin_alpha_q(i,4),cos_alpha_q(i,1),cos_alpha_q(i,2),cos_alpha_q(i,3),cos_alpha_q(i,4));
  51. fprintf(fid,'%c%c%c%c%c%c%c%c',s);
  52. if (i < 2^in_quantify_bit)
  53. fprintf(fid,',\n');
  54. else
  55. fprintf(fid,';\n'); % 分号(;) 结束标志位
  56. end
  57. end
  58. fclose(fid);

2、将重新生成的coe文件写入ROM核中
3、通过查表得到角度所对应的正弦值和余弦值

  1. /*----------------------------------------------------------------------
  2. Author: Zheng Wei
  3. Date: 2022-12-06
  4. Version: 1.0
  5. Description: It is a cos_sin_lut_3 testbench.
  6. -----------------------------------------------------------------------*/
  7. `timescale 1ns / 1ps
  8. module tb;
  9. reg i_sys_clk ;
  10. reg i_sys_rst ;
  11. reg [12:0] r_rom_phase ;
  12. reg [12:0] r_rom_phase_ff ;
  13. reg [12:0] r_rom_phase_2ff ;
  14. reg [12:0] r_rom_phase_3ff ;
  15. reg [09:0] r_rom_addr ;
  16. wire [15:0] w_cos_rom_val ; // ROM readout value [0, pi/4)
  17. wire [15:0] w_sin_rom_val ; // ROM readout value [0, pi/4)
  18. reg [16:0] r_cos_val ; // transform output value[0, 2*pi)
  19. reg [16:0] r_sin_val ; // transform output value[0, 2*pi)
  20. wire [15:0] o_cos_val ; // final output value, drop the least 1bit
  21. wire [15:0] o_sin_val ; // final output value, drop the least 1bit
  22. // clock generate module
  23. parameter period = 6.67; // 150MHz
  24. initial begin
  25. i_sys_clk = 1'b0;
  26. forever #(period/2) i_sys_clk = ~i_sys_clk;
  27. end
  28. //-------------------------------------------------------------------
  29. // system initialization
  30. task task_sysinit;
  31. begin
  32. r_rom_phase = 12'd0;
  33. end
  34. endtask
  35. // system reset
  36. task task_reset;
  37. begin
  38. i_sys_rst = 1'b1;
  39. repeat(20) @(negedge i_sys_clk);
  40. i_sys_rst = 1'b0;
  41. end
  42. endtask
  43. initial begin
  44. task_sysinit;
  45. task_reset ;
  46. repeat(10) @(posedge i_sys_clk);
  47. repeat(100000) @(posedge i_sys_clk);
  48. $stop;
  49. end
  50. always @(posedge i_sys_clk or posedge i_sys_rst) begin
  51. if (i_sys_rst) begin
  52. r_rom_phase <= 13'd0;
  53. end
  54. else begin
  55. r_rom_phase <= r_rom_phase + 13'd1;
  56. end
  57. end
  58. always @(posedge i_sys_clk) begin
  59. r_rom_phase_ff <= r_rom_phase;
  60. r_rom_phase_2ff <= r_rom_phase_ff;
  61. r_rom_phase_3ff <= r_rom_phase_2ff;
  62. end
  63. always @(posedge i_sys_clk or posedge i_sys_rst) begin
  64. if (i_sys_rst) begin
  65. r_rom_addr <= 10'd0;
  66. end
  67. else if(r_rom_phase[10]) begin
  68. r_rom_addr <= ~r_rom_phase[9:0]; // alpha = n*pi/2 - beta
  69. end
  70. else begin
  71. r_rom_addr <= r_rom_phase[9:0]; // alpha = n*pi/2 + beta
  72. end
  73. end
  74. always @(posedge i_sys_clk) begin
  75. case (r_rom_phase_3ff[12:10])
  76. 3'b000: begin // [0, pi/4)
  77. r_cos_val <= {1'b0, w_cos_rom_val};
  78. r_sin_val <= {1'b0, w_sin_rom_val};
  79. end
  80. 3'b001: begin // [pi/4, pi/2)
  81. r_cos_val <= {1'b0, w_sin_rom_val};
  82. r_sin_val <= {1'b0, w_cos_rom_val};
  83. end
  84. 3'b010: begin // [pi/2, 3pi/4)
  85. r_cos_val <= ~{1'b0, w_sin_rom_val} + 1'b1;
  86. r_sin_val <= {1'b0, w_cos_rom_val};
  87. end
  88. 3'b011: begin // [3pi/4, pi)
  89. r_cos_val <= ~{1'b0, w_cos_rom_val} + 1'b1;
  90. r_sin_val <= {1'b0, w_sin_rom_val};
  91. end
  92. 3'b100: begin // [pi, 5*pi/4)
  93. r_cos_val <= ~{1'b0, w_cos_rom_val} + 1'b1;
  94. r_sin_val <= ~{1'b0, w_sin_rom_val} + 1'b1;
  95. end
  96. 3'b101: begin // [5*pi/4, 3*pi/2)
  97. r_cos_val <= ~{1'b0, w_sin_rom_val} + 1'b1;
  98. r_sin_val <= ~{1'b0, w_cos_rom_val} + 1'b1;
  99. end
  100. 3'b110: begin // [3*pi/2, 7*pi/4)
  101. r_cos_val <= {1'b0, w_sin_rom_val};
  102. r_sin_val <= ~{1'b0, w_cos_rom_val} + 1'b1;
  103. end
  104. 3'b111: begin // [7*pi/4, 2*pi)
  105. r_cos_val <= {1'b0, w_cos_rom_val};
  106. r_sin_val <= ~{1'b0, w_sin_rom_val} + 1'b1;
  107. end
  108. endcase
  109. end
  110. assign o_cos_val = r_cos_val[16:1];
  111. assign o_sin_val = r_sin_val[16:1];
  112. //-----------------------------------------------------------------------------------------------
  113. cos_sin_lut_3 u_cos_sin_lut_3(
  114. .clka ( i_sys_clk ), // input wire clka
  115. .addra ( r_rom_addr ), // input wire [9 : 0] addra
  116. .douta ({w_sin_rom_val, w_cos_rom_val}) // output wire [31 : 0] douta
  117. );
  118. endmodule

4、仿真结果


5、关键代码分析

  1. 使用10bit数据来量化pi/4,即pi/4 = 2^10,也即r_rom_phase = 13'b0_0100_0000_0000
  2. 所以我们只需要根据r_rom_phase[12:10]来判断输入角度处于8段的哪一段
  3. 然后根据三角函数公式调整最终输出值。

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

闽ICP备14008679号