CORDIC算法:三角函数的硬件加速革命——从数学原理到FPGA实现的超高效计算方案

news2025/4/2 10:49:28

计算机该如何求解三角函数?或许你的第一印象是采用泰勒展开,或者采用多项式进行逼近。对于前者,来回的迭代计算开销成本很大;对于后者,多项式式逼近在较窄的范围內比较接近,超过一定范围后,就变得十分不理想了。例如x–>0时,x~sin(x)

今天,我们将要介绍三角函数的另一种求法:CORDIC算法

原理

CORDIC的算法的核心就是通过迭代,利用三角函数的物理性质,不断累积旋转角度,从而得到所求角度的精确近似。

我们假设圆为单位圆,范围且在第一象限,如下图:

在这里插入图片描述

我们假设点(x1,y1)与X轴正半轴夹角为α,那么
{ y 2 = s i n ( α + θ ) x 2 = c o s ( α + θ ) \begin{cases} y_2=sin(α+θ)\\ x_2=cos(α+θ) \end{cases} {y2=sin(α+θ)x2=cos(α+θ)
三角函数展开有
{ y 2 = s i n ( α ) c o s ( θ ) + c o s ( α ) s i n ( θ ) x 2 = c o s ( α ) c o s ( θ ) − s i n ( α ) s i n ( θ ) \begin{cases} y_2=sin(α)cos(θ)+cos(α)sin(θ)\\ x_2=cos(α)cos(θ)-sin(α)sin(θ) \end{cases} {y2=sin(α)cos(θ)+cos(α)sin(θ)x2=cos(α)cos(θ)sin(α)sin(θ)


{ y 1 = s i n ( α ) x 1 = c o s ( α ) \begin{cases} y_1=sin(α)\\ x_1=cos(α) \end{cases} {y1=sin(α)x1=cos(α)
带入上式,有
{ y 2 = s i n ( α ) c o s ( θ ) + c o s ( α ) s i n ( θ ) = y 1 c o s ( θ ) + x 1 s i n ( θ ) = c o s ( θ ) ( y 1 + x 1 t a n ( θ ) ) x 2 = c o s ( α ) c o s ( θ ) − s i n ( α ) s i n ( θ ) = x 1 c o s ( θ ) − y 1 s i n ( θ ) = c o s ( θ ) ( x 1 − y 1 t a n ( θ ) ) \begin{cases} y_2=sin(α)cos(θ)+cos(α)sin(θ)=y_1cos(θ)+x_1sin(θ)=cos(θ)(y_1+x_1tan(θ))\\ x_2=cos(α)cos(θ)-sin(α)sin(θ)=x_1cos(θ)-y_1sin(θ)=cos(θ)(x_1-y_1tan(θ)) \end{cases} {y2=sin(α)cos(θ)+cos(α)sin(θ)=y1cos(θ)+x1sin(θ)=cos(θ)(y1+x1tan(θ))x2=cos(α)cos(θ)sin(α)sin(θ)=x1cos(θ)y1sin(θ)=cos(θ)(x1y1tan(θ))

默认初始值为(1,0),记为
v 0 = [ 1 0 ] v_0=\begin{bmatrix} 1\\ 0 \end{bmatrix} v0=[10]
以上的等式可以表示为旋转矩阵的形式
[ x 2 y 2 ] = c o s ( α ) [ 1 − t a n ( α ) t a n ( α ) 1 ] [ x 1 y 1 ] \begin{bmatrix} x_2\\ y_2 \end{bmatrix} =cos(α) \begin{bmatrix} 1 & -tan(α)\\ tan(α)&1 \end{bmatrix} \begin{bmatrix} x_1\\ y_1 \end{bmatrix} [x2y2]=cos(α)[1tan(α)tan(α)1][x1y1]
如果将令角度α,满足tan(α)=2-i, 那么就将tan和乘法运算就变成乘2的负次幂。对应在计算机中,就是移位计算。因而复杂的计算,就变成了简单的加减和移位运算。

所以我们有
[ x n y n ] = c o s ( α n ) [ 1 − 2 − n 2 − n 1 ] [ x n − 1 y n − 1 ] = c o s ( α n ) c o s ( α n − 1 ) . . c o s ( α 0 ) [ 1 − 2 − n 2 − n 1 ] [ 1 − 2 − n + 1 2 − n + 1 1 ] . . [ 1 − 2 − 0 2 − 0 1 ] [ 1 0 ] \begin{bmatrix} x_n\\ y_n \end{bmatrix} =cos(α_n) \begin{bmatrix} 1 & -2^{-n}\\ 2^{-n}&1 \end{bmatrix} \begin{bmatrix} x_{n-1}\\ y_{n-1} \end{bmatrix}= cos(α_n)cos(α_{n-1})..cos(α_0) \begin{bmatrix} 1 & -2^{-n}\\ 2^{-n}&1 \end{bmatrix} \begin{bmatrix} 1 & -2^{-n+1}\\ 2^{-n+1}&1 \end{bmatrix} .. \begin{bmatrix} 1 & -2^{-0}\\ 2^{-0}&1 \end{bmatrix} \begin{bmatrix} 1\\ 0 \end{bmatrix} [xnyn]=cos(αn)[12n2n1][xn1yn1]=cos(αn)cos(αn1)..cos(α0)[12n2n1][12n+12n+11]..[120201][10]

处理细节

1. 缩放因子

由前面推导,我们可以得到:
[ x n y n ] = c o s ( α n ) [ 1 − 2 − n 2 − n 1 ] [ x n − 1 y n − 1 ] = c o s ( α n ) c o s ( α n − 1 ) . . c o s ( α 0 ) [ 1 − 2 − n 2 − n 1 ] [ 1 − 2 − n + 1 2 − n + 1 1 ] . . [ 1 − 2 − 0 2 − 0 1 ] [ 1 0 ] \begin{bmatrix} x_n\\ y_n \end{bmatrix} =cos(α_n) \begin{bmatrix} 1 & -2^{-n}\\ 2^{-n}&1 \end{bmatrix} \begin{bmatrix} x_{n-1}\\ y_{n-1} \end{bmatrix}= cos(α_n)cos(α_{n-1})..cos(α_0) \begin{bmatrix} 1 & -2^{-n}\\ 2^{-n}&1 \end{bmatrix} \begin{bmatrix} 1 & -2^{-n+1}\\ 2^{-n+1}&1 \end{bmatrix} .. \begin{bmatrix} 1 & -2^{-0}\\ 2^{-0}&1 \end{bmatrix} \begin{bmatrix} 1\\ 0 \end{bmatrix} [xnyn]=cos(αn)[12n2n1][xn1yn1]=cos(αn)cos(αn1)..cos(α0)[12n2n1][12n+12n+11]..[120201][10]

我们可以提前将所有的cos(α)的乘积计算出来,做为一个常量,省去乘法运算,记为K
K = c o s ( α n ) c o s ( α n − 1 ) c o s ( α n − 2 ) . . . c o s ( α 0 ) = 0.60725 K=cos(α_n)cos(α_{n-1})cos(α_{n-2})...cos(α_0)=0.60725 K=cos(αn)cos(αn1)cos(αn2)...cos(α0)=0.60725
2. 旋转方向

通常来说CORDIC算法会引入dn ,来判断旋转方向。当前角度大于该次迭代的角度,dn为正,逆时钟旋转,反之为负,顺时针旋转。之所以会采用双旋转,是因为其通常比单向旋转的收敛性更好,结果更精确。

因而我们迭代可以写为
{ y n + 1 = y n + d n ∗ x n ∗ 2 − n x n + 1 = x n − d ∗ y n ∗ 2 − n a n g l e n + 1 = a n g l e n − d ∗ t a b l e o f a n g l e s [ n ] \begin{cases} y_{n+1}=y_n+d_n*x_n*2^{-n}\\ x_{n+1}=x_n-d*y_n*2^{-n}\\ angle_{n+1}=angle_{n}-d*tableofangles[n] \end{cases} yn+1=yn+dnxn2nxn+1=xndyn2nanglen+1=anglendtableofangles[n]
table_of_angles 存储的是θ值, θn=arctan(2-n);

对应的表格如下:

n2^(-n)arctan(2^(-n))
010.785398163
10.50.463647609
20.250.244978663
30.1250.124354995
40.06250.06241881
50.03150.031239833
60.0156250.015623729
70.00781250.007812341
80.003906250.00390623
90.0019531250.001953123
100.0009765630.000976562
110.0004882810.000488281
120.0002441410.000244141
130.000122070.00012207
146.10352E-056.10352E-05
153.05176E-053.05176E-05

下面我会手把手带领大家从软件建模到硬件实现CORDIC算法,规定输入和输出都是无符号17位数,1位整数位,16位小数位。

Python 代码

测试代码

#初始化部分,定义参数
import math
from math import floor

NUM_ITER = 16
Frac_Bits=16
Data_Scale=2**Frac_Bits
Angles_Table=[]

#创建对应的对应的角度表
def create_angel_table():   
    for i in range(NUM_ITER):
        angles=math.atan(2**(-i))
        angles=floor(angles*Data_Scale+0.5)/Data_Scale
        #print(angles)
        #print(angles)
        #angles=angles*(1<<Frac_Bits)+0.5
        #angles=floor(angles)
        #print(angles)
        #print(hex(angles))
        Angles_Table.append(angles)

#计算出缩放因子
def compute_k():
    k=1.0
    for i in range(NUM_ITER):
        angles=math.atan(2**(-i))
        k=k*math.cos(angles)
    #print(K)
    #print(hex(floor(K*(1<<Frac_Bits)+0.5)))
    return  floor(k*Data_Scale+0.5)/Data_Scale  

# cordic 算法迭代
def cordic(theta,k):
    x=k
    y=0
    angle_temp= floor(math.radians(theta)*Data_Scale+0.5)/Data_Scale  
    for i in range(NUM_ITER):
        if(angle_temp>=0):
            x_next=x-y*2**(-i)
            y_next=y+x*2**(-i)
            angle_temp-=Angles_Table[i]
        else:   
            x_next=x+y*2**(-i)
            y_next=y-x*2**(-i)
            angle_temp+=Angles_Table[i]
        x=x_next
        y=y_next
    return x,y

#cordic 算法算出的结果,与真实结果进行比较
def compare(ground_truth, test):
    for i in range(len(ground_truth)): # 如果误差超过 3*2^(-16)次,那么退出比较
        if( abs(ground_truth[i]-test[i])>3):
            print("Error! Loss of accuracy! ground_truth: %f, test: %f", ground_truth[i], test[i])
            return False
    return True
#得到cordic算法结果,经行比较
def main():
    create_angel_table()
    k=compute_k()

    cos_truth=[]
    sin_truth=[]
    cos_test=[]
    sin_test=[]
    
    for i in range(90):
        cos_truth.append(floor(math.cos(i*math.pi/180)*Data_Scale+0.5))
        sin_truth.append(floor(math.sin(i*math.pi/180)*Data_Scale+0.5))
        cos_temp,sin_temp=cordic(i,k)
        cos_test.append(floor(cos_temp*Data_Scale+0.5))
        sin_test.append(floor(sin_temp*Data_Scale+0.5))
        
    if (compare(cos_truth,cos_test) and compare(sin_truth,sin_test)):
        print("Test Pass")
    else:
        print("Test Fail")
    
if __name__ == "__main__":
   main()

比较结果

在这里插入图片描述

由此可知,CORDIC算法精度很高

Verilog 代码

模块代码


module Cordic_Sin(
    input wire [16:0] theta,   // 输入角度(Q1.16格式,范围0 ~ π/2)
    output wire [16:0] sin_out, // 输出sin值(Q1.16格式)
    output wire [16:0] cos_out
);

// 预计算参数(Q1.16格式)
localparam signed [16:0] K =17'sh09B75;  // 1/1.64676补偿因子;  17'h1A592;         

//Q1.15
reg signed [16:0] angles [0:16];    //arctan(2^-i)
integer iter;
initial begin
    angles[0]  = 17'h0C910;
    angles[1]  = 17'h076B2;
    angles[2]  = 17'h03EB7;
    angles[3]  = 17'h01FD6;// i=0~3
    angles[4]  = 17'h00FFB;
    angles[5]  = 17'h007FF;
    angles[6]  = 17'h00400;
    angles[7]  = 17'h00200;// i=4~7
    angles[8]  = 17'h00100;
    angles[9]  = 17'h00080;
    angles[10] = 17'h00040;
    angles[11] = 17'h00020;// i=8~11
    angles[12] = 17'h00010;
    angles[13] = 17'h00008;
    angles[14] = 17'h00004;
    angles[15] = 17'h00002;// i=12~15
    angles[16] = 17'h00001;
end

reg signed [32:0]x,y; //初始化 x=K; y=0
reg signed [32:0]x_next,y_next;
reg signed [17:0] angle; // 初始化角度等于输出角度
integer i;

always@(*)begin
    //初始化
    x={K,16'b0};
    y=33'h0;
    angle={1'b0,theta};
    //迭代计算
    for(i=0;i<16;i=i+1)begin
        if(!angle[17])begin   //
            //正向旋转
            x_next=x-(y>>>i);  //算术移位
            y_next=y+(x>>>i);
            angle=angle-{1'b0,angles[i]};
        end else begin
            //负向旋转
            x_next=x+(y>>>i);
            y_next=y-(x>>>i);
            angle=angle+{1'b0,angles[i]};
        end
        x=x_next;
        y=y_next;
    end
end

assign sin_out = y[32:16];
assign cos_out = x[32:16];

endmodule

Test Bench

`timescale 1ns / 1ps


module Cordic_Sin_Test();
 
 reg  [16:0] theta; 
 wire [16:0] sin_out;
 wire [16:0] cos_out;

initial begin
     
     theta=17'h0;
     #10;
     //15 
     theta=17'h4305;
     #10;
     //30
     theta=17'h860A;
     #10;
     //45
     theta=17'hC90F;
     #10;
     //60
     theta=17'h10C15;
     #10;
     //75
     theta=17'h14F1A;
     #10;
     //90
     theta=17'h1921F;
     #10;
       
end

   Cordic_Sin uut(
    .theta(theta),   // 输入角度(Q1.16格式,范围0 ~ π/2)
    .sin_out(sin_out),// 输出sin值(Q1.16格式)
    .cos_out(cos_out)
);

endmodule

仿真结果

在这里插入图片描述

以上的数据,输入数据需要将其转换成弧度值,然后转换成S0I1F16定点格式,sin,cos准确值也是一样

输入角度sin准确值cos准确值sin计算值cos计算值
06553615465536
15°16962633031696263302
30°32768567563276856755
45°46341463414634046341
60°56756327685675532768
75°63303169626330216962
90°65536065536154

除了个别点外的绝对误差比较大外,其余的计算精度相当高,误差很小

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2323817.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JVM 面经

1、什么是 JVM? JVM 就是 Java 虚拟机&#xff0c;它是 Java 实现跨平台的基石。程序运行之前&#xff0c;需要先通过编译器将 Java 源代码文件编译成 Java 字节码文件&#xff1b;程序运行时&#xff0c;JVM 会对字节码文件进行逐行解释&#xff0c;翻译成机器码指令&#x…

Ubuntu平台下安装Node相关环境

说明&#xff1a;在进行VUE、TS等开发需要用到NodeJS相关环境&#xff0c;不同的项目有时候需要不同的Node版本支撑。本文将详细讲解NVM、Node、Yarn、PM2等环境安装的实施步骤。 测试服务器环境&#xff1a;22.04 LTS。 1. NVM 定义&#xff1a;Node Version Manager&#x…

Windows Server 2025 使用 IIS 搭建 ASP.NET 3.5 网站

开启远程桌面 参考文章Windows server开启远程桌面教程打开服务管理器。ECS 配置安全组&#xff0c;开启 3389Telnet 验证网络联通性 telnet x.x.x.x 338安装 Windows App&#xff0c;登录验证 安装 ASP.NET 3.5 1.参考文章Windows Server 2012安装 .NET Framework 3.5和 Wi…

【强化学习】基于深度强化学习的微能源网能量管理与优化策略研究【Python】

目录 主要内容 程序要点 2.1 微能源网系统组成 2.2 强化学习及Q学习算法 部分代码 运行结果 下载链接 主要内容 该程序借助深度 Q 网络&#xff08;DQN&#xff09;&#xff0c;学习预测负荷、风 / 光可再生能源功率输出及分时电价等环境信息&#xff0c;运用…

楼宇自控借何种技术,驱动建筑迈向高效绿色

在全球积极倡导可持续发展的大背景下&#xff0c;建筑行业作为能源消耗和碳排放的大户&#xff0c;实现高效绿色发展迫在眉睫。楼宇自控系统凭借其先进的技术手段&#xff0c;成为推动建筑向高效绿色转型的关键力量。那么&#xff0c;楼宇自控究竟借助哪些技术&#xff0c;让建…

监控易一体化运维:监控易机房管理,打造高效智能机房

在数字化浪潮中&#xff0c;企业对数据中心和机房的依赖程度与日俱增&#xff0c;机房的稳定运行成为业务持续开展的关键支撑。信息化的变迁&#xff0c;见证了机房管理从传统模式向智能化、精细化转变的过程。今天&#xff0c;就为大家深度剖析监控易在机房管理方面的卓越表现…

PHP安装HTML转图片的扩展GD库的使用

修改你的PHP.ini文件,找到以下位置 ;extensionphp_gd2.dll 把前面的;去掉…

清华大学第10讲:迈向未来的AI教学实验396页PPT 探索未来教育的无限可能|附PPT下载方法

导 读INTRODUCTION 今天跟大家分享的是清华大学新闻与传播学院、人工智能学院双聘教授沈阳教授团队出品的《迈向未来的AI教学实验》课程作业集&#xff0c;随着人工智能技术的飞速发展&#xff0c;教育领域也迎来了前所未有的变革。该报告为沈阳教授与学生们在“迈向未来的AI教…

《白帽子讲 Web 安全》之服务端请求伪造(SSRF)深度剖析:从攻击到防御

引言 在当今复杂的网络环境中&#xff0c;Web 应用安全犹如一座时刻需要精心守护的堡垒。随着技术的不断演进&#xff0c;各类安全威胁层出不穷&#xff0c;其中服务端请求伪造&#xff08;SSRF&#xff09;正逐渐成为令开发者与安全从业者头疼的一大难题。吴翰清在《白帽子讲…

豪越消防一体化安全管控平台:消防管理智能化

在社会快速发展、城市建设日益复杂的今天&#xff0c;消防安全始终是保障人民生命财产安全、维护社会稳定的重要基石。传统消防管理模式在应对当下复杂多变的消防安全需求时&#xff0c;逐渐暴露出诸多局限性&#xff0c;而豪越消防一体化平台的出现&#xff0c;为消防管理领域…

瑞芯微RK356X主板复用接口配置方法,触觉智能嵌入式方案商

本文介绍瑞芯微RK356X系列复用接口配置的方法&#xff0c;基于触觉智能RK3562开发板演示&#xff0c;搭载4核A53处理器&#xff0c;主频高达2.0GHz&#xff1b;内置独立1Tops算力NPU&#xff0c;可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。 复…

NX二次开发刻字功能——预览功能

这个预览功能其实在NX软件中很常见,有利于建模者确定刻字的位置,这个功能早在唐康林老师的超级长方体教程中出现过。我只是学以致用。把该功能集成刻字中。 在勾选预览的同时,如果点击放大镜也就是显示预览结果,要刻字的对象透明度数值为70,同时预览结果文字会变成撤销,如…

容器主机CPU使用率突增问题一则

关键词 LINUX、文件系统crontab 、mlocate根目录使用率 There are many things that can not be broken&#xff01; 如果觉得本文对你有帮助&#xff0c;欢迎点赞、收藏、评论&#xff01; 一、问题现象 业务一台容器服务器&#xff0c;近期经常收到cpu不定期抖动告警&#x…

华为hcia——Datacom实验指南——配置IPv4静态路由,默认路由和浮动静态路由

什么是IPv4 IPv4静态路由&#xff0c;是手动配置的&#xff0c;不会随着网络拓扑的变化而变化&#xff0c;所配置的路由信息也不会在网络中传播&#xff0c;所以它主要运用在小型网络或者作为动态路由的补充。 IPv4的配置 配置的命令很简单 IP route-static &#xff08;目…

【Apache Hive】

一、Hive简介 官网&#xff1a;https://hive.apache.org 1、Hive是什么&#xff1f; Apache Hive 是一款建立在Hadoop之上的开源数据仓库系统&#xff0c;可以将存储在Hadoop文件中的结构化、半结构化数据文件映射为一张数据库表&#xff0c;基于表提供了一种类似SQL的查询模型…

SQL Server安装进度卡在 57%:Windows Update 服务异常

问题现象&#xff1a; 安装 SQL Server 2022 时进度停滞在 57%&#xff0c;日志报错 Error code 0x80070422&#xff0c;提示 “Windows Update 服务未运行”。 快速诊断 检查服务状态&#xff1a; # 查看 Windows Update 服务状态 Get-Service -Name wuauserv | Select-Object…

YOLO历代发展 图像增强方式 架构

YOLO1 YOLOV5 数据增强 mosaic 仿射变换(Affine)、透视变换(Perspective) 网络搭建

DexGrasp Anything:具有物理-觉察的普遍机器人灵巧抓取

25年3月来自上海科技大学的论文“DexGrasp Anything: Towards Universal Robotic Dexterous Grasping with Physics Awareness”。 能够抓取任何物体的灵巧手&#xff0c;对于通用具身智能机器人的开发至关重要。然而&#xff0c;由于灵巧手的自由度高&#xff0c;物体种类繁多…

对称加密算法和非对称加密算法

在这个互联网普及的时代&#xff0c;在不同终端对敏感甚至机密数据进行传输是非常常见的场景&#xff0c;但是如何保证数据传输过程的安全性和高效性是一个值得深入探讨的问题。 为此&#xff0c;伟大的人类研究出了多种加密算法&#xff0c;我们可以大致将其分为两类&#xf…