CORDIC 算法实现 _FPGA

注:本文为 “CORDIC 算法” 相关文章合辑。

未整理去重。

如有内容异常,请看原文。


Cordic 算法的原理介绍

乐富道 2014-01-28 23:05

Cordic 算法知道正弦和余弦值,求反正切,即角度。

采用用不断的旋转求出对应的正弦余弦值,是一种近似求解发。

旋转的角度很讲求,每次旋转的角度必须使得 正切值近似等于 1 2 N \frac{1}{2^N} 2N1。旋转的目的是让 Y Y Y 轴趋近与 0 0 0。把每次旋转的角度累加,即得到旋转的角度和即为正切值。

比如 Y Y Y 轴旋转 4 5 ∘ 45^{\circ} 45,则值减小 1 2 \frac{1}{2} 21;

再旋转 26.5650 5 ∘ 26.56505^{\circ} 26.56505,再减少 1 4 \frac{1}{4} 41;

再旋转角度 14.0362 4 ∘ 14.03624^{\circ} 14.03624,再减少 1 8 \frac{1}{8} 81; 依次减少 1 16 \frac{1}{16} 161 1 32 ⋯ ⋯ \frac{1}{32}\cdots\cdots 321⋯⋯,最后 Y Y Y 轴的值无限小,趋近于 0 0 0

比如 X = 1 X = 1 X=1 Y = 1 Y = 1 Y=1,的角度,角度是 4 5 ∘ 45^{\circ} 45。经过一次旋转,要使得 Y = 0 Y = 0 Y=0,这个角度必须是 4 5 ∘ 45^{\circ} 45

img

如上图

img

如图中,直角坐标系中点( X 0 X_0 X0 Y 0 Y_0 Y0)逆时钟旋转角度 θ \theta θ,变换成坐标( X 1 X_1 X1 Y 1 Y_1 Y1),那么用 X 0 X_0 X0 Y 0 Y_0 Y0,以及 θ \theta θ 的三角函数,如果表示 X 1 X_1 X1 Y 1 Y_1 Y1 呢?

img

请想象,如果坐标也旋转角度 θ \theta θ,那么 X 1 X_1 X1 Y 1 Y_1 Y1 的坐标依然是( X 0 X_0 X0 Y 0 Y_0 Y0)。接着往下看:

img

看完以上这副图,就该明白这个等式了:

x 1 = x 0 cos ⁡ θ − y 0 sin ⁡ θ x_1 = x_0\cos\theta - y_0\sin\theta x1=x0cosθy0sinθ

y 1 = x 0 sin ⁡ θ + y 0 cos ⁡ θ y_1 = x_0\sin\theta + y_0\cos\theta y1=x0sinθ+y0cosθ

再把这个式子化成正切函数。

img

Cordic 算法的思想是通过迭代的方法,不断的旋转特定的角度(这个特定的角度就是使得 Y Y Y 为上次的 1 2 \frac{1}{2} 21),使得累计旋转的角度的和无限接近某一设定的角度,

每次旋转的角度的 θ = arctan ⁡ ( 1 2 n ) \theta = \arctan(\frac{1}{2^n}) θ=arctan(2n1)

img

具体迭代如下表: Z 0 = 3 0 ∘ Z_0 = 30^{\circ} Z0=30 Y 0 = 0 Y_0 = 0 Y0=0 X 0 = 0.6073 X_0 = 0.6073 X0=0.6073

输入 3 0 ∘ 30^{\circ} 30,经过 9 9 9 次迭代后, Z 0 = 0 Z_0 = 0 Z0=0 Y 0 = 0.5006 Y_0 = 0.5006 Y0=0.5006 X 0 = 0.8657 X_0 = 0.8657 X0=0.8657

img

x ( i + 1 ) ′ = ( x i ′ − y i ′ ( σ i ) 2 − i ) x'_{(i + 1)} = (x'_i - y'_i(\sigma_i)2^{-i}) x(i+1)=(xiyi(σi)2i)

y ( i + 1 ) ′ = ( x i ′ ( σ i ) 2 − i + y i ′ ) y'_{(i + 1)} = (x'_i(\sigma_i)2^{-i} + y'_i) y(i+1)=(xi(σi)2i+yi)

(当 i = 0 i = 0 i=0)

x 1 ′ = 0.607 − 0 ⋅ ( + 1 ) ⋅ 1 = 0.607 x'_1 = 0.607 - 0 \cdot (+1 ) \cdot 1 = 0.607 x1=0.6070(+1)1=0.607

y 1 ′ = 0.607 ⋅ ( + 1 ) ⋅ 1 + 0 = 0.607 y'_1 = 0.607 \cdot (+1 ) \cdot 1 + 0 = 0.607 y1=0.607(+1)1+0=0.607

