FPGA SDR(19)自作ATAN2
2018/07/29 追記:360°を8等分して45°~90°に変換してから計算するようにすると音質が改善しました。
2018/07/22 追記:ATAN2の出力を16ビットまでパラメータで指定できるようにしました。
Cyclone II EP2C5T144で使えるQuartus II Web Edition 13.0sp1のMegaWizardにALTERA CORDICが見つかりません。EP2C5T144でもFMラジオを作りたいのでCORDICを勉強してATAN2を作ってみました。加減算とビットシフトだけで済んでしまうんですね。ATAN2の出力を16ビットとして、計算に必要なテーブルはたった13行です。
360°を8等分して45°~90°に変換してから計算しています。
`timescale 1ns/1ns module MyATAN2 #( parameter XY_WIDTH = 10, parameter Q_WIDTH = 10 ) ( input wire areset, input wire clk, input wire en, input wire signed [XY_WIDTH-1:0] x, input wire signed [XY_WIDTH-1:0] y, output reg signed [Q_WIDTH-1:0] q ); localparam TABLE_WIDTH = 16; localparam TABLE_SIZE = 13; localparam DATA_WIDTH = 1 + XY_WIDTH + TABLE_SIZE; localparam PI = 16'sb011_0010_0100_0011_1; // pi = 0011 . 0010 0100 0011 1111 0110 1010 reg [3:0] n; // 0 ~ TABLE_SIZE+1 reg [2:0] quad; // 0 ~ 7 wire signed [DATA_WIDTH-1:0] pi; wire signed [DATA_WIDTH-1:0] pidiv2; reg signed [DATA_WIDTH-1:0] xn; reg signed [DATA_WIDTH-1:0] yn; reg signed [TABLE_WIDTH-1:0] atan; reg signed [TABLE_WIDTH-1:0] atan_table [0:TABLE_SIZE-1]; initial begin atan_table[0] = 16'sb000_1100_1001_0000_1; // atan(1/1): 000 . 1100 1001 0000 1111 1101 1010 atan_table[1] = 16'sb000_0111_0110_1011_0; // atan(1/2): 000 . 0111 0110 1011 0001 1001 1100 atan_table[2] = 16'sb000_0011_1110_1011_0; // atan(1/4): 000 . 0011 1110 1011 0110 1110 1011 atan_table[3] = 16'sb000_0001_1111_1101_0; // atan(1/8): 000 . 0001 1111 1101 0101 1011 1010 atan_table[4] = 16'sb000_0000_1111_1111_1; // atan(1/16): 000 . 0000 1111 1111 1010 1010 1101 atan_table[5] = 16'sb000_0000_0111_1111_1; // atan(1/32): 000 . 0000 0111 1111 1111 0101 0101 atan_table[6] = 16'sb000_0000_0011_1111_1; // atan(1/64): 000 . 0000 0011 1111 1111 1110 1010 atan_table[7] = 16'sb000_0000_0001_1111_1; // atan(1/128): 000 . 0000 0001 1111 1111 1111 1101 atan_table[8] = 16'sb000_0000_0000_1111_1; // atan(1/256): 000 . 0000 0000 1111 1111 1111 1111 atan_table[9] = 16'sb000_0000_0000_0111_1; // atan(1/512): 000 . 0000 0000 0111 1111 1111 1111 atan_table[10] = 16'sb000_0000_0000_0011_1; // atan(1/1024): 000 . 0000 0000 0011 1111 1111 1111 atan_table[11] = 16'sb000_0000_0000_0001_1; // atan(1/2048): 000 . 0000 0000 0001 1111 1111 1111 atan_table[12] = 16'sb000_0000_0000_0000_1; // atan(1/4096): 000 . 0000 0000 0000 1111 1111 1111 end assign pi = PI >>> (TABLE_WIDTH - Q_WIDTH); assign pidiv2 = pi >>> 1; always @(posedge clk) begin if (areset) begin n <= 0; quad <= 0; xn <= 0; yn <= 0; atan <= 0; q <= 0; end else begin if (en) begin n <= 0; if (x[XY_WIDTH-1] == 1'b0 && y[XY_WIDTH-1] == 1'b0) begin if (x >= y) begin quad <= 0; yn <= { x[XY_WIDTH-1], x, {TABLE_SIZE{1'b0}} }; xn <= { y[XY_WIDTH-1], y, {TABLE_SIZE{1'b0}} }; end else begin quad <= 1; xn <= { x[XY_WIDTH-1], x, {TABLE_SIZE{1'b0}} }; yn <= { y[XY_WIDTH-1], y, {TABLE_SIZE{1'b0}} }; end end else if (x[XY_WIDTH-1] == 1'b1 && y[XY_WIDTH-1] == 1'b0) begin if (-x <= y) begin quad <= 2; xn <= -{ x[XY_WIDTH-1], x, {TABLE_SIZE{1'b0}} }; yn <= { y[XY_WIDTH-1], y, {TABLE_SIZE{1'b0}} }; end else begin quad <= 3; yn <= -{ x[XY_WIDTH-1], x, {TABLE_SIZE{1'b0}} }; xn <= { y[XY_WIDTH-1], y, {TABLE_SIZE{1'b0}} }; end end else if (x[XY_WIDTH-1] == 1'b1 && y[XY_WIDTH-1] == 1'b1) begin if (-x >= -y) begin quad <= 4; yn <= -{ x[XY_WIDTH-1], x, {TABLE_SIZE{1'b0}} }; xn <= -{ y[XY_WIDTH-1], y, {TABLE_SIZE{1'b0}} }; end else begin quad <= 5; xn <= -{ x[XY_WIDTH-1], x, {TABLE_SIZE{1'b0}} }; yn <= -{ y[XY_WIDTH-1], y, {TABLE_SIZE{1'b0}} }; end end else begin if (x <= -y) begin quad <= 6; xn <= { x[XY_WIDTH-1], x, {TABLE_SIZE{1'b0}} }; yn <= -{ y[XY_WIDTH-1], y, {TABLE_SIZE{1'b0}} }; end else begin quad <= 7; yn <= { x[XY_WIDTH-1], x, {TABLE_SIZE{1'b0}} }; xn <= -{ y[XY_WIDTH-1], y, {TABLE_SIZE{1'b0}} }; end end atan <= 0; if (quad == 0) q <= pidiv2 - atan; // x <-> y else if (quad == 1) q <= atan; else if (quad == 2) q <= pi - atan; else if (quad == 3) q <= pi - (pidiv2 - atan); // x <-> y else if (quad == 4) q <= -pi + (pidiv2 - atan); // x <-> y else if (quad == 5) q <= -pi + atan; else if (quad == 6) q <= -atan; else q <= -(pidiv2 - atan); // x <-> y end else begin if (n <= TABLE_SIZE) begin n <= n + 1; end if (1 <= n && n <= TABLE_SIZE) begin if (yn[DATA_WIDTH-1] == 1'b0) begin xn <= xn + (yn >>> (n-1)); yn <= yn - (xn >>> (n-1)); atan <= atan + (atan_table[n-1] >>> (TABLE_WIDTH - Q_WIDTH)); end else begin xn <= xn + (yn >>> (n-1)); yn <= yn + (xn >>> (n-1)); atan <= atan - (atan_table[n-1] >>> (TABLE_WIDTH - Q_WIDTH)); end end end end end endmodule