首页
学习
活动
专区
圈层
工具
发布
37 篇文章
1
Linux音频驱动-ASOC(ALSA System on Chip)
2
LPDDR5: A New Clocking Scheme 提高性能
3
FPGA 控制 RGMII 接口 PHY芯片基础
4
DDR3篇第三讲、DDR3读写测试项目分析
5
PHY(Physical Layer,PHY)通俗理
6
MIPI联盟已完成车载的Long-Reach SerDes PHY工业标准 A-PHY v1.0
7
【三】Bluetooth 技术||链路层七种状态与空口报文设计(Core_v5.2)
8
【RL-TCPnet网络教程】第5章 PHY芯片和STM32的MAC基础知识
9
FPGA和USB3.0通信-USB3.0 PHY介绍
10
USB技术浅析
11
优秀的 Verilog/FPGA开源项目介绍(二)-RISC-V
12
优秀的 Verilog/FPGA开源项目介绍(十六)- 数字频率合成器DDS
13
想学习高速ADC/DAC/SDR项目这个项目你不得不理解
14
优秀的 Verilog/FPGA开源项目介绍(九)- DP(增改版)
15
优秀的 Verilog/FPGA开源项目介绍(十三)- I2C
16
高速串行通信常用的编码方式-8b/10b编码/解码
17
SoC设计之PPA
18
SoC设计之功耗--开篇
19
开源SOC的设计与实践
20
SoC设计之功耗 – RTL/netlist功耗计算
21
转置型FIR设计
22
SSD目标检测系统系统结构网络训练
23
P2P接口Booth乘法器设计描述原理代码实现
24
流水线式p2p接口的分析与实现
25
流水线乘加树需求设计规划代码实现
26
分时复用的移位相加乘法器
27
Verilog实现全并行比较算法
28
全并行流水线移位相加乘法器
29
ROM乘法器基本算法单个ROM乘法器分时复用ROM乘法器
30
Flash中XIP模式
31
cordic的FPGA实现(五)、除法实现
32
cordic的FPGA实现(三)、乘法器实现
33
cordic的FPGA实现(三)、sin、cos函数运算与源码分析
34
FPGA卡拉ok系统--Biquad filter
35
音频总线I2S协议
36
脉冲压缩处理
37
虚拟地址(VA,virtual address)到物理地址(PA, ,physical address)的转换
清单首页SoC文章详情

cordic的FPGA实现(三)、sin、cos函数运算与源码分析

在旋转模式中曾提到:由于每次伪旋转都导致向量模长发生了变化,以Ki表示第i次伪旋转模长补偿因子,所以第i次伪旋转真实旋转的结果应该为:

经过n次伪旋转,得到的伪旋转点最终结果可以表示为:

当n趋近于无穷大时,An逼近1.646760258,令xo=1/An且yo=0即可得到目标旋转角度的正弦、余弦值。

那么,我们现在就让xo=1/An且yo=0且(即x0=1/1.646760258=0.6073),就可以得到z0(旋转角所对应的正弦、余弦值)。

我在想:为什么常量定义中定义的是反正切函数的一半、一半、一半逐个减半,而不是角度一半、一半、一半的减小呢?没想通,反正就是反正切函数的值(角度)逐个减半吧?不对!当然是使用反正切函数的变量值逐个减半更好!因为这样的话逐个将tan>>>(带符号右移)一位就好,要是角度的话一半一半的话绝逼有小数!想出这个CORDIC求解tan、sin、cos的人真的好厉害!!!

verilog代码:

