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

运行方式与通过条件

  1. 使用支持SystemVerilog的仿真器(如Vivado XSim、ModelSim、Verilator)编译两个文件:cordic_vectoring.v 与 tb_cordic_vectoring.v。
  2. 运行仿真,观察终端输出。
  3. 通过条件:打印 ALL TESTS PASSED,且每个测试用例的模长误差与角度误差均小于0.01(弧度)。

关键说明

  • 输入向量不可为零向量,否则角度无定义;本模块不处理该边界。
  • 角度输出单位为弧度(Q1.14定点),如需角度制可自行乘以 \(180/\pi\)。
  • 迭代次数16级对应角度精度约0.005°,模长精度约0.01%。
  • 若输入超出 \([-2.0, 2.0)\) 范围,内部移位可能溢出,需扩展位宽或预处理缩放。