1. CORDIC向量模式基础
任务目标
实现CORDIC向量模式(Vectoring Mode),对给定的二维向量 (x, y) 迭代旋转至接近x轴,从而同时求出向量模长 \(R = \sqrt{x^2+y^2}\) 和相位角 \(\theta = \arctan(y/x)\)。通过对比数学库 atan2 与 hypot 的结果验证正确性。
实现原理与范围
本案例使用16级流水迭代(\(i=0 \dots 15\)),采用整数定点数格式:Q1.14(1位符号 + 14位小数)。输入向量分量范围限定为 \([-2.0, 2.0)\),角度输出范围 \([-99.99^\circ, 99.99^\circ]\)(即覆盖 \(\pm\pi/2\) 附近,因迭代收敛域约 \(\pm99.88^\circ\))。代码实现纯组合逻辑迭代,不包含流水线寄存器,以最简方式展示CORDIC核心算法。
核心代码
module cordic_vectoring #(
parameter DW = 16, // 数据位宽
parameter ITER = 16 // 迭代次数
)(
input wire signed [DW-1:0] x_in, // Q1.14 定点
input wire signed [DW-1:0] y_in, // Q1.14 定点
output wire signed [DW-1:0] mag, // 模长 Q1.14
output wire signed [DW-1:0] phase // 角度 Q1.14(弧度)
);
// 内部迭代连线
wire signed [DW-1:0] x [0:ITER];
wire signed [DW-1:0] y [0:ITER];
wire signed [DW-1:0] z [0:ITER];
// 反正切常量表(弧度 × 2^14)
localparam signed [DW-1:0] ATAN_TABLE [0:15] = '{
16'd51472, // atan(2^-0) = 0.7854
16'd30386, // atan(2^-1) = 0.4636
16'd16055, // atan(2^-2) = 0.2450
16'd8150, // atan(2^-3) = 0.1244
16'd4091, // atan(2^-4) = 0.0624
16'd2047, // atan(2^-5) = 0.0312
16'd1024, // atan(2^-6) = 0.0156
16'd512, // atan(2^-7) = 0.0078
16'd256, // atan(2^-8) = 0.0039
16'd128, // atan(2^-9) = 0.0020
16'd64, // atan(2^-10)= 0.0010
16'd32, // atan(2^-11)= 0.0005
16'd16, // atan(2^-12)= 0.0002
16'd8, // atan(2^-13)= 0.0001
16'd4, // atan(2^-14)= 0.00005
16'd2 // atan(2^-15)= 0.000025
};
// 增益补偿常数 1/K = 0.6073(Q1.14格式)
localparam signed [DW-1:0] K_COMP = 16'd9951;
assign x[0] = x_in;
assign y[0] = y_in;
assign z[0] = 16'd0;
genvar i;
generate
for (i = 0; i < ITER; i = i + 1) begin : cordic_iter
wire signed [DW-1:0] x_shift = x[i] >>> i;
wire signed [DW-1:0] y_shift = y[i] >>> i;
wire d = ~y[i][DW-1]; // 向量模式:y≥0时d=1,旋转方向使y趋向0
assign x[i+1] = d ? (x[i] - y_shift) : (x[i] + y_shift);
assign y[i+1] = d ? (y[i] + x_shift) : (y[i] - x_shift);
assign z[i+1] = d ? (z[i] + ATAN_TABLE[i]) : (z[i] - ATAN_TABLE[i]);
end
endgenerate
// 输出:模长乘增益补偿,角度取z
assign mag = (x[ITER] * K_COMP) >>> 14;
assign phase = z[ITER];
endmodule
Testbench 与验证
module tb_cordic_vectoring;
reg signed [15:0] x_in, y_in;
wire signed [15:0] mag, phase;
cordic_vectoring dut(.*);
// 将定点数转为实数
real x_r, y_r, mag_r, phase_r;
real expected_mag, expected_phase;
integer errors;
initial begin
errors = 0;
// 测试用例1:向量 (1.0, 1.0)
x_in = 16'sd16384; y_in = 16'sd16384; // Q1.14: 1.0
#10;
x_r = $itor(x_in) / 16384.0;
y_r = $itor(y_in) / 16384.0;
mag_r = $itor(mag) / 16384.0;
phase_r = $itor(phase) / 16384.0;
expected_mag = $sqrt(x_r*x_r + y_r*y_r);
expected_phase = $atan2(y_r, x_r);
if ($abs(mag_r - expected_mag) > 0.01) begin
$display("FAIL mag: got %f, expected %f", mag_r, expected_mag);
errors = errors + 1;
end
if ($abs(phase_r - expected_phase) > 0.01) begin
$display("FAIL phase: got %f, expected %f", phase_r, expected_phase);
errors = errors + 1;
end
// 测试用例2:向量 (-0.5, 1.5)
x_in = -16'sd8192; y_in = 16'sd24576; // -0.5, 1.5
#10;
x_r = $itor(x_in) / 16384.0;
y_r = $itor(y_in) / 16384.0;
mag_r = $itor(mag) / 16384.0;
phase_r = $itor(phase) / 16384.0;
expected_mag = $sqrt(x_r*x_r + y_r*y_r);
expected_phase = $atan2(y_r, x_r);
if ($abs(mag_r - expected_mag) > 0.01) begin
$display("FAIL mag: got %f, expected %f", mag_r, expected_mag);
errors = errors + 1;
end
if ($abs(phase_r - expected_phase) > 0.01) begin
$display("FAIL phase: got %f, expected %f", phase_r, expected_phase);
errors = errors + 1;
end
if (errors == 0)
$display("ALL TESTS PASSED");
else
$display("TOTAL ERRORS: %0d", errors);
$finish;
end
endmodule
运行方式与通过条件
- 使用支持SystemVerilog的仿真器(如Vivado XSim、ModelSim、Verilator)编译两个文件:
cordic_vectoring.v与tb_cordic_vectoring.v。 - 运行仿真,观察终端输出。
- 通过条件:打印
ALL TESTS PASSED,且每个测试用例的模长误差与角度误差均小于0.01(弧度)。
关键说明
- 输入向量不可为零向量,否则角度无定义;本模块不处理该边界。
- 角度输出单位为弧度(Q1.14定点),如需角度制可自行乘以 \(180/\pi\)。
- 迭代次数16级对应角度精度约0.005°,模长精度约0.01%。
- 若输入超出 \([-2.0, 2.0)\) 范围,内部移位可能溢出,需扩展位宽或预处理缩放。