使用帥氣的cordic算法進行坐標系互轉及log10的求解


參考博客

 https://blog.csdn.net/u010712012/article/details/77755567

https://blog.csdn.net/Reborn_Lee/article/details/87436090

參考論文

 基於FPGA的自然對數變換器的設計與實現.pdf

前言

 眾所周知,verilog並不能直接計算cos sin,但信號處理中卻可能用到cos sin等函數的求解問題。

一種足夠好的逼近方式為cordic。無需使用乘法操作,只是簡單的加減移位操作即可,這就可以很好的使用verilog操作啦。

cordic算法有旋轉模式和向量模式兩種,分別可在圓坐標系、線性坐標系、雙曲坐標系中使用。

在旋轉模式中,通過使Z逼近0,得到x,y。

在向量模式中,通過使y逼近0,得到x,z。

線性坐標系暫時沒有用到。

通過給定不同的初值,則可以求解不同的函數。

 

極坐標轉直角坐標

已知(z,r),z表示角度,r表示極徑。則可以通過旋轉模式求解cos,sin。再乘r則得到實際上的直角坐標系(x,y)。

算法流程:本次迭代次數為16次,其他次數照着迭代公式寫即可,為方便fpga內部計算,數值均放大成整數,角度均放大了2^16次,則計算出來的最終結果也應相應除以2^16次。

 1、 設置迭代次數為16,則x0 = 0.607253,y0 = 0,並輸入待計算的角度θ,θ在[-99.7°,99.7°]范圍內。 
2、 根據三個迭代公式進行迭代,i從0至15: 
xi+1 = xi – d iy i2-i 
yi+1 = yi + d ix i2-i 
zi+1 = zi - diθi 
注:z0 = θ,di與zi同符號。 
3、 經過16次迭代計算后,得到的x16 和y16分別為cosθ和sinθ。

計算出的cos和sin再乘r即可得到相應的直角坐標系點(x,y)。

算法的本質即從45度開始旋轉,直到z逼近0。而算法中的K本質上是個定值跟迭代次數有關,即∏cosθi。當迭代16次時,其值為

0.6072529351。

 以下采用流水線對算法進行實現,可以獲得最大的吞吐率。如果想節約資源,自然可以用復用串行迭代。

原始cordic可以處理的角度范圍為[-99.7°,99.7°],要想放大輸入角度范圍覆蓋[-pi,pi],則需要前處理和后處理,使得角度處於第1和第4象限。

仿真結果如下所示:

角度輸入為33度,則結果為:cos:54959/2^16=0.838607788085938 ,sin:35697/2^16= 0.544692993164063

而matlab結果為:cos: 0.838670567945424 , sin: 0.544639035015027

可以看到誤差極小。

代碼僅供參考,勿做商業用途。

