0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

怎樣使用CORDIC算法求解角度正余弦呢?

FPGA之家 ? 來源:博客園 ? 2023-08-31 14:54 ? 次閱讀

1、算法簡介

CORDIC(Coordinate Rotation Digital Computer)算法即坐標旋轉(zhuǎn)數(shù)字計算方法,是J.D.Volder1于1959年首次提出,主要用于三角函數(shù)、雙曲線、指數(shù)、對數(shù)的計算。該算法通過基本的加和移位運算代替乘法運算,使得矢量的旋轉(zhuǎn)和定向的計算不再需要三角函數(shù)、乘法、開方、反三角、指數(shù)等函數(shù),計算向量長度并能把直角坐標系轉(zhuǎn)換為極坐標系。因為Cordic 算法只用了移位和加法,很容易用純硬件來實現(xiàn),非常適合FPGA實現(xiàn)。

CORDIC算法是天平稱重思想在數(shù)值運算領(lǐng)域的杰出范例。核心的思想是把非線性的問題變成了線性的迭代問題【4】。

CORDIC算法完成坐標或向量的平面旋轉(zhuǎn)(下圖以逆時針旋轉(zhuǎn)為例)。

20a3bca4-47c1-11ee-97a6-92fbcf53809c.png

旋轉(zhuǎn)后,可得如下向量:

20b31a82-47c1-11ee-97a6-92fbcf53809c.png

旋轉(zhuǎn)的角度θ經(jīng)過多次旋轉(zhuǎn)得到的(步步逼近,接近二分查找法),每次旋轉(zhuǎn)一小角度。單步旋轉(zhuǎn)定義如下公式:

20c217f8-47c1-11ee-97a6-92fbcf53809c.png

公式(2)提取cosθ,可修改為:

20d063ee-47c1-11ee-97a6-92fbcf53809c.png

修改后的公式把乘法次數(shù)從4次改為3次,剩下的乘法運算可以通過選擇每次旋轉(zhuǎn)的角度去除,將每一步的正切值選為2的指數(shù)(二分查找法),除以2的指數(shù)可以通過右移操作完成(verilog)。

每次旋轉(zhuǎn)的角度可以表示為:

20da1fba-47c1-11ee-97a6-92fbcf53809c.png

所有迭代角度累加值等于最終需要的旋轉(zhuǎn)角度θ:

20e323a8-47c1-11ee-97a6-92fbcf53809c.png

這里Sn為1或者-1,根據(jù)旋轉(zhuǎn)方向確定(后面有確定方法,公式(15)),順時針為-1,逆時針為1。

20ed1822-47c1-11ee-97a6-92fbcf53809c.png

可以得到如下公式:

20f93c6a-47c1-11ee-97a6-92fbcf53809c.png

結(jié)合公式(3)和(7),得到公式(8):

210b52ce-47c1-11ee-97a6-92fbcf53809c.png

到這里,除了余弦值這個系數(shù),算法只要通過簡單的移位和加法操作完成。而這個系數(shù)可以通過預(yù)先計算最終值消掉。首先重新重寫這個系數(shù)如下:

211ae4b4-47c1-11ee-97a6-92fbcf53809c.png

第二步計算所有的余弦值并相乘,這個值K稱為增益系數(shù)。

2129846a-47c1-11ee-97a6-92fbcf53809c.png

由于K值是常量,我們可以先忽略它。

2138cf60-47c1-11ee-97a6-92fbcf53809c.png

21443a62-47c1-11ee-97a6-92fbcf53809c.png

到這里我們發(fā)現(xiàn),算法只剩下移位和加減法,這就非常適合硬件實現(xiàn)了,為硬件快速計算三角函數(shù)提供了一種新的算法。在進行迭代運算時,需要引入一個新的變量Z,表示需要旋轉(zhuǎn)的角度θ中還沒有旋轉(zhuǎn)的角度。

2151f328-47c1-11ee-97a6-92fbcf53809c.png

這里,我們可以把前面提到確定旋轉(zhuǎn)方向的方法介紹了,就是通過這個變量Z的符號確定。

215959c4-47c1-11ee-97a6-92fbcf53809c.png

216e5108-47c1-11ee-97a6-92fbcf53809c.png

通過公式(5)和(15),將未旋轉(zhuǎn)的角度變?yōu)?。

一個類編程風格的結(jié)構(gòu)如下,反正切值是預(yù)先計算好的。

217d0fcc-47c1-11ee-97a6-92fbcf53809c.png

1.1 旋轉(zhuǎn)模式