代码语言:javascript
复制
module cordic
(
    input CLOCK,RESET,
   input iCall, 
   output oDone,
   input [31:0]iData,
   output [31:0]cos,
   output [31:0]sin,
   /*
   输出的x为cos值,输出的y为sin值,x=qx,y=qy
   */
   output [31:0]q_deg,q_y,q_x
);
   reg [31:0] atan [15:0];
   //声明atan反正切函数常量表,该常量表从tan(45)度开始每次减小一半儿
   initial begin
       atan[0] = 32'd2949120; atan[1] = 32'd1740992; atan[2] = 32'd919872; atan[3] = 32'd466944;
      atan[4] = 32'd234368; atan[5] = 32'd117312; atan[6] = 32'd58688; atan[7] = 32'd29312; 
      atan[8] = 32'd14656; atan[9] = 32'd7360; atan[10] = 32'd3648; atan[11] = 32'd1856; 
      atan[12] = 32'd896;  atan[13] = 32'd448; atan[14] = 32'd256; atan[15] = 32'd128;
   end
   //带符号位的寄存器声明
   reg signed [31:0]x,y,tx,ty,deg;
   reg [7:0]i;
   reg isDone;
   
   always @ ( posedge CLOCK or negedge RESET )
       if( !RESET )
           begin
            { x,y,tx,ty,deg } <= { 32'd0,32'd0,32'd0,32'd0,32'd0 };
            i <= 8'd0;
            isDone <= 1'b0;
         end
      else if( iCall )
         case( i )
        
             0:
           begin x <= 0.607253 * 65536; y <= 32'd0; deg <= iData << 16; i <= i + 1'b1; end
           
           1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16:
           /*
           在剩余角度大于0时,需要继续逆时针旋转,在单位圆上逆时针旋转的话横坐标会减小,纵坐标会增大
           
           */
           if( deg > 0 )
              begin
                  ty = y >>> i-1;
                  tx = x >>> i-1;
                   x <= x - ty;
                  y <= y + tx;
                  deg <= deg - atan[i-1];
                  i <= i + 1'b1;
              end
           else
           /*
           在剩余角度小于0时候,需要顺时针旋转,顺时针旋转的话纵坐标会减小,横坐标会增大
           */
              begin
                  ty = y >>> i-1;
                  tx = x >>> i-1;
                   x <= x + ty ;
                  y <= y - tx ;
                  deg <= deg + atan[i-1];
                  i <= i + 1'b1;
              end
          
          17:
          begin isDone <= 1'b1; i <= i + 1'b1; end
          
          18:
          begin isDone <= 1'b0; i <= 8'd0; end
             
        endcase
        
    assign oDone = isDone;
    assign cos = x;
    assign sin = y;
    assign { q_deg,q_y,q_x } = { deg,y,x };
    
endmodule

仿真代码:

代码语言:javascript
复制
`timescale 1ns/1ns
module cordic_tb;

reg clk;  //系统时钟
reg rst_n;//复位信号
reg iCall;//模块调用信号
reg [31:0]iData; //待求角度
wire oDone;      //迭代完成标志
wire [31:0]cos;  //cos值
wire [31:0]sin;  //sin值
wire [31:0]deg_left; //剩余角度
cordic u0(
.CLOCK(clk),
.RESET(rst_n),
.iCall(iCall), 
.oDone(oDone),
.iData(iData),
.cos(cos),
.sin(sin),
   /*
   输出的x为cos值,输出的y为sin值,x=qx,y=qy
   */
.q_deg(deg_left)
);

initial begin 
clk=0;
forever #5 clk=~clk;
end 

initial begin 
rst_n=0;
#10;
rst_n=1; 
end 

reg [7:0]i;
always@(posedge clk or negedge rst_n)
if(~rst_n)
begin
 i<=8'd0;
 iCall<=1'b0;
 iData<=32'd0;
end 
else 
case(i) 
0: //z=30
 begin
  if(oDone)
   begin
   iCall<=1'b0;
   i<=i+1'b1;
  end 
   else 
   begin
    iCall<=1'b1;
    iData<=32'd30;
   end 
 end 
1: //z=45
 begin
  if(oDone)
   begin
   iCall<=1'b0;
   i<=i+1'b1;
  end 
   else 
   begin
    iCall<=1'b1;
    iData<=32'd45;
   end  
 end 
2: //z=60
 begin
  if(oDone)
   begin
   iCall<=1'b0;
   i<=i+1'b1;
  end 
   else 
   begin
    iCall<=1'b1;
    iData<=32'd60;
   end  
 end 
3: //z=75
 begin
  if(oDone)
   begin
   iCall<=1'b0;
   i<=i+1'b1;
  end 
   else 
   begin
    iCall<=1'b1;
    iData<=32'd75;
   end  
 end 
4: //z=90
 begin
  if(oDone)
   begin
   iCall<=1'b0;
   i<=i+1'b1;
  end 
   else 
   begin
    iCall<=1'b1;
    iData<=32'd90;
   end 
 end 
 5:
 i<=i;
 endcase  
endmodule

仿真结果:

真实结果 迭代结果

sin30=0.5000 32769/65536=0.5000

cos30=0.8660 56759/65536=0.8661

sin45=0.7071 46341/65536=0.7071

cos45=0.7071 46342/65536=0.7071

sin60=0.8660 56759/65536=0.8661

cos60=0.5000 32769/65536=0.5000

下一篇
举报
领券