`timescale 1ns/1ps
module cos_sin_cordic (
    input                        i_clk       ,
    input                        i_en        ,
    input    signed    [31:0]    i_angle     ,
    output                       o_en        ,
    output                       o_error     ,
    output             [31:0]    o_cos_x     ,
    output             [31:0]    o_sin_y           
);
////parameter
parameter p_angle_0  = 2949120, //45°放大2^16
          p_angle_1  = 1740967,
          p_angle_2  = 919879,
          p_angle_3  = 466945,
          p_angle_4  = 234379,
          p_angle_5  = 117304,
          p_angle_6  = 58666,
          p_angle_7  = 29335,
          p_angle_8  = 14668,
          p_angle_9  = 7334,
          p_angle_10 = 3667,
          p_angle_11 = 1833,
          p_angle_12 = 917,
          p_angle_13 = 458,
          p_angle_14 = 229,
          p_angle_15 = 115;
parameter p_x_initial  = 39797; //0.6072529351放大了2^16次
parameter p_angle_p90  = 32'sd5898240, //90度放大2^16次
          p_angle_n90  = -32'sd5898240, //-90度
          p_angle_p180 = 32'sd11796480, //180
          p_angle_n180 = -32'sd11796480, //-180
          p_angle_p0    = 32'sd0;
//角度象限判定 角度范圍為[-pi,pi]
////象限標識
//00: 第4象限
//01:第1象限
//10:第2象限
//11:第3象限
reg [31:0] r_angle = 32'd0;
reg [1:0] r_quadrant_flag = 2'b00;
reg r_error = 1'b0; //角度范圍輸入錯誤
always @(posedge i_clk)
begin
    if ((i_angle < p_angle_n180) || (i_angle > p_angle_p180)) //越界報錯
        r_error <= 1'b1;
    else 
        r_error <= 1'b0;
end 
always @(posedge i_clk) //角度象限判定
begin
    if ((i_angle >= p_angle_p0) && (i_angle <= p_angle_p90)) //第1象限
    begin 
        r_angle <= i_angle;
        r_quadrant_flag <= 2'b01;
    end
    else if (i_angle > p_angle_p90) //第2象限
    begin
        r_angle <= i_angle - p_angle_p90;
        r_quadrant_flag <= 2'b10;
    end
    else if ((i_angle < p_angle_p0) && (i_angle >= p_angle_n90)) //第4象限
    begin
        r_angle <= i_angle;
        r_quadrant_flag <= 2'b00;        
    end
    else //第3象限
    begin
        r_angle <= i_angle - p_angle_n90;
        r_quadrant_flag <= 2'b11;
    end
end

//賦初始值
reg [31:0] r_x_0 = 32'd0;
reg [31:0] r_y_0 = 32'd0;
reg [31:0] r_angle_remain_0 = 32'd0;
always @(posedge i_clk)
begin
    r_x_0 <= p_x_initial;
    r_y_0 <= 32'd0;
    r_angle_remain_0 <= r_angle;
end
//第1次旋轉
reg [31:0] r_x_1 = 32'd0;
reg [31:0] r_y_1 = 32'd0;
reg [31:0] r_angle_remain_1 = 32'd0;
always @(posedge i_clk)
begin
    if (r_angle_remain_0[31]) //負數
    begin
        r_x_1 <= r_x_0 + r_y_0;
        r_y_1 <= r_y_0 - r_x_0;
        r_angle_remain_1 <= r_angle_remain_0 + p_angle_0;
    end
    else //角度為正
    begin
        r_x_1 <= r_x_0 - r_y_0;
        r_y_1 <= r_y_0 + r_x_0;
        r_angle_remain_1 <= r_angle_remain_0 - p_angle_0;
    end
end
//第2次旋轉
reg [31:0] r_x_2 = 32'd0;
reg [31:0] r_y_2 = 32'd0;
reg [31:0] r_angle_remain_2 = 32'd0;
always @(posedge i_clk)
begin
    if (r_angle_remain_1[31]) //負數
    begin
        r_x_2 <= r_x_1 + {{1{r_y_1[31]}},r_y_1[31:1]};
        r_y_2 <= r_y_1 - {{1{r_x_1[31]}},r_x_1[31:1]};
        r_angle_remain_2 <= r_angle_remain_1 + p_angle_1;
    end
    else //角度為正
    begin
        r_x_2 <= r_x_1 - {{1{r_y_1[31]}},r_y_1[31:1]};
        r_y_2 <= r_y_1 + {{1{r_x_1[31]}},r_x_1[31:1]};
        r_angle_remain_2 <= r_angle_remain_1 - p_angle_1;
    end
end
//第3次旋轉
reg [31:0] r_x_3 = 32'd0;
reg [31:0] r_y_3 = 32'd0;
reg [31:0] r_angle_remain_3 = 32'd0;
always @(posedge i_clk)
begin
    if (r_angle_remain_2[31]) //負數
    begin
        r_x_3 <= r_x_2 + {{2{r_y_2[31]}},r_y_2[31:2]};
        r_y_3 <= r_y_2 - {{2{r_x_2[31]}},r_x_2[31:2]};
        r_angle_remain_3 <= r_angle_remain_2 + p_angle_2;
    end
    else //角度為正
    begin
        r_x_3 <= r_x_2 - {{2{r_y_2[31]}},r_y_2[31:2]};
        r_y_3 <= r_y_2 + {{2{r_x_2[31]}},r_x_2[31:2]};
        r_angle_remain_3 <= r_angle_remain_2 - p_angle_2;
    end
end
//第4次旋轉
reg [31:0] r_x_4 = 32'd0;
reg [31:0] r_y_4 = 32'd0;
reg [31:0] r_angle_remain_4 = 32'd0;
always @(posedge i_clk)
begin
    if (r_angle_remain_3[31]) //負數
    begin
        r_x_4 <= r_x_3 + {{3{r_y_3[31]}},r_y_3[31:3]};
        r_y_4 <= r_y_3 - {{3{r_x_3[31]}},r_x_3[31:3]};
        r_angle_remain_4 <= r_angle_remain_3 + p_angle_3;
    end
    else //角度為正
    begin
        r_x_4 <= r_x_3 - {{3{r_y_3[31]}},r_y_3[31:3]};
        r_y_4 <= r_y_3 + {{3{r_x_3[31]}},r_x_3[31:3]};
        r_angle_remain_4 <= r_angle_remain_3 - p_angle_3;
    end
end
//第5次旋轉
reg [31:0] r_x_5 = 32'd0;
reg [31:0] r_y_5 = 32'd0;
reg [31:0] r_angle_remain_5 = 32'd0;
always @(posedge i_clk)
begin
    if (r_angle_remain_4[31]) //負數
    begin
        r_x_5 <= r_x_4 + {{4{r_y_4[31]}},r_y_4[31:4]};
        r_y_5 <= r_y_4 - {{4{r_x_4[31]}},r_x_4[31:4]};
        r_angle_remain_5 <= r_angle_remain_4 + p_angle_4;
    end
    else //角度為正
    begin
        r_x_5 <= r_x_4 - {{4{r_y_4[31]}},r_y_4[31:4]};
        r_y_5 <= r_y_4 + {{4{r_x_4[31]}},r_x_4[31:4]};
        r_angle_remain_5 <= r_angle_remain_4 - p_angle_4;
    end
end
//第6次旋轉
reg [31:0] r_x_6 = 32'd0;
reg [31:0] r_y_6 = 32'd0;
reg [31:0] r_angle_remain_6 = 32'd0;
always @(posedge i_clk)
begin
    if (r_angle_remain_5[31]) //負數
    begin
        r_x_6 <= r_x_5 + {{5{r_y_5[31]}},r_y_5[31:5]};
        r_y_6 <= r_y_5 - {{5{r_x_5[31]}},r_x_5[31:5]};
        r_angle_remain_6 <= r_angle_remain_5 + p_angle_5;
    end
    else //角度為正
    begin
        r_x_6 <= r_x_5 - {{5{r_y_5[31]}},r_y_5[31:5]};
        r_y_6 <= r_y_5 + {{5{r_x_5[31]}},r_x_5[31:5]};
        r_angle_remain_6 <= r_angle_remain_5 - p_angle_5;
    end
end
//第7次旋轉
reg [31:0] r_x_7 = 32'd0;
reg [31:0] r_y_7 = 32'd0;
reg [31:0] r_angle_remain_7 = 32'd0;
always @(posedge i_clk)
begin
    if (r_angle_remain_6[31]) //負數
    begin
        r_x_7 <= r_x_6 + {{6{r_y_6[31]}},r_y_6[31:6]};
        r_y_7 <= r_y_6 - {{6{r_x_6[31]}},r_x_6[31:6]};
        r_angle_remain_7 <= r_angle_remain_6 + p_angle_6;
    end
    else //角度為正
    begin
        r_x_7 <= r_x_6 - {{6{r_y_6[31]}},r_y_6[31:6]};
        r_y_7 <= r_y_6 + {{6{r_x_6[31]}},r_x_6[31:6]};
        r_angle_remain_7 <= r_angle_remain_6 - p_angle_6;
    end
end
//第8次旋轉
reg [31:0] r_x_8 = 32'd0;
reg [31:0] r_y_8 = 32'd0;
reg [31:0] r_angle_remain_8 = 32'd0;
always @(posedge i_clk)
begin
    if (r_angle_remain_7[31]) //負數
    begin
        r_x_8 <= r_x_7 + {{7{r_y_7[31]}},r_y_7[31:7]};
        r_y_8 <= r_y_7 - {{7{r_x_7[31]}},r_x_7[31:7]};
        r_angle_remain_8 <= r_angle_remain_7 + p_angle_7;
    end
    else //角度為正
    begin
        r_x_8 <= r_x_7 - {{7{r_y_7[31]}},r_y_7[31:7]};
        r_y_8 <= r_y_7 + {{7{r_x_7[31]}},r_x_7[31:7]};
        r_angle_remain_8 <= r_angle_remain_7 - p_angle_7;
    end
end
//第9次旋轉
reg [31:0] r_x_9 = 32'd0;
reg [31:0] r_y_9 = 32'd0;
reg [31:0] r_angle_remain_9 = 32'd0;
always @(posedge i_clk)
begin
    if (r_angle_remain_8[31]) //負數
    begin
        r_x_9 <= r_x_8 + {{8{r_y_8[31]}},r_y_8[31:8]};
        r_y_9 <= r_y_8 - {{8{r_x_8[31]}},r_x_8[31:8]};
        r_angle_remain_9 <= r_angle_remain_8 + p_angle_8;
    end
    else //角度為正
    begin
        r_x_9 <= r_x_8 - {{8{r_y_8[31]}},r_y_8[31:8]};
        r_y_9 <= r_y_8 + {{8{r_x_8[31]}},r_x_8[31:8]};
        r_angle_remain_9 <= r_angle_remain_8 - p_angle_8;
    end
end
//第10次旋轉
reg [31:0] r_x_10 = 32'd0;
reg [31:0] r_y_10 = 32'd0;
reg [31:0] r_angle_remain_10 = 32'd0;
always @(posedge i_clk)
begin
    if (r_angle_remain_9[31]) //負數
    begin
        r_x_10 <= r_x_9 + {{9{r_y_9[31]}},r_y_9[31:9]};
        r_y_10 <= r_y_9 - {{9{r_x_9[31]}},r_x_9[31:9]};
        r_angle_remain_10 <= r_angle_remain_9 + p_angle_9;
    end
    else //角度為正
    begin
        r_x_10 <= r_x_9 - {{9{r_y_9[31]}},r_y_9[31:9]};
        r_y_10 <= r_y_9 + {{9{r_x_9[31]}},r_x_9[31:9]};
        r_angle_remain_10 <= r_angle_remain_9 - p_angle_9;
    end
end
//第11次旋轉
reg [31:0] r_x_11 = 32'd0;
reg [31:0] r_y_11 = 32'd0;
reg [31:0] r_angle_remain_11 = 32'd0;
always @(posedge i_clk)
begin
    if (r_angle_remain_10[31]) //負數
    begin
        r_x_11 <= r_x_10 + {{10{r_y_10[31]}},r_y_10[31:10]};
        r_y_11 <= r_y_10 - {{10{r_x_10[31]}},r_x_10[31:10]};
        r_angle_remain_11 <= r_angle_remain_10 + p_angle_10;
    end
    else //角度為正
    begin
        r_x_11 <= r_x_10 - {{10{r_y_10[31]}},r_y_10[31:10]};
        r_y_11 <= r_y_10 + {{10{r_x_10[31]}},r_x_10[31:10]};
        r_angle_remain_11 <= r_angle_remain_10 - p_angle_10;
    end
end
//第12次旋轉
reg [31:0] r_x_12 = 32'd0;
reg [31:0] r_y_12 = 32'd0;
reg [31:0] r_angle_remain_12 = 32'd0;
always @(posedge i_clk)
begin
    if (r_angle_remain_11[31]) //負數
    begin
        r_x_12 <= r_x_11 + {{11{r_y_11[31]}},r_y_11[31:11]};
        r_y_12 <= r_y_11 - {{11{r_x_11[31]}},r_x_11[31:11]};
        r_angle_remain_12 <= r_angle_remain_11 + p_angle_11;
    end
    else //角度為正
    begin
        r_x_12 <= r_x_11 - {{11{r_y_11[31]}},r_y_11[31:11]};
        r_y_12 <= r_y_11 + {{11{r_x_11[31]}},r_x_11[31:11]};
        r_angle_remain_12 <= r_angle_remain_11 - p_angle_11;
    end
end
//第13次旋轉
reg [31:0] r_x_13 = 32'd0;
reg [31:0] r_y_13 = 32'd0;
reg [31:0] r_angle_remain_13 = 32'd0;
always @(posedge i_clk)
begin
    if (r_angle_remain_12[31]) //負數
    begin
        r_x_13 <= r_x_12 + {{12{r_y_12[31]}},r_y_12[31:12]};
        r_y_13 <= r_y_12 - {{12{r_x_12[31]}},r_x_12[31:12]};
        r_angle_remain_13 <= r_angle_remain_12 + p_angle_12;
    end
    else //角度為正
    begin
        r_x_13 <= r_x_12 - {{12{r_y_12[31]}},r_y_12[31:12]};
        r_y_13 <= r_y_12 + {{12{r_x_12[31]}},r_x_12[31:12]};
        r_angle_remain_13 <= r_angle_remain_12 - p_angle_12;
    end
end
//第14次旋轉
reg [31:0] r_x_14 = 32'd0;
reg [31:0] r_y_14 = 32'd0;
reg [31:0] r_angle_remain_14 = 32'd0;
always @(posedge i_clk)
begin
    if (r_angle_remain_13[31]) //負數
    begin
        r_x_14 <= r_x_13 + {{13{r_y_13[31]}},r_y_13[31:13]};
        r_y_14 <= r_y_13 - {{13{r_x_13[31]}},r_x_13[31:13]};
        r_angle_remain_14 <= r_angle_remain_13 + p_angle_13;
    end
    else //角度為正
    begin
        r_x_14 <= r_x_13 - {{13{r_y_13[31]}},r_y_13[31:13]};
        r_y_14 <= r_y_13 + {{13{r_x_13[31]}},r_x_13[31:13]};
        r_angle_remain_14 <= r_angle_remain_13 - p_angle_13;
    end
end
//第15次旋轉
reg [31:0] r_x_15 = 32'd0;
reg [31:0] r_y_15 = 32'd0;
reg [31:0] r_angle_remain_15 = 32'd0;
always @(posedge i_clk)
begin
    if (r_angle_remain_14[31]) //負數
    begin
        r_x_15 <= r_x_14 + {{14{r_y_14[31]}},r_y_14[31:14]};
        r_y_15 <= r_y_14 - {{14{r_x_14[31]}},r_x_14[31:14]};
        r_angle_remain_15 <= r_angle_remain_14 + p_angle_14;
    end
    else //角度為正
    begin
        r_x_15 <= r_x_14 - {{14{r_y_14[31]}},r_y_14[31:14]};
        r_y_15 <= r_y_14 + {{14{r_x_14[31]}},r_x_14[31:14]};
        r_angle_remain_15 <= r_angle_remain_14 - p_angle_14;
    end
end
//第16次旋轉
reg [31:0] r_x_16 = 32'd0;
reg [31:0] r_y_16 = 32'd0;
reg [31:0] r_angle_remain_16 = 32'd0;
always @(posedge i_clk)
begin
    if (r_angle_remain_15[31]) //負數
    begin
        r_x_16 <= r_x_15 + {{15{r_y_15[31]}},r_y_15[31:15]};
        r_y_16 <= r_y_15 - {{15{r_x_15[31]}},r_x_15[31:15]};
        r_angle_remain_16 <= r_angle_remain_15 + p_angle_15;
    end
    else //角度為正
    begin
        r_x_16 <= r_x_15 - {{15{r_y_15[31]}},r_y_15[31:15]};
        r_y_16 <= r_y_15 + {{15{r_x_15[31]}},r_x_15[31:15]};
        r_angle_remain_16 <= r_angle_remain_15 - p_angle_15;
    end
end
//計算結果轉化為真實結果
//flag延遲16+1+1
reg [31:0] r_cos_x;
reg [31:0] r_sin_y;
reg [16:0] r_quadrant_flag_delay_0 = 17'd0;
reg [16:0] r_quadrant_flag_delay_1 = 17'd0;
always @(posedge i_clk)
begin
    r_quadrant_flag_delay_0 <= {r_quadrant_flag_delay_0[15:0],r_quadrant_flag[0]};
    r_quadrant_flag_delay_1 <= {r_quadrant_flag_delay_1[15:0],r_quadrant_flag[1]};
end
wire [1:0] demo;
assign demo = {r_quadrant_flag_delay_1[16],r_quadrant_flag_delay_0[16]};
always @(posedge i_clk)
begin
    case ({r_quadrant_flag_delay_1[16],r_quadrant_flag_delay_0[16]})
        2'b01: //第1象限
        begin
            r_cos_x <= r_x_16;
            r_sin_y <= r_y_16;
        end 
        2'b10: //第2象限
        begin
            r_cos_x <= ~r_y_16 + 1'b1;
            r_sin_y <= r_x_16;
        end
        2'b11: //第3象限
        begin
            r_cos_x <= r_y_16;
            r_sin_y <= ~r_x_16 + 1'b1;
        end
        2'b00: //第4象限
        begin
            r_cos_x <= r_x_16;
            r_sin_y <= r_y_16;
        end
    endcase 
end

////使能延遲對齊輸出,延遲1+1+16+1
reg [18:0] r_en_delay = 19'd0;
always @(posedge i_clk)
begin
    r_en_delay <= {r_en_delay[17:0],i_en};
end
reg [17:0] r_error_delay = 18'd0;
always @(posedge i_clk)
begin
    r_error_delay <= {r_error_delay[16:0],r_error};
end
//信號輸出
assign o_cos_x = r_cos_x;
assign o_sin_y = r_sin_y;
assign o_error = r_error_delay[17];
assign o_en = r_en_delay[18];

endmodule // end the cos_sin_cordic model;

 

直角坐標轉極坐標

 已知(x,y)求解(z,r),

算法流程:

設置迭代次數為16,則x0 = x,y0 = y,z0 = 0,di與yi的符號相反。表示,經過n次旋轉,使Pn靠近x軸。 
因此,當迭代結束之后,Pn將近似接近x軸,此時yn = 0,可知旋轉了θ,即zn = θ = arctan(y/x)。r= xn * ∏cosθi。即r=xn*K。而16次迭代下的K值為0.6072529351。

迭代公式如下:

xi+1 = xi – d iy i2-i 
yi+1 = yi + d ix i2-i 
zi+1 = zi - diθi 

仿真結果如下所示。

x和y均為10000。

θ = 2949406/2^16 = 45.0044;R = 23291*K=23291* 0.6072529351= 14143.5281114141,跟matlab結果比較:14142.135623731

誤差較小。

代碼如下,勿做商業用途。

`timescale 1ns/1ps
module z_r_cordic (
    input               i_clk            ,
    input               i_en             ,
    input     [31:0]    i_x              ,
    input     [31:0]    i_y              ,
    output              o_en             ,
    output    [31:0]    o_angle          ,
    output    [31:0]    o_r           
);
////parameter
parameter p_angle_0  = 2949120, //45°放大2^16
          p_angle_1  = 1740967,
          p_angle_2  = 919879,
          p_angle_3  = 466945,
          p_angle_4  = 234379,
          p_angle_5  = 117304,
          p_angle_6  = 58666,
          p_angle_7  = 29335,
          p_angle_8  = 14668,
          p_angle_9  = 7334,
          p_angle_10 = 3667,
          p_angle_11 = 1833,
          p_angle_12 = 917,
          p_angle_13 = 458,
          p_angle_14 = 229,
          p_angle_15 = 115;

