CORDIC 算法理论与实践

CORDIC 算法可以在圆周,双曲坐标和线性下的用二维向量旋转后逐渐逼近的方式来计算出某个超越函数的近似值,虽然是近似值,但是如果迭代次数足够,仍然可以得到非常逼近准确结果的值。

下面分开讨论CORDIC 在圆周,双曲坐标和线性下的情况。
(1)圆周系统
先通过圆周系统来了解CORDIC 算法的基本思想。该算法的基本原理如图1

所示,现有向量V1,与X 轴夹角为Ф,逆时针旋转角度θ 后,得到新的向量
V2,

由上面的矩阵公司简化得到:

为了在硬件上实现方便,作如下约定:每一次旋转的角度θ正切值为2 的倍数,即

并且约定以δi 代表向量的旋转方向,+1 表示逆时针旋转,-1 表示顺时针旋转,故第i 步的旋转可用下式表示:

其中开根号的结果是模校正因子,对于字长一定的运算,它是一个常数,我们用K+1表示。以16bit 字长为例,

这样可将输入数据X,Y 校正后再参与运算,避免在运算中增加校正运算。运算迭代式可以简化成:

上式运算就只有加或减法和移位了。上面的公式n 次迭代可以得到:

假设给定X0=K+1;Y0=0, 则迭代结果:

所以,将所需产生的角度值作为z0 输入,迭代结果输出xn 和yn 就是需要的浮点超越函数值。采用的迭代方程组为:

CORDIC 算法在圆周系统中还可以用向量模式表达出来。向量模式将输入向量通过一个特定的角将Y 变为0。该模式下的CORDIC 公式类似于旋转模式,不同的是旋转的方向取决于Y 而不是Z 的符号。N 次迭代后CORDIC 公式变为:

从上面的推导可以看出,CORDIC 算法在圆周系统下的向量模式可以用来计算给定向量(X,Y)的长度和角。这显然就是从迪卡尔坐标到极坐标的转换。

下面给出一个CORDIC算法在圆周系统下的向量模式下获取角度的Verilog 程序:

/*==============================================================================*\
Filename : Cordic.v
Discription : 坐标旋转数字计算方法。通过该算法,对输入的向量坐标进行9次迭代
计算,得到该向量的模值和相角。

\*==============================================================================*/

module CORDIC
(
Clk_20m,
_Rst,
Cordic_start,
Ug_d,
Ug_q,
Ug,
Delta

);

input Clk_20m,
_Rst,
Cordic_start; //CORDIC变换启动标志

input[15:0] Ug_d, //输出电压的d轴分量
Ug_q; //输出电压的q轴分量
output[15:0] Ug; //输出电压向量的模值
output[13:0] Delta; //输出电压向量的相角

wire[31:0] Ug_tmp;
reg[3:0] Times; //迭代次数累加器
reg[15:0] Ug_d_tmp, //输出电压d轴分量的中间迭代结果
Ug_q_tmp; //输出电压q轴分量的中间迭代结果

reg[13:0] //Delta,
Delta_tmp; //相位角旋转累加寄存器

// assign Ug = ( Ug_d_tmp>>1 ) + ( Ug_d_tmp>>3 ) - ( Ug_d_tmp>>6 ) - ( Ug_d_tmp>>9 );

//对电压模值进行比例系数调整,得到实际模值的32倍
// assign Ug_tmp[31:0] = Ug_d_tmp[15:0] * 16'd48224;//d39797;
assign Ug_tmp[31:0] = Ug_d_tmp[15:0] * 16'd45208;
assign Ug[15:0] = Ug_tmp[31:16];

//输出电压向量的相角即为CORDIC算法输出的旋转角
assign Delta = Delta_tmp;
/*
always @( posedge Clk_20m or negedge _Rst )
begin
if ( !_Rst )
Delta <= 14'h0;
else if ( Delta_tmp <= 14'h6 )
Delta <= Delta_tmp;
else if ( Delta_tmp <= 14'h1fff )
Delta <= 14'h6;
else if ( Delta_tmp <= 14'h3ffa )
Delta <= 14'h3ffa;
else
Delta <= Delta_tmp;

else
Delta <= 14'h6;

end

*/