旋轉(zhuǎn)模式下,CORDIC算法驅(qū)動Z變?yōu)?,結(jié)合公式(13)和(16),算法的核心計算如下:

21932a14-47c1-11ee-97a6-92fbcf53809c.png

一種特殊情況是,另初始值如下:

219d895a-47c1-11ee-97a6-92fbcf53809c.png

因此,旋轉(zhuǎn)模式下CORDIC算法可以計算一個輸入角度的正弦值和余弦值。

1.2 向量模式

向量模式下,有兩種特例:

21ac4210-47c1-11ee-97a6-92fbcf53809c.png

因此,向量模式下CORDIC算法可以用來計算輸入向量的模和反正切,也能開方計算,并可以將直角坐標轉(zhuǎn)換為極坐標。

2、硬件算法實現(xiàn)

根據(jù)【5】,可以看到CORDIC迭代算法的一種直接實現(xiàn)方式是反饋結(jié)構(gòu),此結(jié)構(gòu)只設(shè)計一級CORDIC運算迭代單元、然后在系統(tǒng)時鐘的驅(qū)動下,將本級的輸出作為本級的輸入,通過同一級迭代完成運算。這種方法硬件開銷小、但控制相對復雜。

所以根據(jù)【1】、【2】,使用流水線結(jié)構(gòu)實現(xiàn)了CORDIC迭代算法、求取了角度的正弦和余弦值。

下面分段介紹下各部分代碼:

首先是角度的表示,進行了宏定義,360讀用16位二進制表示2^16,每一度為2^16/360。

//360°--2^16,phase_in = 16bits (input [15:0] phase_in)
//1°--2^16/360
`define rot0  16'h2000    //45
`define rot1  16'h12e4    //26.5651
`define rot2  16'h09fb    //14.0362
`define rot3  16'h0511    //7.1250
`define rot4  16'h028b    //3.5763
`define rot5  16'h0145    //1.7899
`define rot6  16'h00a3    //0.8952
`define rot7  16'h0051    //0.4476
`define rot8  16'h0028    //0.2238
`define rot9  16'h0014    //0.1119
`define rot10 16'h000a    //0.0560
`define rot11 16'h0005    //0.0280
`define rot12 16'h0003    //0.0140
`define rot13 16'h0002    //0.0070
`define rot14 16'h0001    //0.0035
`define rot15 16'h0000    //0.0018

然后是流水線級數(shù)定義、增益放大倍數(shù)以及中間結(jié)果位寬定義。流水線級數(shù)16,為了滿足精度要求,有文獻指出流水線級數(shù)必須大于等于角度位寬16(針對正弦余弦計算的CORDIC算法優(yōu)化及其FPGA實現(xiàn))。增益放大2^16,為了避免溢出狀況中間結(jié)果(x,y,z)定義為17為,最高位作為符號位判斷,1為負數(shù),0為正數(shù)。

module cordic
(
    input clk,
    
    input [15:0] phase_in,
    output reg signed [16:0] eps,
    output reg signed [16:0] sin,
    output reg signed [16:0] cos
);
parameter PIPELINE = 16;

parameter K = 16'h9b74;
//gian k=0.607253*2^16,9b74,n means the number pipeline
//pipeline 16-level    //maybe overflow,matlab result not overflow
//MSB is signed bit,transform the sin and cos according to phase_in[15:14]
reg signed [16:0] x0=0,y0=0,z0=0;
reg signed [16:0] x1=0,y1=0,z1=0;
reg signed [16:0] x2=0,y2=0,z2=0;
reg signed [16:0] x3=0,y3=0,z3=0;
reg signed [16:0] x4=0,y4=0,z4=0;
reg signed [16:0] x5=0,y5=0,z5=0;
reg signed [16:0] x6=0,y6=0,z6=0;
reg signed [16:0] x7=0,y7=0,z7=0;
reg signed [16:0] x8=0,y8=0,z8=0;
reg signed [16:0] x9=0,y9=0,z9=0;
reg signed [16:0] x10=0,y10=0,z10=0;
reg signed [16:0] x11=0,y11=0,z11=0;
reg signed [16:0] x12=0,y12=0,z12=0;
reg signed [16:0] x13=0,y13=0,z13=0;
reg signed [16:0] x14=0,y14=0,z14=0;
reg signed [16:0] x15=0,y15=0,z15=0;
reg signed [16:0] x16=0,y16=0,z16=0;

還需要定義memory型寄存器數(shù)組并初始化為0,用于寄存輸入角度高2位的值。