//賦初始值
reg [31:0] r_x_0 = 32'd0;
reg [31:0] r_y_0 = 32'd0;
reg [31:0] r_angle_remain_0 = 32'd0;
always @(posedge i_clk)
begin
    r_x_0 <= i_x;
    r_y_0 <= i_y;
    r_angle_remain_0 <= 32'd0;
end
//第1次旋轉
reg [31:0] r_x_1 = 32'd0;
reg [31:0] r_y_1 = 32'd0;
reg [31:0] r_angle_remain_1 = 32'd0;
always @(posedge i_clk)
begin
    if (r_y_0[31]) //負數
    begin
        r_x_1 <= r_x_0 - r_y_0;
        r_y_1 <= r_y_0 + r_x_0;
        r_angle_remain_1 <= r_angle_remain_0 - p_angle_0;
    end
    else //角度為正
    begin
        r_x_1 <= r_x_0 + r_y_0;
        r_y_1 <= r_y_0 - r_x_0;
        r_angle_remain_1 <= r_angle_remain_0 + p_angle_0;
    end
end
//第2次旋轉
reg  [31:0] r_x_2 = 32'd0;
reg  [31:0] r_y_2 = 32'd0;
reg  [31:0] r_angle_remain_2 = 32'd0;
always @(posedge i_clk)
begin
    if (r_y_1[31]) //負數
    begin
        r_x_2 <= r_x_1 - {{1{r_y_1[31]}},r_y_1[31:1]};
        r_y_2 <= r_y_1 + {{1{r_x_1[31]}},r_x_1[31:1]};
        r_angle_remain_2 <= r_angle_remain_1 - p_angle_1;
    end
    else //角度為正
    begin
        r_x_2 <= r_x_1 + {{1{r_y_1[31]}},r_y_1[31:1]};
        r_y_2 <= r_y_1 - {{1{r_x_1[31]}},r_x_1[31:1]};
        r_angle_remain_2 <= r_angle_remain_1 + p_angle_1;
    end
