CORDIC(Coordinate Rotation Digital Computer)算法是J.Volder在1956在航空控制系统设计中构思的,但其实相似的算法在更早的1624年就已经被Henry Briggs公布了。https://en.wikipedia.org/wiki/CORDIC
CORDIC的基本思想: 通过坐标旋转不断的迭代,去逼近一个设定的值,其核心是每次迭代旋转的角度是上一次的一半(类似于2分法),这样计算可通过加法和移位实现,适合数字电路实现。
CORDIC能实现的计算: 乘、除、平方根、正弦、余弦、反正切、复数乘法、坐标转换、指数运算等
CORDIC算法原理参考链接:
Xilinx CORDIC算法
三角函数计算,Cordic 算法入门

1. 圆周旋转,计算正余弦、复数求模、反正切

先看下边第一个图,圆周旋转其实就是对圆坐标系上的点进行旋转,从图中可以看到3个参数,坐标参数(x,y)和角度值θ\thetaθ,如果圆的半径R=1R = 1R=1,则有

x=cos⁡θx = \cos\thetax=cosθ
y=sin⁡θy = \sin\thetay=sinθ
R=x2+y2=cos⁡2θ+sin⁡2θ=1R = \sqrt{x^2 + y^2} = \sqrt{\cos^2\theta + \sin^2\theta} = 1R=x2+y2​=cos2θ+sin2θ​=1

那么如果我们知道角度为θ\thetaθ时的坐标参数(x,y)(x, y)(x,y),我们就能知道θ\thetaθ的正余弦函数值

cos⁡θ=x\cos\theta = xcosθ=x
sin⁡θ=y\sin\theta =ysinθ=y

那么怎么获得这个坐标参数呢,请看下边第二个图,我们想要计算的角度值为θ\thetaθ,其对应的坐标值为(x3,y3)(x_3, y_3)(x3​,y3​),我们通过旋转来不断的逼近这个坐标点V3V_3V3​,每次旋转的角度都是固定的,并且越来越小。如果旋转超过了V3V_3V3​,如V1V_1V1​到V2V_2V2​的旋转,则下次旋转的方向与之前相反。就这样不断的在V3V_3V3​附近摆动,因为旋转的角度不断减小,所以会越来越接近V3V_3V3​。这个在目标值附近不断摆动并接近目标值的过程就是迭代。

迭代需要注意的细节有

  • 半径R的伸缩
  • 每次迭代要旋转的固定角度

这里会涉及到几个公式如下,公式详细可参考Xilinx CORDIC算法

xi+1=xi−di(yi2−i)x_{i+1} = x_i - d_i(y_i2^{-i})xi+1​=xi​−di​(yi​2−i)
yi+1=yi+di(xi2−i)y_{i+1} = y_i + d_i(x_i2^{-i})yi+1​=yi​+di​(xi​2−i)
zi+1=zi−diθiz_{i+1} = z_i - d_i\theta_{i}zi+1​=zi​−di​θi​

iii是迭代次数,did_idi​是判断算子,用来确定旋转的方向,zzz是角度累加器。

怎么计算正余弦

计算正余弦就是要计算坐标值,此时我们已经知道了角度值zzz,计算正余弦的过程如下

  • 设定初始的坐标为(1, 0)
  • 旋转zzz个角度,即使zzz趋于0
  • 最终得到的xxx和yyy的值就是我们要的正余弦函数值

可通过下面这段MATLAB代码来理解

for i = 0:1:itime                   % itime为迭代次数if z0 > 0                        % z0生成判断算子,确定旋转方向x = x0 - y0 / 2^(i);y = y0 + x0 / 2^(i);z = z0 - atan(1/2^i);elsex = x0 + y0 / 2^(i);y = y0 - x0 / 2^(i);z = z0 + atan(1/2^i);endx0 = x;y0 = y;z0 = z;
end

怎么计算复数求模和反正切

先看我们要求的是什么

