CORDIC算法:三角函數的硬件加速革命——從數學原理到FPGA實現的超高效計算方案

計算機該如何求解三角函數?或許你的第一印象是采用泰勒展開,或者采用多項式進行逼近。對于前者,來回的迭代計算開銷成本很大;對于后者,多項式式逼近在較窄的范圍內比較接近,超過一定范圍后,就變得十分不理想了。例如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(θ)=y1?cos(θ)+x1?sin(θ)=cos(θ)(y1?+x1?tan(θ))x2?=cos(α)cos(θ)?sin(α)sin(θ)=x1?cos(θ)?y1?sin(θ)=cos(θ)(x1??y1?tan(θ))?

默認初始值為(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} [x2?y2??]=cos(α)[1tan(α)??tan(α)1?][x1?y1??]
如果將令角度α,滿足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} [xn?yn??]=cos(αn?)[12?n??2?n1?][xn?1?yn?1??]=cos(αn?)cos(αn?1?)..cos(α0?)[12?n??2?n1?][12?n+1??2?n+11?]..[12?0??2?01?][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} [xn?yn??]=cos(αn?)[12?n??2?n1?][xn?1?yn?1??]=cos(αn?)cos(αn?1?)..cos(α0?)[12?n??2?n1?][12?n+1??2?n+11?]..[12?0??2?01?][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(αn?1?)cos(αn?2?)...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?+dn??xn??2?nxn+1?=xn??d?yn??2?nanglen+1?=anglen??d?tableofangles[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 floorNUM_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.0for 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=ky=0angle_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_nexty=y_nextreturn 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 Falsereturn 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 beginangles[0]  = 17'h0C910;angles[1]  = 17'h076B2;angles[2]  = 17'h03EB7;angles[3]  = 17'h01FD6;// i=0~3angles[4]  = 17'h00FFB;angles[5]  = 17'h007FF;angles[6]  = 17'h00400;angles[7]  = 17'h00200;// i=4~7angles[8]  = 17'h00100;angles[9]  = 17'h00080;angles[10] = 17'h00040;angles[11] = 17'h00020;// i=8~11angles[12] = 17'h00010;angles[13] = 17'h00008;angles[14] = 17'h00004;angles[15] = 17'h00002;// i=12~15angles[16] = 17'h00001;
endreg 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)beginif(!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]};endx=x_next;y=y_next;end
endassign sin_out = y[32:16];
assign cos_out = x[32:16];endmodule

Test Bench