end
//第3次旋轉
reg [31:0] r_x_3 = 32'd0;
reg [31:0] r_y_3 = 32'd0;
reg [31:0] r_angle_remain_3 = 32'd0;
always @(posedge i_clk)
begin
    if (r_y_2[31]) //負數
    begin
        r_x_3 <= r_x_2 - {{2{r_y_2[31]}},r_y_2[31:2]};
        r_y_3 <= r_y_2 + {{2{r_x_2[31]}},r_x_2[31:2]};
        r_angle_remain_3 <= r_angle_remain_2 - p_angle_2;
    end
    else //角度為正
    begin
        r_x_3 <= r_x_2 + {{2{r_y_2[31]}},r_y_2[31:2]};
        r_y_3 <= r_y_2 - {{2{r_x_2[31]}},r_x_2[31:2]};
        r_angle_remain_3 <= r_angle_remain_2 + p_angle_2;
    end
end
//第4次旋轉
reg [31:0] r_x_4 = 32'd0;
reg [31:0] r_y_4 = 32'd0;
reg [31:0] r_angle_remain_4 = 32'd0;
always @(posedge i_clk)
begin
    if (r_y_3[31]) //負數
    begin
        r_x_4 <= r_x_3 - {{3{r_y_3[31]}},r_y_3[31:3]};
        r_y_4 <= r_y_3 + {{3{r_x_3[31]}},r_x_3[31:3]};
        r_angle_remain_4 <= r_angle_remain_3 - p_angle_3;
    end
    else //角度為正
    begin
        r_x_4 <= r_x_3 + {{3{r_y_3[31]}},r_y_3[31:3]};
        r_y_4 <= r_y_3 - {{3{r_x_3[31]}},r_x_3[31:3]};
        r_angle_remain_4 <= r_angle_remain_3 + p_angle_3;
    end