∣a+bi∣=(a)2+(b)2=((a)2+(b)2)2+(0)2|a + bi| = \sqrt{(a)^2 + (b)^2} = \sqrt{(\sqrt{(a)^2 + (b)^2})^2 + (0)^2}∣a+bi∣=(a)2+(b)2​=((a)2+(b)2​)2+(0)2​
tan−1(a)=tan−1(a1)=tan−1(yx)=θtan^{-1}(a) = tan^{-1}(\frac{a}{1}) = tan^{-1}(\frac{y}{x}) = \thetatan−1(a)=tan−1(1a​)=tan−1(xy​)=θ
其中y=ay = ay=a,x=1x = 1x=1

计算正余弦函数的过程可以看成是第二图中V0V_0V0​到V3V_3V3​的旋转,而计算复数求模和反正切就可以看成是**V3V_3V3​到V0V_0V0​的旋转**,即初始我们是知道(x3,y3)(x_3, y_3)(x3​,y3​)的,然后我们要求(x0,0)(x_0, 0)(x0​,0)的值,因为这是圆周旋转,所以这里有一个隐含条件

(x3)2+(y3)2=(x0)2+(0)2=∣x0∣\sqrt{(x_3)^2 + (y_3)^2} = \sqrt{(x_0)^2 + (0)^2} = |x_0|(x3​)2+(y3​)2​=(x0​)2+(0)2​=∣x0​∣

那么复数求模a+bia + bia+bi的过程如下

  • 设定初始值x0=a,y0=b,z0=0x_0 = a, y_0 = b, z_0 = 0x0​=a,y0​=b,z0​=0。如果只求模,zzz其实无所谓,因为求解过程不需要用到zzz
  • 使yyy趋于0
  • 迭代完成后的结果xxx就是复数的模

求反正切的过程与复数求模基本一致,因为都是V3V_3V3​到V0V_0V0​的旋转,在这个迭代过程中,zzz一直在积累角度,迭代完成后**zzz的值就是旋转的角度θ\thetaθ**。即有

θ=tan−1(ba)\theta = tan^{-1}(\frac{b}{a})θ=tan−1(ab​)

如果我们将初始值yyy设为x=a=1x = a = 1x=a=1,那么bbb的反正切函数值为

tan−1(b)=z=θtan^{-1}(b) = z = \thetatan−1(b)=z=θ

计算复数求模和反正切函数值的MATLAB代码

for i = 0:1:itime                   % itime为迭代次数,迭代的越多,越精确if y0 < 0                        % y0生成判断算子,确定旋转方向x = x0 - y0 / 2^(i);y = y0 + x0 / 2^(i);z = z0 - atan(1/2^i);elsex = x0 + y0 / 2^(i);y = y0 - x0 / 2^(i);z = z0 + atan(1/2^i);endx0 = x;y0 = y;z0 = z;
end

2. 线性旋转,乘除运算的CORDIC实现

Xilinx CORDIC算法在介绍线性旋转的时候有说到一个线性坐标系,有的讲CORDIC的书里也有提到线性坐标系旋转,但是也有的书里是没有提到的,而且在百度和谷歌里都没搜到“线性坐标系”这个名词,所以也不知道是不是对的。不过从下面这个图来理解线性旋转好像确实有点不好理解,所以就先不管了。

  • 线性旋转的迭代过程可表示为

xi+1=xix_{i+1} = x_ixi+1​=xi​
yi+1=yi+di(xi2−i)y_{i+1} = y_i + d_i(x_i2^{-i})yi+1​=yi​+di​(xi​2−i)
zi+1=zi−di(2−i)z_{i+1} = z_i - d_i(2^{-i})zi+1​=zi​−di​(2−i)

  • 选择di=sign(zi)d_i = sign(z_i)di​=sign(zi​)使得zi→0z_i → 0zi​→0。nnn次迭代后得到

xn=x0x_n = x_0xn​=x0​
yn=y0+x0z0y_n = y_0 + x_0z_0yn​=y0​+x0​z0​
zn=0z_n = 0zn​=0

如果初始y0y_0y0​设为0,那么迭代完成后就可以得到xxx与zzz的乘积

  • 选择di=−sign(xiyi)d_i = -sign(x_iy_i)di​=−sign(xi​yi​)使得yi→0y_i → 0yi​→0。nnn次迭代后得到