always @( posedge Clk_20m or negedge _Rst )
begin
if ( !_Rst )
begin
Times[3:0] <= 4'hf;
Ug_d_tmp[15:0] <= 16'h0;
Ug_q_tmp[15:0] <= 16'h0;
Delta_tmp[13:0] <= 14'h0;
end
else if ( Cordic_start ) //启动CORDIC变换
begin
Times[3:0] <= 4'h0;
Ug_d_tmp <= Ug_d;
Ug_q_tmp <= Ug_q;
Delta_tmp <= 14'h0;
end
else if ( Times <= 4'd9 ) //开始迭代计算
begin
Times[3:0] <= Times[3:0] + 4'h1; //迭代次数加1
case ( Times )
4'h0:

//Ug_q_tmp[15] 符号位
if ( Ug_q_tmp[15] ) //旋转的目标是使Ug_q_tmp趋近于0,
//根据对Ug_q_tmp符号的判断,决定正向旋转还是反向旋转
begin
Ug_d_tmp <= Ug_d_tmp - Ug_q_tmp; //重新计算新的d轴分量
Ug_q_tmp <= Ug_q_tmp + Ug_d_tmp; //重新计算新的q轴分量
Delta_tmp <= Delta_tmp - 14'hB40; //对相位角进行累加计算
end
else
begin
Ug_d_tmp <= Ug_d_tmp + Ug_q_tmp;
Ug_q_tmp <= Ug_q_tmp - Ug_d_tmp;
Delta_tmp <= Delta_tmp + 14'hB40; //(2880/64)=45
end
4'h1:
if ( Ug_q_tmp[15] )
begin
Ug_d_tmp <= Ug_d_tmp - { Ug_q_tmp[15], Ug_q_tmp[15:1] };
Ug_q_tmp <= Ug_q_tmp + { Ug_d_tmp[15], Ug_d_tmp[15:1] };
Delta_tmp <= Delta_tmp - 14'h6A4; // (1700/64)=26.5625
end
else
begin
Ug_d_tmp <= Ug_d_tmp + { Ug_q_tmp[15], Ug_q_tmp[15:1] };
Ug_q_tmp <= Ug_q_tmp - { Ug_d_tmp[15], Ug_d_tmp[15:1] };
Delta_tmp <= Delta_tmp + 14'h6A4; //
end
4'h2:
if ( Ug_q_tmp[15] )
begin
Ug_d_tmp <= Ug_d_tmp - { {2{Ug_q_tmp[15]}}, Ug_q_tmp[15:2] };
Ug_q_tmp <= Ug_q_tmp + { {2{Ug_d_tmp[15]}}, Ug_d_tmp[15:2] };
Delta_tmp <= Delta_tmp - 14'h382; // (382/64=14.03125)
end
else
begin
Ug_d_tmp <= Ug_d_tmp + { {2{Ug_q_tmp[15]}}, Ug_q_tmp[15:2] };
Ug_q_tmp <= Ug_q_tmp - { {2{Ug_d_tmp[15]}}, Ug_d_tmp[15:2] };
Delta_tmp <= Delta_tmp + 14'h382;
end
4'h3:
if ( Ug_q_tmp[15] )
begin
Ug_d_tmp <= Ug_d_tmp - { {3{Ug_q_tmp[15]}}, Ug_q_tmp[15:3] };
Ug_q_tmp <= Ug_q_tmp + { {3{Ug_d_tmp[15]}}, Ug_d_tmp[15:3] };
Delta_tmp <= Delta_tmp - 14'h1c8; // (382/64=14.03125)
end
else
begin
Ug_d_tmp <= Ug_d_tmp + { {3{Ug_q_tmp[15]}}, Ug_q_tmp[15:3] };
Ug_q_tmp <= Ug_q_tmp - { {3{Ug_d_tmp[15]}}, Ug_d_tmp[15:3] };
Delta_tmp <= Delta_tmp + 14'h1c8; // (456/64=7.125)
end
4'h4:
if ( Ug_q_tmp[15] )
begin
Ug_d_tmp <= Ug_d_tmp - { {4{Ug_q_tmp[15]}}, Ug_q_tmp[15:4] };
Ug_q_tmp <= Ug_q_tmp + { {4{Ug_d_tmp[15]}}, Ug_d_tmp[15:4] };
Delta_tmp <= Delta_tmp - 14'hE5; //(229/64=3.578125)
end
else
begin
Ug_d_tmp <= Ug_d_tmp + { {4{Ug_q_tmp[15]}}, Ug_q_tmp[15:4] };
Ug_q_tmp <= Ug_q_tmp - { {4{Ug_d_tmp[15]}}, Ug_d_tmp[15:4] };
Delta_tmp <= Delta_tmp + 14'hE5;
end
4'h5:
if ( Ug_q_tmp[15] )
begin
Ug_d_tmp <= Ug_d_tmp - { {5{Ug_q_tmp[15]}}, Ug_q_tmp[15:5] };
Ug_q_tmp <= Ug_q_tmp + { {5{Ug_d_tmp[15]}}, Ug_d_tmp[15:5] };
Delta_tmp <= Delta_tmp - 14'h72; //(114/64=1.78125)
end
else
begin
Ug_d_tmp <= Ug_d_tmp + { {5{Ug_q_tmp[15]}}, Ug_q_tmp[15:5] };
Ug_q_tmp <= Ug_q_tmp - { {5{Ug_d_tmp[15]}}, Ug_d_tmp[15:5] };
Delta_tmp <= Delta_tmp + 14'h72;
end
4'h6:
if ( Ug_q_tmp[15] )
begin
Ug_d_tmp <= Ug_d_tmp - { {6{Ug_q_tmp[15]}}, Ug_q_tmp[15:6] };
Ug_q_tmp <= Ug_q_tmp + { {6{Ug_d_tmp[15]}}, Ug_d_tmp[15:6] };
Delta_tmp <= Delta_tmp - 14'h39;//(57/64=0.890625)
end
else
begin
Ug_d_tmp <= Ug_d_tmp + { {6{Ug_q_tmp[15]}}, Ug_q_tmp[15:6] };
Ug_q_tmp <= Ug_q_tmp - { {6{Ug_d_tmp[15]}}, Ug_d_tmp[15:6] };
Delta_tmp <= Delta_tmp + 14'h39;
end
4'h7:
if ( Ug_q_tmp[15] )
begin
Ug_d_tmp <= Ug_d_tmp - { {7{Ug_q_tmp[15]}}, Ug_q_tmp[15:7] };
Ug_q_tmp <= Ug_q_tmp + { {7{Ug_d_tmp[15]}}, Ug_d_tmp[15:7] };
Delta_tmp <= Delta_tmp - 14'h1C;//(28/64=0.4375)
end
else
begin
Ug_d_tmp <= Ug_d_tmp + { {7{Ug_q_tmp[15]}}, Ug_q_tmp[15:7] };
Ug_q_tmp <= Ug_q_tmp - { {7{Ug_d_tmp[15]}}, Ug_d_tmp[15:7] };
Delta_tmp <= Delta_tmp + 14'h1C;
end
4'h8:
if ( Ug_q_tmp[15] )
begin
Ug_d_tmp <= Ug_d_tmp - { {8{Ug_q_tmp[15]}}, Ug_q_tmp[15:8] };
Ug_q_tmp <= Ug_q_tmp + { {8{Ug_d_tmp[15]}}, Ug_d_tmp[15:8] };
Delta_tmp <= Delta_tmp - 14'hE;//(14/64=0.21875)
end
else
begin
Ug_d_tmp <= Ug_d_tmp + { {8{Ug_q_tmp[15]}}, Ug_q_tmp[15:8] };
Ug_q_tmp <= Ug_q_tmp - { {8{Ug_d_tmp[15]}}, Ug_d_tmp[15:8] };
Delta_tmp <= Delta_tmp + 14'hE;
end
4'h9:
if ( Ug_q_tmp[15] )
begin
Ug_d_tmp <= Ug_d_tmp - { {9{Ug_q_tmp[15]}}, Ug_q_tmp[15:9] };
Ug_q_tmp <= Ug_q_tmp + { {9{Ug_d_tmp[15]}}, Ug_d_tmp[15:9] };
Delta_tmp <= Delta_tmp - 14'h7;
end
else
begin
Ug_d_tmp <= Ug_d_tmp + { {9{Ug_q_tmp[15]}}, Ug_q_tmp[15:9] };
Ug_q_tmp <= Ug_q_tmp - { {9{Ug_d_tmp[15]}}, Ug_d_tmp[15:9] };
Delta_tmp <= Delta_tmp + 14'h7; //(7/64=0.109375)
end
default: //缺省情况下所有寄存器清零
begin
Ug_d_tmp <= 16'h0;
Ug_q_tmp <= 16'h0;
Delta_tmp <= 14'h0;
end
// ;
endcase
end
else
Times[3:0] <= 4'hf; //迭代计算完毕,结束CORDIC算法,迭代次数置复位值

end

endmodule

时间: 2024-09-20 21:04:09

CORDIC 算法理论与实践的相关文章

[置顶]群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法【附C#群蚁算法完整项目代码】

若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样的任务,所以就好好把基础研究了一下,驱动式学习,目标明确,所以还是比较快去接受和理解,然后写代码实现就好了.今天就带领大家走近TSP问题以及群蚁算法.  机器学习目录:[目录]数据挖掘与机器学习相关算法文章总目录 本文原文地址:群蚁算法理论与实践全攻略--旅行商等路径优化问题的新方法  1.关于旅行

群蚁算法理论与实践全攻略

  若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样的任务,所以就好好把基础研究了一下,驱动式学习,目标明确,所以还是比较快去接受和理解,然后写代码实现就好了.今天就带领大家走近TSP问题以及群蚁算法. 1.关于旅行商(TSP)问题及衍化 旅行商问题(Traveling Saleman Problem,TSP)是车辆路径调度问题(VRP)的特例,

Java 理论与实践: 非阻塞算法简介

[本文转载自Java 理论与实践: 非阻塞算法简介]Java 5.0 第一次让使用 Java 语言开发非阻塞算法成为可能,java.util.concurrent 包充分地利用了这个功能.非阻塞算法属于并发算法,它们可以安全地派生它们的线程,不通过锁定派生,而是通过低级的原子性的硬件原生形式 -- 例如比较和交换.非阻塞算法的设计与实现极为困难,但是它们能够提供更好的吞吐率,对生存问题(例如死锁和优先级反转)也能提供更好的防御.在这期的 Java 理论与实践 中,并发性大师 Brian Goet

Java 理论与实践: JDK 5.0 中更灵活、更具可伸缩性的锁定机制

伸缩 内容: synchronized 快速回顾 对 synchronized 的改进 比较 ReentrantLock 和 synchronized 的可伸缩性 条件变量 这不公平 结束语 参考资料 关于作者 对本文的评价 相关内容: Java 理论与实践 系列 Synchronization is not the enemy Reducing contention IBM developer kits for the Java platform (downloads) 订阅: develop

Java理论与实践: 垃圾收集简史

Java 语言可能是使用最广泛的依赖于垃圾收集的编程语言,但是它并不是第 一个.垃圾收集已经成为了包括 Lisp.Smalltalk.Eiffel.Haskell.ML. Scheme和 Modula-3 在内的许多编程语言的一个集成部分,并且从 20 世纪 60 年代早期就开始使用了.在 Java 理论与实践的本篇文章中,Brian Goetz 描述 了垃圾收集最常用的技术. 垃圾收集的好处是无可争辩的 ―― 可靠性提高.使内存管理与类接口设计 分离,并使开发者减少了跟踪内存管理错误的时间.著

谈理论与实践

  还记得我工作后接触的第一个理论就是长尾理论,后续在培训中又学习了蓝海战略.定位理论.权衡.免费等等.可以说我学到和了解了很多的理论.由于做游戏数据分析工作,因此像SPSS.SAS.Clementine.Excel都能熟练使用,包括很多的模型算法,比如RFM.C5.0.决策树等等很多的内容都有涉及,都有研究,我也相信,时下具备这些所谓"知识"的人不占少数,讲起来滔滔不绝,可是回头来问一句:你确定你懂吗? 理论 书你真的看透了吗? 一个理论的掌握不是你读完了这本理论的书籍,就敢说你掌握

WCF从理论到实践(8):事件广播

上文讨论了WCF中三种消息交换模式,one-way,request/reply,duplex.前两项比较简单,无需多言,duplex相对比较复杂,上文只是实现了简单的回调,在真正应用的时候,还有许多值得注意之处,本文就结合一个实际的应用例子来谈论下duplex的具体应用和非常值得我们注意的地方. 本文的出发点 通过阅读本文,您能理解以下知识: 如何实现一个基于duplex的事件广播 解析在实现duplex事件广播中的几个问题 初步探讨一下异步 本文适合的读者 本文属于中等难度的文章,需要有WCF

Java 理论与实践:变还是不变?

不变对象具有许多能更方便地使用它们的特性,包括不严格的同步需求和不必考虑数据讹误就能自由地共享和高速缓存对象引用.尽管不变性可能未必对于所有类都有意义,但大多数程序中至少有一些类将受益于不可变.在本月的 Java 理论与实践中,Brian Goetz 说明了不变性的一些长处和构造不变类的一些准则.请在附带的论坛中与作者和其他读者分享您关于本文的心得.(也可以单击文章顶部或底部的"讨论"来访问论坛.) 不变对象是指在实例化后其外部可见状态无法更改的对象.Java 类库中的 String.

轻描淡写:SEO就是理论到实践的贯通

  说起SEO,始终都是另不少人头疼的话题.有人说SEO就是推广,还有人说SEO就是骗人的东西,每天拿着那点内容.外链,来吹嘘自身的能力有多高,这样的人也不在少数.但果真如此吗?反观自身网站却没有良好的排名,也难怪如此说了.笔者要说的是"SEO是理论到实践的贯通!现实中存在的理论高手太多了,但真正将之贯通运用的人才太少了,也难怪更多的人看透的仅仅是表象. 一:SEO是洞察力的贯通 搜索引擎排名没有永远的第一,有的只是优胜劣汰,符合其规则排名或飞一会,待得规则变动,排名也掉出其外.在网站优化中,只