通过 Cordic 算法后,得到

y 9 = 0.5006 ( = sin ⁡ ( 3 0 ∘ ) ) y_9 = 0.5006 (=\sin(30^{\circ})) y9=0.5006(=sin(30))

x 9 = 0.8657 ( = cos ⁡ ( 3 0 ∘ ) ) x_9 = 0.8657 (=\cos(30^{\circ})) x9=0.8657(=cos(30))

所以也可以用 cordic 算法求出正切值的。

或者求反正切值:

img

计算公式:

img

posted @ 2014-01-28 23:05 乐富道


基于 FPGA 的 CORDIC 算法实现 —— Verilog 版

善良的一休君于 2017-08-21 20:07:34 发布

目前,学习与开发 FPGA 的程序员们大多使用的是 Verilog HDL 语言(以下简称为 Verilog),关于 Verilog 的诸多优点一休哥就不多介绍了,在此,我们将重点放在 Verilog 的运算操作上。

我们都知道,在 Verilog 中,运算一般分为逻辑运算(与或非等)与算术运算(加减乘除等)。而在一开始学习 Verilog 时,老司机一定会提醒我们,“切记,千万别用‘/’除、‘%’取模(有的也叫取余)和‘**’幂。” 这话说的不无道理,因为这三个运算是不可综合的。但,需清楚理解的是,不可综合的具体意思为不能综合为简单的模块,当我们在程序中调用了这些运算时,‘/’除和‘%’取模在 Quartus 软件中是可以综合的,因此可以正常调用运行,但是会消耗一些逻辑资源,而且会产生延时,即这两个运算的处理时间会很长,可能会大于时序控制时钟的单周期时间。此时呢,我们会建议你调用 IP 核来实现运算操作,虽然这样也会消耗许多逻辑资源,但产生的延时相对较小满足了你基本的需求。

问题好像迎刃而解了,可是仔细一想,除了这些运算,我们还剩下什么?对呀,三角函数,反三角函数,对数函数,指数函数呢,这些函数我们在高中就学习了的呀,难道在 FPGA 中就没有用武之地吗?有人会说,查找表呗,首先将某个运算的所有可能的输入与输出对一一罗列出来,然后放进 Rom 中,然后根据输入查表得到输出。这个方法虽然有效的避免了延时问题,却是一个十分消耗资源的方法,不适合资源紧张的设计。那么,就真的没有办法了吗?

答案就是咱们今天的标题了,CORDIC,而且 CORDIC 是一个比较全能的算法,通过这一原理,我们可以实现三角函数,反三角函数,对数函数,指数函数等多种运算。接下来,一休哥就带领大家来学习 CORDIC 的原理吧。(题外话:请相信一休哥,本文不会让你感到太多痛苦~)

本文将分三个小部分来展开介绍:

1、CORDIC 的基本原理介绍

2、CORDIC 的具体操作流程介绍

3、CORDIC 的旋转模式 ——Verilog 仿真

本文涉及到的全部资料链接:

链接:http://pan.baidu.com/s/1gfrJzMj
密码:x92u

一、CORDIC 的基本原理介绍

CORDIC 算法是一个 “化繁为简” 的算法,将许多复杂的运算转化为一种 “仅需要移位和加法” 的迭代操作。CORDIC 算法有旋转和向量两个模式,分别可以在圆坐标系、线性坐标系和双曲线坐标系使用,从而可以演算出 8 种运算,而结合这 8 种运算也可以衍生出其他许多运算。下表展示了 8 种运算在 CORDIC 算法中实现的条件。

这里写图片描述

这里写图片描述

首先,我们先从旋转模式下的圆坐标系讲起,这也是 CORDIC 方法最初的用途。

1、CORDIC 的几何原理介绍

假设在 x y xy xy 坐标系中有一个点 P 1 ( x 1 , y 1 ) P1(x_1,y_1) P1(x1,y1),将 P 1 P1 P1 点绕原点旋转 θ \theta θ 角后得到点 P 2 ( x 2 , y 2 ) P2(x_2,y_2) P2(x2,y2)

这里图片描述

这里写图片描述

于是可以得到 P 1 P1 P1 P 2 P2 P2 的关系:

x 2 = x 1 cos ⁡ θ − y 1 sin ⁡ θ = cos ⁡ θ ( x 1 − y 1 tan ⁡ θ ) y 2 = y 1 cos ⁡ θ + x 1 sin ⁡ θ = cos ⁡ θ ( y 1 + x 1 tan ⁡ θ ) \begin{align*} x_2 &= x_1\cos\theta - y_1\sin\theta = \cos\theta(x_1 - y_1\tan\theta)\\ y_2 &= y_1\cos\theta + x_1\sin\theta = \cos\theta(y_1 + x_1\tan\theta) \end{align*} x2y2=x1cosθy1sinθ=cosθ(x1y1tanθ)=y1cosθ+x1sinθ=cosθ(y1+x1tanθ)