reg [1:0] quadrant [PIPELINE:0];
integer i;
initial
begin
    for(i=0;i<=PIPELINE;i=i+1)
    quadrant[i] = 2'b0;
end

接著,是對輸入角度象限處理,將角度都轉(zhuǎn)換到第一象限,方便處理。輸入角度值最高兩位賦值0,即轉(zhuǎn)移到第一象限[0°,90°]。此外,完成x0,y0和z0的初始化,并增加一位符號位。

always @ (posedge clk)//stage 0,not pipeline
begin
    x0 <= {1'b0,K}; //add one signed bit,0 means positive
    y0 <= 17'b0;
    z0 <= {3'b0,phase_in[13:0]};//control the phase_in to the range[0-Pi/2]
end

接下來根據(jù)剩余待旋轉(zhuǎn)角度z的符號位進行16次迭代處理,即完成16級流水線處理。

View Code

其中使用到了算數(shù)右移(>>>)運算、所以在之前聲明時將相應(yīng)的reg/wire均聲明為signed類型。這一點在【1】的最后也有說明。

需要注意的是這里的算數(shù)移位運算(這一運算的詳細過程在【3】中進行了說明),與之區(qū)分的是邏輯移位運算。

二者規(guī)則為:

邏輯左移和右移,空出的位均補零。

算數(shù)左移與邏輯左移相同,都在低位補零;算數(shù)右移、移出的高位比特使用符號位填充(0正1負)

舉例說明,對8'b_1011_0111進行邏輯、算數(shù)移位的結(jié)果如下圖所示:

2216cc84-47c1-11ee-97a6-92fbcf53809c.png

比如這里的原數(shù)值是8'b10110111、為負數(shù)(補碼形式)、換算成十進制為-73.

算數(shù)右移一位之后的結(jié)果是8'b11011011、由補碼換算成原碼再換算為十進制為-37.

由于進行了象限的轉(zhuǎn)換,最終流水結(jié)果需要根據(jù)象限進行轉(zhuǎn)換為正確的值。這里寄存17次高2位角度輸入值,配合流水線結(jié)果用于象限判斷,并完成轉(zhuǎn)換。

//according to the pipeline,register phase_in[15:14]
always @ (posedge clk)
begin
quadrant[0] <= phase_in[15:14];
quadrant[1] <= quadrant[0];
quadrant[2] <= quadrant[1];
quadrant[3] <= quadrant[2];
quadrant[4] <= quadrant[3];
quadrant[5] <= quadrant[4];
quadrant[6] <= quadrant[5];
quadrant[7] <= quadrant[6];
quadrant[8] <= quadrant[7];
quadrant[9] <= quadrant[8];
quadrant[10] <= quadrant[9];
quadrant[11] <= quadrant[10];
quadrant[12] <= quadrant[11];
quadrant[13] <= quadrant[12];
quadrant[14] <= quadrant[13];
quadrant[15] <= quadrant[14];
quadrant[16] <= quadrant[15];
end

最后,根據(jù)寄存的高2位角度輸入值,利用三角函數(shù)關(guān)系,得出最后的結(jié)果,其中負數(shù)進行了補碼操作。

//alter register, according to quadrant[16] to transform the result to the right result
always @ (posedge clk)
    eps <= z16;

always @ (posedge clk) begin
case(quadrant[16]) //or 15
2'b00:begin //if the phase is in first quadrant,the sin(X)=sin(A),cos(X)=cos(A)
        cos <= x16;
        sin <= y16;
        end
2'b01:begin //if the phase is in second quadrant,the sin(X)=sin(A+90)=cosA,cos(X)=cos(A+90)=-sinA
        cos <= ~(y16) + 1'b1;//-sin
        sin <= x16;//cos
        end
2'b10:begin //if the phase is in third quadrant,the sin(X)=sin(A+180)=-sinA,cos(X)=cos(A+180)=-cosA
        cos <= ~(x16) + 1'b1;//-cos
        sin <= ~(y16) + 1'b1;//-sin
        end
2'b11:begin //if the phase is in forth quadrant,the sin(X)=sin(A+270)=-cosA,cos(X)=cos(A+270)=sinA
        cos <= y16;//sin
        sin <= ~(x16) + 1'b1;//-cos
        end
endcase
end

完整代碼:

220bf228-47c1-11ee-97a6-92fbcf53809c.jpgWhole Code

testbench測試代碼:

220bf228-47c1-11ee-97a6-92fbcf53809c.jpgTestbench

3、Modelsim仿真結(jié)果

2261b8e8-47c1-11ee-97a6-92fbcf53809c.png

仿真結(jié)果的補充說明:

(1)程序全程未使用復位信號,testbench中第一個計算的角度為16'h2000也就是45度,如果以圖示時刻為0時刻、仿真結(jié)果對應(yīng)的波形即分別為sin(x+π/4)和cos(x+π/4)的波形。作為參考,0.5*√2*65535≈46340.

(2)關(guān)于運算過程中的位數(shù)溢出

根據(jù)仿真結(jié)果,本測試例下,x4出現(xiàn)過16位位數(shù)溢出。

(3)關(guān)于流水線設(shè)計的理解

前文提到過實現(xiàn)CORDIC迭代算法時可以使用反饋結(jié)構(gòu)(只使用一級)、也可以使用流水線結(jié)構(gòu)(多級),如果任務(wù)是只單獨計算一個角度的正弦或者余弦值,那么所需要的迭代次數(shù)或者說消耗的時鐘周期數(shù)量其實是相同的,本設(shè)計中為16個時鐘。

流水線結(jié)構(gòu)的威力是在連續(xù)、源源不斷地計算一組多個角度的正余弦值的時候才展現(xiàn)出來,當初始流水線被填滿之后,每經(jīng)過一個時鐘周期、都會在輸出上獲得一個更新的角度的正余弦結(jié)果值,上圖仿真結(jié)果圖中黃色cursor左側(cè)的時間段內(nèi)、流水線即被逐步填滿。

換句話說,如果現(xiàn)在的任務(wù)是要計算n個角度的正余弦值、計算一個角度需要的迭代次數(shù)為x,反饋結(jié)構(gòu)需要的時長為(n*x)個時鐘周期,流水線結(jié)構(gòu)只需要(n+x-1)個時鐘周期。







審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • FPGA
    +關(guān)注

    關(guān)注

    1630

    文章

    21777

    瀏覽量

    604733
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5359

    瀏覽量

    120816
  • 向量機
    +關(guān)注

    關(guān)注

    0

    文章

    166

    瀏覽量

    20891
  • CORDIC
    +關(guān)注

    關(guān)注

    0

    文章

    37

    瀏覽量

    19983
  • CORDIC算法
    +關(guān)注

    關(guān)注

    0

    文章

    17

    瀏覽量

    9751

原文標題:使用CORDIC算法求解角度正余弦及Verilog實現(xiàn)

文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    基于改進的CORDIC算法的FFT復乘及其FPGA實現(xiàn)

    的性能。但傳統(tǒng)CORDIC算法中每次CORDIC迭代方向需由剩余角度的計算來確定,影響了工作速度。為此,本文根據(jù)定點FFT復乘中旋轉(zhuǎn)因子的旋轉(zhuǎn)方向可預(yù)先確定的特點,對
    發(fā)表于 07-11 21:32

    分分鐘看懂CORDIC算法

    最近出于項目需要,對CORDIC算法深入學習下。剛開始的時候上網(wǎng)搜了下資料發(fā)現(xiàn)一上來就直接是推導公式,然后工程運用與理論推導聯(lián)系太少感覺無從下手!對于像我們數(shù)學丟了很多年的同學來說實在是痛苦啊。好在
    發(fā)表于 08-11 14:05

    CORDIC算法求助

    請問CORDIC算法用verilog算法實現(xiàn)時,角度累加器中的45度,26.56度,14.04度怎么跟verilog語言相對應(yīng)?
    發(fā)表于 07-11 20:18

    基于UDB的CORDIC

    大家好,這是一個UDP實現(xiàn)的16位定點CORDIC,用于計算給定角度的正弦和余弦。它在PSoC 3上被支持,并且可能(忽略警告)運行到33 MHz。我已經(jīng)附上了一個演示項目與項目庫,所以嘗試運行它在
    發(fā)表于 05-24 10:03

    FPGA設(shè)計中必須掌握的Cordic算法

    大多數(shù)工程師在碰到需要在 FPGA 中實現(xiàn)諸如正弦、余弦或開平方這樣的數(shù)學函數(shù)時,首先會想到的是用查找表,可能再結(jié)合線性內(nèi)插或者冪級數(shù)(如果有乘法器可用)。不過對這種工作來說,CORDIC 算法
    發(fā)表于 09-19 09:07

    高性能HPOR CORDIC算法及實現(xiàn)

    CORDIC 算法在通信和圖像處理等各個領(lǐng)域有著廣泛的應(yīng)用,但是浮點CORDIC 由于迭代延時大且實現(xiàn)復雜沒有得到很好的應(yīng)用,本文提出了一種修正浮點CORDIC
    發(fā)表于 12-15 14:27 ?15次下載

    基于CORDIC算法的載波同步鎖相環(huán)設(shè)計

    研究了一種利用CORDIC算法的矢量及旋轉(zhuǎn)模式對載波同步中相位偏移進行估計并校正的方法。設(shè)計并實現(xiàn)了基于CORDIC算法的數(shù)字鎖相環(huán)。通過仿真,驗證了設(shè)計的有效性和高效性。
    發(fā)表于 12-15 14:49 ?0次下載
    基于<b class='flag-5'>CORDIC</b><b class='flag-5'>算法</b>的載波同步鎖相環(huán)設(shè)計

    FPGA實現(xiàn)高精度余弦函數(shù)

    在研究CORDIC算法的數(shù)學基礎(chǔ)上,采用流水線的硬件結(jié)構(gòu)實現(xiàn)了該算法,并在Altera公司的FPGA芯片上進行了驗證,使余弦函數(shù)的計算達到
    發(fā)表于 12-16 14:30 ?33次下載
    FPGA實現(xiàn)高精度<b class='flag-5'>正</b><b class='flag-5'>余弦</b>函數(shù)

    求解特定消諧逆變器開關(guān)角度的完備算法_楊克虎

    求解特定消諧逆變器開關(guān)角度的完備算法_楊克虎
    發(fā)表于 01-08 11:28 ?1次下載

    使用Xilinx CORDIC IP核生成、余弦

    本文介紹如何調(diào)用Xilinx的CORDIC IP核生成某一頻率的正弦波和余弦波。 主要是CORDIC IP核的設(shè)置,下面對其具體參數(shù)的設(shè)置進行了說明。 標注1:選擇函數(shù)的類型,這里選擇sin和cos
    發(fā)表于 02-08 15:24 ?6499次閱讀
    使用Xilinx <b class='flag-5'>CORDIC</b> IP核生成<b class='flag-5'>正</b>、<b class='flag-5'>余弦</b>波

    FPGA基于CORDIC算法的求平方實現(xiàn)

    CORDIC是在沒有專用乘法器(最小化門數(shù)量)情況下,一組完成特定功能的算法,包括平方、超越、Log、sin/cos/artan。原理為連續(xù)的旋轉(zhuǎn)一個較小的角度,以一定精度逼近想要的角度
    發(fā)表于 02-11 19:24 ?5889次閱讀

    基于FPGA的Cordic算法實現(xiàn)的設(shè)計與驗證

    本文是基于FPGA實現(xiàn)Cordic算法的設(shè)計與驗證,使用Verilog HDL設(shè)計,初步可實現(xiàn)正弦、余弦、反正切函數(shù)的實現(xiàn)。將復雜的運算轉(zhuǎn)化成FPGA擅長的加減法和乘法,而乘法運算可以用移位運算代替
    發(fā)表于 07-03 10:18 ?2809次閱讀
    基于FPGA的<b class='flag-5'>Cordic</b><b class='flag-5'>算法</b>實現(xiàn)的設(shè)計與驗證

    一文帶你們了解什么是CORDIC算法

    CORDIC算法簡介 在信號處理領(lǐng)域,CORDIC(Coordinate Rotation Digital Computer,坐標旋轉(zhuǎn)數(shù)字計算機)算法具有重大工程意義。
    的頭像 發(fā)表于 04-11 11:16 ?1.5w次閱讀
    一文帶你們了解什么是<b class='flag-5'>CORDIC</b><b class='flag-5'>算法</b>

    FPGA實現(xiàn)Cordic算法求解arctanθ

    由于在項目中需要使用的MPU6050,進行姿態(tài)解算,計算中設(shè)計到arctan 和 sqr(x*2 + y * 2),這兩部分的計算,在了解了一番之后,發(fā)現(xiàn)Cordic算法可以很方便的一次性求出這兩個這兩部分的計算。
    的頭像 發(fā)表于 09-27 09:30 ?2233次閱讀
    FPGA實現(xiàn)<b class='flag-5'>Cordic</b><b class='flag-5'>算法</b><b class='flag-5'>求解</b>arctanθ

    深度解析CORDIC算法原理

    CORDIC算法的思想是通過迭代的方法,使得累計旋轉(zhuǎn)過的角度的和無限接近目標角度。它是一種數(shù)值計算逼近的方法,運算只有移位和加減。
    的頭像 發(fā)表于 04-29 16:48 ?2949次閱讀
    深度解析<b class='flag-5'>CORDIC</b><b class='flag-5'>算法</b>原理