end
//第5次旋轉
reg [31:0] r_x_5 = 32'd0;
reg [31:0] r_y_5 = 32'd0;
reg [31:0] r_angle_remain_5 = 32'd0;
always @(posedge i_clk)
begin
    if (r_y_4[31]) //負數
    begin
        r_x_5 <= r_x_4 - {{4{r_y_4[31]}},r_y_4[31:4]};
        r_y_5 <= r_y_4 + {{4{r_x_4[31]}},r_x_4[31:4]};
        r_angle_remain_5 <= r_angle_remain_4 - p_angle_4;
    end
    else //角度為正
    begin
        r_x_5 <= r_x_4 + {{4{r_y_4[31]}},r_y_4[31:4]};
        r_y_5 <= r_y_4 - {{4{r_x_4[31]}},r_x_4[31:4]};
        r_angle_remain_5 <= r_angle_remain_4 + p_angle_4;
    end
end
//第6次旋轉
reg [31:0] r_x_6 = 32'd0;
reg [31:0] r_y_6 = 32'd0;
reg [31:0] r_angle_remain_6 = 32'd0;
always @(posedge i_clk)
begin
    if (r_y_5[31]) //負數
    begin
        r_x_6 <= r_x_5 - {{5{r_y_5[31]}},r_y_5[31:5]};
        r_y_6 <= r_y_5 + {{5{r_x_5[31]}},r_x_5[31:5]};
        r_angle_remain_6 <= r_angle_remain_5 - p_angle_5;
    end
    else //角度為正
    begin
        r_x_6 <= r_x_5 + {{5{r_y_5[31]}},r_y_5[31:5]};
        r_y_6 <= r_y_5 - {{5{r_x_5[31]}},r_x_5[31:5]};
        r_angle_remain_6 <= r_angle_remain_5 + p_angle_5;
    end
