前言
截止2022年2月15日,中国科学院大学《高等数字集成电路分析及设计》课程终于完结,所以我计划分享几个自己完成的实践作业,供大家交流学习。
设计收获
- 对cordic算法有了清晰的理解
- 初次体验了借助verilog以外语言(这里是matlab)来对设计的电路进行验证
CORDIC算法计算复数相位角题目
设计一个时序逻辑电路,对输入复数Z = X + Y*i,计算其归一化相位角P(取值范围[-1, 1))。例如:
- Z = 10 +10i, P = 0.25
- Z = -3 + 4i,P = 0.704833
- Z = 3 – 4i,P = -0.295167
- Z = -10 + 0i, P = -1
计算相角使用CORDIC算法向量模式。模块采用串行结构实现,对于每个有效输入,经过若干时钟周期能够输出1个有效数据。
顶层模块名为calc_phase,输入输出功能定义:
名称 | 方向 | 位宽 | 描述 |
---|---|---|---|
clk | I | 1 | 系统时钟 |
rst_n | I | 1 | 系统异步复位,低电平有效 |
vld_in | I | 1 | 输入数据有效指示 |
x | I | 16 | 输入实部数据,二进制补码格式 |
y | I | 16 | 输入虚部数据,二进制补码格式 |
vld_out | O | 1 | 输出数据有效指示 |
p | O | 16 | 输出相位数据,二进制补码定点格式,1位符号整数位,15位小数位,取值范围[-1, 1) |
设计要求: |
- Verilog实现代码可综合,给出综合以及仿真结果。
- 计算过程进行适当精度控制,保证输出结果精确度。
CORDIC算法计算复数相位角设计实现
架构和原理
如图所示,使用状态机控制cordic求解过程。
其中IDLE状态等待有效输入数据,依据x,y的正负确定输入复数x+iy为第几象限,并对x,y进行变换到第一、四象限后赋给x_r1和y_r1,作为cordic迭代的初始,同时设置角度累加值angle_remain初值为0;
BUSY状态使用cordic算法进行迭代求解,这里迭代了15次,其迭代式如下:
if (~y_r1[30]) begin
x_r1 <= x_r1 + (y_r1>>>counter);
y_r1 <= y_r1 - (x_r1>>>counter);
angle_remain <= angle_remain + angle[counter+1];
end
else begin
x_r1 <= x_r1 - (y_r1>>>counter);
y_r1 <= y_r1 + (x_r1>>>counter);
angle_remain <= angle_remain - angle[counter+1];
end
其中原表达式中的符号标志d,借用y_r1的正负来判断,巧妙省去了一个bit的寄存器;
DONE状态在迭代结束后,将结果输出,这里除了依据象限标记将角度累加值angle_remain修正为p_t外,还要对p_t进行截取以符合p输出为16bit的要求。初始时,将角度累加值放大了100000倍,这里截取,又将其缩小了4倍,所以得到的p的输出为真实相位角的25000倍。
仿真(iverilog)
对题目中给定的四组测试数据进行仿真得到如下波形:
可以看出四组数据得到的p值依次是:6250,17620,-7380,24999
依据架构和原理中的分析,可知其对应的相位角为0.25,0.7048,-0.2952,0.99996。可知与理论值十分接近,较好控制了求解精度。(其中0.99996与理论的1也是接近的,因为相位角是周期性的,-1与1表示同一个相位)
附录
源码获取见原文底部