xn=x0x_n = x_0xn​=x0​
yn=0y_n =0yn​=0
zn=z0+y0x0z_n = z_0 + \frac{y_0}{x_0}zn​=z0​+x0​y0​​

如果初始z0z_0z0​设为0,那么迭代完成后就可以得到yyy除xxx的

其实上面的过程隐含了一个等式

y=xzy = xzy=xz

我们都知道乘法可以通过二进制的移位相加来实现,如6乘以5

5=22+205 = 2^2 + 2^05=22+20
则 6乘5 = 6左移2位 + 6
6*5 = 0b(11000) + 0b(00110) = 0b(11110) = 30

所以求乘积的过程就是x0x_0x0​不断移位相加的过程,这个过程会近似乘完所有z0z_0z0​的分解项(分解成如5=22+205 = 2^2 + 2^05=22+20的形式),每次乘积后累加,最后得到yny^nyn。
而求商的过程则与求乘积的过程恰好相反

乘法迭代的MATLAB代码

for i = -indx:15            % 注意indx                if z0 > 0                       x = x0;y = y0 + x0 / 2^(i);z = z0 - (1/2^i);elsex = x0;y = y0 - x0 / 2^(i);z = z0 + (1/2^i);endx0 = x;y0 = y;z0 = z;
end

注意2indx2^{indx}2indx必须大于z0z_0z0​的12\frac{1}{2}21​,否则迭代不会收敛,即zzz不会趋于0

除法迭代的MATLAB代码

for i = -indx:15                    if y0 < 0                       x = x0;y = y0 + x0 / 2^(i);z = z0 - (1/2^i);elsex = x0;y = y0 - x0 / 2^(i);z = z0 + (1/2^i);endx0 = x;y0 = y;z0 = z;
fprintf('x0 = %d, y0 = %d, z0 = %d\n', x0, y0, z0)
end

注意x0∗2indxx_0*2^{indx}x0​∗2indx必须大于y0y_0y0​的12\frac{1}{2}21​,否则迭代不会收敛,即yyy不会趋于0

为什么不会收敛呢
因为”一尺之棰,日取其半,万世不竭”…………
拿乘法来说,假设z0=100z_0 = 100z0​=100, indx=5indx = 5indx=5,那迭代nnn次之后有

zn=z0−(25+24+...+25−n+1)=100−26(1−2−n)=36+26−nz_n = z_0 - (2^5 + 2^4 + ... + 2^{5-n + 1}) = 100 - 2^6(1 - 2^{-n}) = 36 + 2^{6-n}zn​=z0​−(25+24+...+25−n+1)=100−26(1−2−n)=36+26−n

即不管迭代多少次,znz_nzn​是永远大于36的,所以不能收敛。