end
//第7次旋轉
reg [31:0] r_x_7 = 32'd0;
reg [31:0] r_y_7 = 32'd0;
reg [31:0] r_angle_remain_7 = 32'd0;
always @(posedge i_clk)
begin
    if (r_y_6[31]) //負數
    begin
        r_x_7 <= r_x_6 - {{6{r_y_6[31]}},r_y_6[31:6]};
        r_y_7 <= r_y_6 + {{6{r_x_6[31]}},r_x_6[31:6]};
        r_angle_remain_7 <= r_angle_remain_6 - p_angle_6;
    end
    else //角度為正
    begin
        r_x_7 <= r_x_6 + {{6{r_y_6[31]}},r_y_6[31:6]};
        r_y_7 <= r_y_6 - {{6{r_x_6[31]}},r_x_6[31:6]};
        r_angle_remain_7 <= r_angle_remain_6 + p_angle_6;
    end
end
//第8次旋轉
reg [31:0] r_x_8 = 32'd0;
reg [31:0] r_y_8 = 32'd0;
reg [31:0] r_angle_remain_8 = 32'd0;
always @(posedge i_clk)
begin
    if (r_y_7[31]) //負數
    begin
        r_x_8 <= r_x_7 - {{7{r_y_7[31]}},r_y_7[31:7]};
        r_y_8 <= r_y_7 + {{7{r_x_7[31]}},r_x_7[31:7]};
        r_angle_remain_8 <= r_angle_remain_7 - p_angle_7;
    end
    else //角度為正
    begin
        r_x_8 <= r_x_7 + {{7{r_y_7[31]}},r_y_7[31:7]};
        r_y_8 <= r_y_7 - {{7{r_x_7[31]}},r_x_7[31:7]};
        r_angle_remain_8 <= r_angle_remain_7 + p_angle_7;
    end