`timescale 1ns / 1psmodule Cordic_Sin_Test();reg  [16:0] theta; wire [16:0] sin_out;wire [16:0] cos_out;initial begintheta=17'h0;#10;//15 theta=17'h4305;#10;//30theta=17'h860A;#10;//45theta=17'hC90F;#10;//60theta=17'h10C15;#10;//75theta=17'h14F1A;#10;//90theta=17'h1921F;#10;endCordic_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.pswp.cn/pingmian/73743.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/73743.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/73743.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【剪輯_BGM 整合】

【優質BGM?以剪映為基礎】 自定義 一、舒緩愜意 二、輕快 1&#xff0c;快樂騎行 2&#xff0c;醫療科普 3&#xff0c;宣傳片勵志搖滾熱血 Going back to Business 4&#xff0c;電子寵物&#xff08;memories&#xff09; 5&#xff0c;詩與遠方&#xff08;熱播&…

linux 常見命令使用介紹

Linux 常見命令使用介紹 Linux 是一個功能強大的操作系統&#xff0c;其核心是命令行工具。掌握一些常用的 Linux 命令可以極大地提高工作效率。本文將詳細介紹一些常見的 Linux 命令及其用法。 1. 文件與目錄操作 ls - 列出文件和目錄 # 查看當前目錄下的所有文件和子目錄&…

Rust從入門到精通之精通篇:24.高級異步編程

高級異步編程 在 Rust 精通篇中&#xff0c;我們將深入探索 Rust 的高級異步編程技術。Rust 的異步編程模型基于 Future 特征和異步運行時&#xff0c;提供了高效的非阻塞 I/O 和并發處理能力。在本章中&#xff0c;我們將超越基礎知識&#xff0c;探索如何構建高性能異步系統…

(C語言)學生信息表(基于通訊錄改版)(測試版)(C語言項目)

1.首先是頭文件&#xff1a; //student.h //頭文件//防止頭文件被重復包含#pragma once//宏定義符號常量&#xff0c;方便維護和修改 #define ID_MAX 20 #define NAME_MAX 20 #define AGE_MAX 5 #define SEX_MAX 5 #define CLA_MAX 20 //定義初始最大容量 #define MAX 1//定義結…

Problem D: 抽象類

1.題目問題 2.輸入 3.輸出 4.代碼實現 補充&#xff1a; 沒錯&#xff0c;你沒看錯&#xff0c;沒有 abstract class Vehicle &#xff0c;才能過。 惡心人 答案&#xff1a; {abstract void NoOfWheels(); }class Car extends Vehicle {Overridepublic void NoOfWheels()…

UniApp開發多端應用——流式語音交互場景優化

一、問題背景&#xff1a;UniApp默認方案的局限性 在流式語音交互場景&#xff08;如AI語音助手、實時字幕生成&#xff09;中&#xff0c;UniApp默認的uni.getRecorderManager 和uni.createInnerAudioContext 存在以下瓶頸&#xff1a; 錄音端&#xff1a; 延遲高&#xff1…

docker構建并啟動前端

docker文件示例代碼&#xff1a; # Use a minimal image for development FROM node:18-alpine# Set working directory inside the container WORKDIR /app# Copy package.json and package-lock.json (or yarn.lock) into the container COPY package.json package-lock.jso…

25大唐杯賽道一本科B組大綱總結(上)

25大唐杯省賽馬上要開始&#xff0c;還沒開始準備的要抓緊了 可看我之前發的備賽攻略&#xff0c;理論的準備要先將大綱整理成思維導圖框架 然后根據重點&#xff0c;在資料中尋找&#xff0c;記憶 這里幫大家整理好了&#xff0c;后續其他組別會相繼更新 基于競賽大綱做的思…

【Python3教程】Python3基礎篇之Lambda(匿名函數)

博主介紹:?全網粉絲22W+,CSDN博客專家、Java領域優質創作者,掘金/華為云/阿里云/InfoQ等平臺優質作者、專注于Java技術領域? 技術范圍:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大數據、物聯網、機器學習等設計與開發。 感興趣的可…

重試機制之指針退避策略算法

一、目的&#xff1a;隨著重試次數增加&#xff0c;逐步延長重連等待時間&#xff0c;避免加重服務器負擔。 二、計算公式&#xff1a; 每次重試的延遲時間 初始間隔 (退避基數 ^ 重試次數) 通常設置上限防止等待時間過長。 const delay Math.min(initialDelay * Math.pow…

SSE SseEmitter.completeWithError(e) 觸發的處理邏輯

在 Java 客戶端使用 OkHttp 監聽 SSE&#xff08;Server-Sent Events&#xff09; 的情況下&#xff0c;當服務端調用 SseEmitter.completeWithError(e)&#xff0c;客戶端會觸發 EventSourceListener 的 onFailure() 方法&#xff08;而不是 onError&#xff09;。 1. 服務端&…

4月手機新品前瞻,影像,性能與設計卷得起飛

在智能手機市場中,4月向來是新品頻發的黃金時段。各大手機廠商紛紛摩拳擦掌,準備推出自家的重磅機型,在影像、性能與設計等核心領域展開激烈角逐,一場沒有硝煙的“科技大戰”即將拉開帷幕。接下來,讓我們一同深入了解那些備受矚目的新品,提前感受科技進步帶來的魅力。 一…

設計審查效率革命|CAD原生數據直通自動公差驗證

“為何 90% 的 GD&T 問題在設計評審時未被發現&#xff1f;怎樣避免因 GD&T 考慮不周導致的批量返工&#xff1f;” 這正是 CETOL 自動輔助審查設計系統要解決的核心問題&#xff1a;通過200結構化審查規則攔截潛在設計疏漏。 功能一&#xff1a;裝配約束健康診斷&…

k8s scheduler幾種擴展方式的關系及區別

網上關于scheduler擴展介紹的文章很多&#xff0c;但都是東說一句西說一嘴&#xff0c;完全沒有邏輯性&#xff0c;對于邏輯建構者看著很痛苦&#xff0c;這篇文章不會深入教你怎么擴展&#xff0c;而是教你幾種擴展方式的關系和邏輯結構&#xff1a; 目前Kubernetes支持五種方…

近場探頭的選型

近場探頭包括磁場探頭和電場探頭。 下圖中畫圈的是電場探頭&#xff1a; 左側3只是磁場探頭&#xff0c;最右側一只是電場探頭。不同孔徑的磁場探頭的有效測量距離和分辨率不同 電場探頭和磁場探頭分別在什么情況下使用&#xff1a; 一般近場測試&#xff0c;使用的都是磁場探…

Pycharm運行時報“Empty suite”,可能是忽略了這個問題

問題&#xff1a;使用Pycharm運行testcases目錄下的.py文件&#xff0c;報“Empty suite”&#xff0c;沒有找到測試項。 排查過python解釋器、pytest框架安裝等等&#xff0c;依然報這個錯&#xff0c;依然沒找到&#xff0c;最后終端運行&#xff1a; pytest test_demo.py&a…

鴻蒙北向應用開發:deveco 5.0 kit化文件相關2

鴻蒙北向應用開發:deveco 5.0 kit化文件相關 在kit化時,有時候會出現這樣一種場景即你想把已有的d.ts導出換個名字,這樣從名字上更貼合你的kit聚合 什么意思呢?比如現在有 ohos.hilog.d.ts 導出了hilog,現在你想kit化hilog,使得hilog導出名字為usrhilog,這樣用戶在使用你的k…

《Python實戰進階》No37: 強化學習入門:Q-Learning 與 DQN-加餐版1 Q-Learning算法可視化

在《Python實戰進階》No37: 強化學習入門&#xff1a;Q-Learning 與 DQN 這篇文章中&#xff0c;我們介紹了Q-Learning算法走出迷宮的代碼實踐&#xff0c;本文加餐&#xff0c;把Q-Learning算法通過代碼可視化呈現。我嘗試了使用Matplotlib實現&#xff0c;但局限于Matplotli…

Linux 搭建dns主域解析,和反向解析

#!/bin/bash # DNS主域名服務 # user li 20250325# 檢查當前用戶是否為root用戶 # 因為配置DNS服務通常需要較高的權限&#xff0c;只有root用戶才能進行一些關鍵操作 if [ "$USER" ! "root" ]; then# 如果不是root用戶&#xff0c;輸出錯誤信息echo "…

GenBI 中如何引入 LLM 做意圖路由,區分查數據還是閑聊

寫在前面 生成式商業智能(Generative BI, GenBI)的魅力在于其能夠理解用戶的自然語言,并將復雜的數據查詢和分析過程自動化。用戶不再需要學習 SQL 或操作復雜的界面,只需像與同事交談一樣提出問題,就能獲得數據洞察。然而,一個現實的挑戰是:用戶的輸入并非總是明確的數…