以上就是CORDIC的几何原理部分,而我们该如何深入理解这个几何原理的真正含义呢?

从原理中,我们可以知道,当已知一个点 P 1 P1 P1 的坐标,并已知该点 P 1 P1 P1 旋转的角度 θ \theta θ,则可以根据上述公式求得目标点 P 2 P2 P2 的坐标。然后,麻烦来了,我们需要用FPGA去执行上述运算操作,而FPGA的Verilog语言根本不支持三角函数运算。因此,我们需要对上述式子进行简化操作,将复杂的运算操作转换为一种单一的“迭代位移”算法。那么,接下来我们介绍优化算法部分。

2、CORDIC的优化算法介绍

我们先介绍算法的优化原理:将旋转角 θ \theta θ 细化成若干分固定大小的角度 θ i \theta_i θi,并且规定 θ i \theta_i θi 满足 tan ⁡ θ i = 2 − i \tan\theta_i = 2^{-i} tanθi=2i,因此 ∑ θ i \sum\theta_i θi 的值在 [ − 99. 7 ∘ , 99. 7 ∘ ] [-99.7^{\circ},99.7^{\circ}] [99.7,99.7] 范围内,如果旋转角 θ \theta θ 超出此范围,则运用简单的三角运算操作即可(加减 π \pi π)。

然后我们需要修改几何原理部分的假设,假设在 x y xy xy 坐标系中有一个点 P 0 ( x 0 , y 0 ) P0(x_0,y_0) P0(x0,y0),将 P 0 P0 P0 点绕原点旋转 θ \theta θ 角后得到点 P n ( x n , y n ) Pn(x_n,y_n) Pn(xn,yn)

于是可以得到 P 0 P0 P0 P n Pn Pn 的关系:

x n = x 0 cos ⁡ θ − y 0 sin ⁡ θ = cos ⁡ θ ( x 0 − y 0 tan ⁡ θ ) y n = y 0 cos ⁡ θ + x 0 sin ⁡ θ = cos ⁡ θ ( y 0 + x 0 tan ⁡ θ ) \begin{align*} x_n &= x_0\cos\theta - y_0\sin\theta = \cos\theta(x_0 - y_0\tan\theta)\\ y_n &= y_0\cos\theta + x_0\sin\theta = \cos\theta(y_0 + x_0\tan\theta) \end{align*} xnyn=x0cosθy0sinθ=cosθ(x0y0tanθ)=y0cosθ+x0sinθ=cosθ(y0+x0tanθ)

然后,我们将旋转角 θ \theta θ 细化成 θ i \theta_i θi,由于每次的旋转角度 θ i \theta_i θi 是固定不变的(因为满足 tan ⁡ θ i = 2 − i \tan\theta_i = 2^{-i} tanθi=2i),如果一直朝着一个方向旋转则 ∑ θ i \sum\theta_i θi 一定会超过 θ \theta θ(如果 θ \theta θ [ − 99. 7 ∘ , 99. 7 ∘ ] [-99.7^{\circ},99.7^{\circ}] [99.7,99.7] 范围内)。因此我们需要对 θ i \theta_i θi 设定一个方向值 d i d_i di。如果旋转角已经大于 θ \theta θ,则 d i d_i di − 1 -1 1,表示下次旋转为顺时针,即向 θ \theta θ 靠近;如果旋转角已经小于 θ \theta θ,则 d i d_i di 1 1 1,表示下次旋转为逆时针,即也向 θ \theta θ 靠近。然后我们可以得到每次旋转的角度值 d i θ i d_i\theta_i diθi,设角度剩余值为 z i + 1 z_{i + 1} zi+1,则有 z i + 1 = z i − d i θ i z_{i + 1} = z_i - d_i\theta_i zi+1=zidiθi,其中 z 0 z_0 z0 θ \theta θ。如此随着 i i i 的增大,角度剩余值 z i + 1 z_{i + 1} zi+1 将会趋近于 0 0 0,此时运算结束。(注:可以发现, d i d_i di z i z_i zi 的符号位相同)

第一次旋转 θ 0 \theta_0 θ0 d 0 d_0 d0 为旋转方向:

x 1 = cos ⁡ θ 0 ( x 0 − d 0 y 0 tan ⁡ θ 0 ) y 1 = cos ⁡ θ 0 ( y 0 + d 0 x 0 tan ⁡ θ 0 ) \begin{align*} x_1 &= \cos\theta_0(x_0 - d_0y_0\tan\theta_0)\\ y_1 &= \cos\theta_0(y_0 + d_0x_0\tan\theta_0) \end{align*} x1y1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值