end
//第9次旋轉
reg [31:0] r_x_9 = 32'd0;
reg [31:0] r_y_9 = 32'd0;
reg [31:0] r_angle_remain_9 = 32'd0;
always @(posedge i_clk)
begin
    if (r_y_8[31]) //負數
    begin
        r_x_9 <= r_x_8 - {{8{r_y_8[31]}},r_y_8[31:8]};
        r_y_9 <= r_y_8 + {{8{r_x_8[31]}},r_x_8[31:8]};
        r_angle_remain_9 <= r_angle_remain_8 - p_angle_8;
    end
    else //角度為正
    begin
        r_x_9 <= r_x_8 + {{8{r_y_8[31]}},r_y_8[31:8]};
        r_y_9 <= r_y_8 - {{8{r_x_8[31]}},r_x_8[31:8]};
        r_angle_remain_9 <= r_angle_remain_8 + p_angle_8;
    end
end
//第10次旋轉
reg [31:0] r_x_10 = 32'd0;
reg [31:0] r_y_10 = 32'd0;
reg [31:0] r_angle_remain_10 = 32'd0;
always @(posedge i_clk)
begin
    if (r_y_9[31]) //負數
    begin
        r_x_10 <= r_x_9 - {{9{r_y_9[31]}},r_y_9[31:9]};
        r_y_10 <= r_y_9 + {{9{r_x_9[31]}},r_x_9[31:9]};
        r_angle_remain_10 <= r_angle_remain_9 - p_angle_9;
    end
    else //角度為正
    begin
        r_x_10 <= r_x_9 + {{9{r_y_9[31]}},r_y_9[31:9]};
        r_y_10 <= r_y_9 - {{9{r_x_9[31]}},r_x_9[31:9]};
        r_angle_remain_10 <= r_angle_remain_9 + p_angle_9;
    end
end
//第11次旋轉
reg [31:0] r_x_11 = 32'd0;
reg [31:0] r_y_11 = 32'd0;
reg [31:0] r_angle_remain_11 = 32'd0;
always @(posedge i_clk)
begin
    if (r_y_10[31]) //負數
    begin
        r_x_11 <= r_x_10 - {{10{r_y_10[31]}},r_y_10[31:10]};
        r_y_11 <= r_y_10 + {{10{r_x_10[31]}},r_x_10[31:10]};
        r_angle_remain_11 <= r_angle_remain_10 - p_angle_10;
    end
    else //角度為正
    begin
        r_x_11 <= r_x_10 + {{10{r_y_10[31]}},r_y_10[31:10]};
        r_y_11 <= r_y_10 - {{10{r_x_10[31]}},r_x_10[31:10]};
        r_angle_remain_11 <= r_angle_remain_10 + p_angle_10;
    end
end
//第12次旋轉
reg [31:0] r_x_12 = 32'd0;
reg [31:0] r_y_12 = 32'd0;
reg [31:0] r_angle_remain_12 = 32'd0;
always @(posedge i_clk)
begin
    if (r_y_11[31]) //負數
    begin
        r_x_12 <= r_x_11 - {{11{r_y_11[31]}},r_y_11[31:11]};
        r_y_12 <= r_y_11 + {{11{r_x_11[31]}},r_x_11[31:11]};
        r_angle_remain_12 <= r_angle_remain_11 - p_angle_11;
    end
    else //角度為正
    begin
        r_x_12 <= r_x_11 + {{11{r_y_11[31]}},r_y_11[31:11]};
        r_y_12 <= r_y_11 - {{11{r_x_11[31]}},r_x_11[31:11]};
        r_angle_remain_12 <= r_angle_remain_11 + p_angle_11;
    end
end
//第13次旋轉
reg [31:0] r_x_13 = 32'd0;
reg [31:0] r_y_13 = 32'd0;
reg [31:0] r_angle_remain_13 = 32'd0;
always @(posedge i_clk)
begin
    if (r_y_12[31]) //負數
    begin
        r_x_13 <= r_x_12 - {{12{r_y_12[31]}},r_y_12[31:12]};
        r_y_13 <= r_y_12 + {{12{r_x_12[31]}},r_x_12[31:12]};
        r_angle_remain_13 <= r_angle_remain_12 - p_angle_12;
    end
    else //角度為正
    begin
        r_x_13 <= r_x_12 + {{12{r_y_12[31]}},r_y_12[31:12]};
        r_y_13 <= r_y_12 - {{12{r_x_12[31]}},r_x_12[31:12]};
        r_angle_remain_13 <= r_angle_remain_12 + p_angle_12;
    end