2---理解正余弦、复数求模、反正切和乘除运算的CORDIC算法实现相关推荐

  1. 基于加取模和循环左移运算的扩散算法matlab

    基于加取模和循环左移运算的扩散算法 实际上是对前面两种扩散算法的显著改良. LSB3表示取数据的最低三位,对于8b的灰度图像,每个像素都是8b的,所以LSB3得到的数据范围始终在0~7,是一个像素点数 ...

  2. python 复数求模_Python基础语法知识汇总(学习党的最爱!)

    本文章包含了Python一系列基本知识,其中包括:基本数据类型(整数,浮点数,复数,字符串):分支语句:异常处理:函数:局部变量与全局变量:递归:组合数据类型(集合,元组,列表,字典):文件基本操作. ...

  3. 复数求模运算的快速近似实现方法

    数字信号处理中,经常需要对复数进行求模运算.找了一些资料,发现对精度要求不高的情况下是有比较好的简化运算方法的.我这里整理出了如下简化步骤: 1. 对复数的实部和虚部取绝对值 2. 把绝对值大的定为M ...

  4. matlab 复数求模长,matlab计算带有复数的函数,最后求复数函数的模,结果里面却有...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 matlab计算带有复数的函数,最后求复数函数的模,结果里面却有复数标志i,输入自变量,得到的结果确实是实数,不知道怎么回事; 代码如下: syms n2 ...

  5. python中的除法,取整和求模

    本文为转载,原博客地址:https://blog.csdn.net/huzq1976/article/details/51581330 首先注明:如果没有特别说明,以下内容都是基于python 3.4 ...

  6. python中的除法、取整和求模_python中的除法,取整和求模

    首先注明:如果没有特别说明,以下内容都是基于python 3.4的. 先说核心要点: 1. /是精确除法,//是向下取整除法,%是求模 2. %求模是基于向下取整除法规则的 3. 四舍五入取整roun ...

  7. python中的除法、取整和求模_python中的除法,取整和求模-Go语言中文社区

    首先注明:如果没有特别说明,以下内容都是基于python 3.4的. 先说核心要点: 1. /是精确除法,//是向下取整除法,%是求模 2. %求模是基于向下取整除法规则的 3. 四舍五入取整roun ...

  8. Vivado cordic IP求模求角教程

    前言 当需要对复数求模的时候,用FPGA怎么求呢?怎么开根号? 方法1:先求幅值平方和,再使用cordic IP开根号.(蠢办法) 方法2:直接用cordic求取模值. 此处只介绍方法2,资源占用更少 ...

  9. HLS / Chisel 实现CORDIC算法高性能复数除法

    CORDIC(坐标旋转数字算法)是一种计算三角.双曲和其他数学函数的数字算法,每次运算均产生一次结果输出.这使我们能够根据应用需求调整算法精度:增加运算迭代次数可以得到更精确的结果.CORDIC 是只 ...

最新文章

  1. C语言写的俄罗斯方块
  2. TF之AE:AE实现TF自带数据集数字真实值对比AE先encoder后decoder预测数字的精确对比—daidingdaiding
  3. python 立体图像_OpenCV-Python 立体图像的深度图 | 五十二
  4. 使用C/C++解析json文件
  5. Avalonia跨平台入门第十四篇之ListBox折叠列表
  6. android 监听本机网络请求_fiddler如何抓取https请求实现fiddler手机抓包-证书安装失败100%解决...
  7. python gevent asyncio_python用from gevent import monkey; monkey.patch_all()之后报ssl等错误
  8. 人脸对齐(五)--ESR算法
  9. 用进化的观点学习网络协议
  10. 计算机视觉方面的三大国际会议是ICCV, CVPR和ECCV,我统称之为ICE。
  11. 数据库:码 属性 候选码 主码的关系
  12. Pandas汇总不同excel工作簿中的表格并合并同类数据
  13. 【荣耀内推】2023届荣耀校招开启啦
  14. contiki 学习资料
  15. 计算机输入法切换用户,输入法切换不出来电脑输入法不见了的最佳解决方案
  16. clickhouse集群容器化搭建
  17. 1万用户的虚拟服务器,10万用户用什么虚拟主机
  18. 从苹果ATT新政第一年,看全球数据主权之争与治理规则的变迁
  19. 时钟频率,时钟周期他们的关系是什么?
  20. java找茬_一起来找茬(1)-开发写的神奇左连接

热门文章

  1. 离散系统频响特性函数freqz()
  2. python注释快捷键alt_python快捷键的使用【摘抄】
  3. [R语言]{实例}车辆车架号VIN码校验函数
  4. 我的世界服务器整人系列,我的世界:整人还在用TNT?老玩家用这7个道具简直谁见谁怕!...
  5. vue-devtools安装教程 附各种常见错误处理(图标不显示 图标显示控制台没用Vue选项卡)
  6. 关于Visual Studio订阅(原MSDN订阅)中无法激活Office 365权益的解决方法(仅适用于MVP)
  7. 北京大学计算机所邹磊,Welcome to Lei Zou's Homepage
  8. 阿里内部信:构建“大中台、小前台”组织机制
  9. 使用git时出现fatal: Authentication failed for
  10. 人工神经网络的训练步骤,人工神经网络建模步骤