end
//第14次旋轉
reg [31:0] r_x_14 = 32'd0;
reg [31:0] r_y_14 = 32'd0;
reg [31:0] r_angle_remain_14 = 32'd0;
always @(posedge i_clk)
begin
    if (r_y_13[31]) //負數
    begin
        r_x_14 <= r_x_13 - {{13{r_y_13[31]}},r_y_13[31:13]};
        r_y_14 <= r_y_13 + {{13{r_x_13[31]}},r_x_13[31:13]};
        r_angle_remain_14 <= r_angle_remain_13 - p_angle_13;
    end
    else //角度為正
    begin
        r_x_14 <= r_x_13 + {{13{r_y_13[31]}},r_y_13[31:13]};
        r_y_14 <= r_y_13 - {{13{r_x_13[31]}},r_x_13[31:13]};
        r_angle_remain_14 <= r_angle_remain_13 + p_angle_13;
    end
end
//第15次旋轉
reg [31:0] r_x_15 = 32'd0;
reg [31:0] r_y_15 = 32'd0;
reg [31:0] r_angle_remain_15 = 32'd0;
always @(posedge i_clk)
begin
    if (r_y_14[31]) //負數
    begin
        r_x_15 <= r_x_14 - {{14{r_y_14[31]}},r_y_14[31:14]};
        r_y_15 <= r_y_14 + {{14{r_x_14[31]}},r_x_14[31:14]};
        r_angle_remain_15 <= r_angle_remain_14 - p_angle_14;
    end
    else //角度為正
    begin
        r_x_15 <= r_x_14 + {{14{r_y_14[31]}},r_y_14[31:14]};
        r_y_15 <= r_y_14 - {{14{r_x_14[31]}},r_x_14[31:14]};
        r_angle_remain_15 <= r_angle_remain_14 + p_angle_14;
    end
end
//第16次旋轉
reg [31:0] r_x_16 = 32'd0;
reg [31:0] r_y_16 = 32'd0;
reg [31:0] r_angle_remain_16 = 32'd0;
always @(posedge i_clk)
begin
    if (r_y_14[31]) //負數
    begin
        r_x_16 <= r_x_15 - {{15{r_y_15[31]}},r_y_15[31:15]};
        r_y_16 <= r_y_15 + {{15{r_x_15[31]}},r_x_15[31:15]};
        r_angle_remain_16 <= r_angle_remain_15 - p_angle_15;
    end
    else //角度為正
    begin
        r_x_16 <= r_x_15 + {{15{r_y_15[31]}},r_y_15[31:15]};
        r_y_16 <= r_y_15 - {{15{r_x_15[31]}},r_x_15[31:15]};
        r_angle_remain_16 <= r_angle_remain_15 + p_angle_15;
    end
end
////使能延遲對齊輸出
reg [16:0] r_en_delay = 17'd0;
always @(posedge i_clk)
begin
    r_en_delay <= {r_en_delay[15:0],i_en};
end
////信號輸出
assign o_angle = r_angle_remain_16;
assign o_r = r_x_16;
assign o_en = r_en_delay[16];

endmodule // end the z_r_cordic model;

 

雙曲反正切的妙用

 雙曲反正切有啥用呢,如果你想求log10,冥思苦想,這玩意咋用verilog求?而我們知道如下公式:

則log10就可以轉化為求解arctanh的值。而我們知道,arctanh是可以用cordic在雙曲模式下求解其值的。所以,log就可以用cordic求解。

在雙曲模式下的算法迭代跟其他的不一樣,涉及到收斂問題,且從N為4開始,每當3k+1的項需要重復迭代。即1,2,3,4,4,5,6.....12,13,13,14.....

而同時簡單的正數迭代,y和x的取值范圍十分有限,對於arctanh((r-1)/(r+1))的r最大值僅僅為9,簡直是不可用的。

還好前人早已想到了這個問題,請參考論文,需要添加負數次的迭代,擴大定義域。

算法過程:

1.取x=r+1,y=r-1,z=0。當Y迭代逼近0的時候,z的值即為arctanh((r-1)/(r+1))的值。取迭代次數為16次的時候,N=-5起始迭代。則可以事先求解出相應的arctanh值作為常量供迭代方程加減。

 

2.迭代公式,選取從N=-5處開始迭代,則有

 3.編寫verilog代碼。

仿真一下看看。

r=10仿真結果如下所示:x,y首先均左移8位。

 

log10(10) = 71047/2^16*0.86858896 = 0.9416

log10(100) = 125429/2^16*0.86858896 = 1.6624

log10(1000) =225544/2^16*0.86858896 = 2.9893

log10(10000) = 299021/2^16*0.86858896 = 3.9631

有一定的誤差,跟迭代次數和迭代輸入值x,y有關

 注意事項:(1)處理中間結果的越界問題,位寬需要注意。

                   (2)如果r輸入是個很小的數,比如10,可能還沒迭代兩次,y就到0了,必然導致結果的誤差過大,則可以放大x和y,畢竟我們知道arctanh(y/x)=arctanh(y*k/(x*k))的。

                            所以結果並不會發生改變,但可以使得迭代更多次,保證精度。當然預先做個數值范圍判定移位更佳。

                   (3)算術移位的問題,必須定義signed,否則會有問題的。還是老實使用拼接截位操作得好。

以上只是對算法進行了功能的實現,側重點並不在資源量的最優。

以上。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM