URL
https://opencores.org/ocsvn/cordic_atan_iq/cordic_atan_iq/trunk
Subversion Repositories cordic_atan_iq
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 7 to Rev 8
- ↔ Reverse comparison
Rev 7 → Rev 8
/cordic_atan_iq/AuxClasses.sv
0,0 → 1,46
`ifndef _AuxClasses_ |
`define _AuxClasses_ |
|
package AuxClassesPkg; |
|
const real PI = 3.1415926535897932384626433832795; |
|
const int V_MAX = {{3{1'b0}}, {29{1'b1}}}; |
const int V_MIN = {{3{1'b1}}, {29{1'b0}}}; |
|
// const int V_MAX = {{4{1'b0}}, {28{1'b1}}}; |
// const int V_MIN = {{4{1'b1}}, {28{1'b0}}}; |
|
class IQClass; |
int I, Q; |
|
function new(int I, int Q); |
this.I = I; |
this.Q = Q; |
endfunction |
endclass :IQClass |
|
class IQArrayList; |
IQClass data[$]; |
|
function new(); |
data = {}; |
endfunction |
|
function void push_back(int I, int Q); |
IQClass iq = new(I, Q); |
data.push_back(iq); |
endfunction |
|
function int size(); |
return data.size; |
endfunction |
|
function string ToString(); |
return ""; |
endfunction |
endclass :IQArrayList |
|
endpackage :AuxClassesPkg |
|
`endif |
/cordic_atan_iq/AuxFunc.sv
0,0 → 1,89
`ifndef _AuxPkg_ |
`define _AuxPkg_ |
`include "AuxClasses.sv" |
|
package AuxFuncPkg; |
import AuxClassesPkg::*; |
export AuxClassesPkg::*; |
|
function automatic int atan_iq_int(int IS, int QS); |
if (IS == 0) |
if (QS > 0) |
return 2**30; // 90 |
else if (QS < 0) |
return -(2**30); // -90 |
else |
return 0; |
else if (QS == 0) |
if (IS < 0) |
return 1<<31; // -180 |
else |
return 0; |
else if (IS < 0) |
if (QS > 0) |
return int'(($atan(real'(QS)/IS) + PI) * ((2.0**31) / PI)); |
else |
return int'(($atan(real'(QS)/IS) - PI) * ((2.0**31) / PI)); |
else |
return int'($atan(real'(QS)/IS) * ((2.0**31) / PI)); |
endfunction |
|
function automatic real int_to_deg(int angle); |
return real'(angle) / 2.0**30 * 90.0; |
endfunction |
|
function automatic int delta(int ref_angle, int angle); |
return angle - ref_angle; |
endfunction |
|
function automatic real rel_pct(int ref_angle, int angle); |
int d = delta(ref_angle, angle); |
|
if (d < 0) d = -d; |
|
if (ref_angle == 0) |
if (d == 0) |
return 0; |
else |
return 100; |
else |
return real'(d) / real'(ref_angle) * 100.0; |
endfunction |
|
function automatic IQArrayList GenIQ(int POINTS = 8); |
IQArrayList v = new; |
|
// 135...45 deg |
for (int i = -POINTS; i < POINTS; i++) |
v.push_back(i * (V_MAX / POINTS), V_MAX); |
|
// 45...-45 deg |
for (int i = POINTS; i > -POINTS; i--) |
v.push_back(V_MAX, i * (V_MAX / POINTS)); |
|
// -45...-135 deg |
for (int i = POINTS; i > -POINTS; i--) |
v.push_back(i * (V_MAX / POINTS), V_MIN); |
|
// -135...135 deg |
for (int i = -POINTS; i < POINTS; i++) |
v.push_back(V_MIN, i * (V_MAX / POINTS)); |
|
return v; |
endfunction |
|
function automatic int unsigned iabs(int value); |
if (value < 0) value = -value; |
return value; |
endfunction |
|
function automatic int unsigned imag(int I, int Q); |
real res = int'( $sqrt(real'(I) * real'(I) + real'(Q) * real'(Q)) ); |
int unsigned res_uint = longint'(res); |
// $display("I %d Q %d Mag %g (%d)\n", I, Q, res, res_uint); |
return res_uint; |
endfunction |
|
endpackage :AuxFuncPkg |
|
`endif |
/cordic_atan_iq/atan32_table.sv
0,0 → 1,53
`ifndef _atan32_table_ |
`define _atan32_table_ |
// atan table for values 1, 1/2, 1/4, 1/8, 1/16... |
// Scale: code 2^30 = 90 deg, code 0 = 0 deg |
|
package ConstPkg; |
|
parameter STEPS = 32; |
parameter real K = 0.6072529350088813; |
parameter bit [29:0] K_u30 = 30'h26dd3b6a; |
parameter bit [31:0] K_u32 = 32'h9b74eda8; |
// for sin and cos start calculation from vector {K_u30, 0} |
// modulus of vector {I, Q} = (coe_abs * K_u32) >> 32 |
// last table value dont use |
|
parameter bit signed [31:0] atan_table[STEPS] = '{ |
32'sh20000000, // tan = 1/2^1 = 1/2 |
32'sh12e4051e, // tan = 1/2^2 = 1/4 |
32'sh09fb385b, // tan = 1/2^3 = 1/8 |
32'sh051111d4, // tan = 1/2^4 = 1/16 |
32'sh028b0d43, // tan = 1/2^5 = 1/32 |
32'sh0145d7e1, // tan = 1/2^6 = 1/64 |
32'sh00a2f61e, // tan = 1/2^7 = 1/128 |
32'sh00517c55, // tan = 1/2^8 = 1/256 |
32'sh0028be53, // tan = 1/2^9 = 1/512 |
32'sh00145f2f, // tan = 1/2^10 = 1/1024 |
32'sh000a2f98, // tan = 1/2^11 = 1/2048 |
32'sh000517cc, // tan = 1/2^12 = 1/4096 |
32'sh00028be6, // tan = 1/2^13 = 1/8192 |
32'sh000145f3, // tan = 1/2^14 = 1/16384 |
32'sh0000a2fa, // tan = 1/2^15 = 1/32768 |
32'sh0000517d, // tan = 1/2^16 = 1/65536 |
32'sh000028be, // tan = 1/2^17 = 1/131072 |
32'sh0000145f, // tan = 1/2^18 = 1/262144 |
32'sh00000a30, // tan = 1/2^19 = 1/524288 |
32'sh00000518, // tan = 1/2^20 = 1/1048576 |
32'sh0000028c, // tan = 1/2^21 = 1/2097152 |
32'sh00000146, // tan = 1/2^22 = 1/4194304 |
32'sh000000a3, // tan = 1/2^23 = 1/8388608 |
32'sh00000051, // tan = 1/2^24 = 1/16777216 |
32'sh00000029, // tan = 1/2^25 = 1/33554432 |
32'sh00000014, // tan = 1/2^26 = 1/67108864 |
32'sh0000000a, // tan = 1/2^27 = 1/134217728 |
32'sh00000005, // tan = 1/2^28 = 1/268435456 |
32'sh00000003, // tan = 1/2^29 = 1/536870912 |
32'sh00000001, // tan = 1/2^30 = 1/1073741824 |
32'sh00000001, // tan = 1/2^31 = 1/2147483648 |
32'sh00000000 // tan = 1/2^32 = 1/4294967296 |
}; |
|
endpackage: ConstPkg |
|
`endif |
/cordic_atan_iq/atan32_table_gen.m
0,0 → 1,49
clc |
|
i = 0; |
atan_table(1) = int32(1); |
|
while i == 0 || atan_table(i) ~= 0 |
atan_table(i+1) = int32(round(atan(1/2^i) / (pi/2) * 2^30)); |
i = i + 1; |
end |
|
k = 1; |
for i=1:length(atan_table) % ? |
k = k * 1 / sqrt(1 + 2^(-2 * (i-1))); |
end |
|
fid = fopen('atan32_table.sv', 'w'); |
|
fprintf(fid, '`ifndef _atan32_table_\n'); |
fprintf(fid, '`define _atan32_table_\n'); |
fprintf(fid, '// atan table for values 1, 1/2, 1/4, 1/8, 1/16...\n'); |
fprintf(fid, '// Scale: code 2^30 = 90 deg, code 0 = 0 deg\n\n'); |
|
fprintf(fid, 'package ConstPkg;\n\n'); |
fprintf(fid, ' parameter STEPS = %d;\n', length(atan_table)); |
fprintf(fid, ' parameter real K = %.16f;\n', k); |
fprintf(fid, ' parameter bit [29:0] K_u30 = 30''h%08x;\n', int32(round(k * 2^30))); |
fprintf(fid, ' parameter bit [31:0] K_u32 = 32''h%08x;\n', uint32(round(k * 2^32))); |
fprintf(fid, '// for sin and cos start calculation from vector {K_u30, 0}\n'); |
fprintf(fid, '// modulus of vector {I, Q} = (coe_abs * K_u32) >> 32\n'); |
fprintf(fid, '// last table value dont use\n\n'); |
|
fprintf(fid, ' parameter bit signed [31:0] atan_table[STEPS] = ''{\n'); |
|
for i=1:length(atan_table) |
fprintf(fid, ' 32''sh%08x', atan_table(i)); |
if i ~= length(atan_table) |
fprintf(fid, ', // tan = 1/2^%d = 1/%d\n', i, 2^i); |
else |
fprintf(fid, ' // tan = 1/2^%d = 1/%d\n', i, 2^i); |
fprintf(fid, ' };\n\n'); |
end |
end |
|
fprintf(fid, 'endpackage: ConstPkg\n\n'); |
fprintf(fid, '`endif\n'); |
|
fclose(fid); |
|
sum(double(atan_table / 2^30)) |
/cordic_atan_iq/cordic_atan_abs.sv
0,0 → 1,30
`ifndef _cordic_atan_abs_ |
`define _cordic_atan_abs_ |
`include "cordic_atan_iq.sv" |
|
module cordic_atan_abs(clk, IS, QS, angle, abs); |
import ConstPkg::K_u32; |
|
input wire clk; |
input wire signed [29:0] IS, QS; |
output reg signed [31:0] angle; |
output reg [30:0] abs; // sqrt(I^2 + Q^2) |
|
wire signed [31:0] angle_res; |
wire [31:0] coe_radius; |
|
cordic_atan_iq cordic_inst(.clk, .IS, .QS, .angle(angle_res), .coe_radius); |
|
reg [($bits(coe_radius) + $bits(K_u32) - 1):0] abs_reg; |
|
always_ff @(posedge clk) |
abs_reg <= coe_radius * K_u32; |
|
assign abs = abs_reg[$bits(K_u32)+:31]; |
|
always_ff @(posedge clk) |
angle <= angle_res; |
|
endmodule :cordic_atan_abs |
|
`endif |
/cordic_atan_iq/cordic_atan_abs_tb.sv
0,0 → 1,152
timeunit 1ns; |
timeprecision 1ns; |
|
`include "AuxFunc.sv" |
`include "AuxClasses.sv" |
|
module cordic_atan_abs_tb; |
import AuxFuncPkg::*; |
import AuxClassesPkg::*; |
|
bit clk = 0; |
bit signed [29:0] IS, QS; |
wire signed [31:0] angle; |
wire [30:0] abs; |
|
int ang_delta_max = 0, ang_delta_min = 0; |
int abs_delta_max = 0, abs_delta_min = 0; |
real pct; |
int i, j; |
|
always #10ns clk++; |
|
initial begin |
repeat(10) @(posedge clk); |
|
//Test(20_000_000, 4_000_000); |
//Test(0, V_MAX); |
//Test(V_MIN, 0); |
// Test(V_MIN, V_MIN); |
// Test(32'he0000008, 32'h1fffffff); |
//Test(0, V_MIN); |
Test2(); |
|
$stop(2); |
end |
|
cordic_atan_abs dut(.*); |
|
// |
task Test(bit signed [29:0] I, Q); |
int atan_ref, ang_delta, abs_ref, abs_res, abs_delta; |
|
IS = I; |
QS = Q; |
repeat(100) @(posedge clk); |
|
atan_ref = atan_iq_int(int'(IS), int'(QS)); |
ang_delta = delta(atan_ref, angle); |
pct = rel_pct(atan_ref, angle); |
|
$display("%d {%08h, %08h}. Ref %g deg (%d), RTL A = %g deg (%d), delta %d (%g pct)", i, int'(IS), int'(QS), int_to_deg(atan_ref), atan_ref, int_to_deg(angle), angle, ang_delta, pct); |
|
abs_ref = imag(I, Q); |
abs_res = 32'(abs); |
abs_delta = delta(abs_ref, abs_res); |
$display("\tAbs: Ref %d, RTL %d, delta %d", abs_ref, abs_res, abs_delta); |
|
assert (iabs(ang_delta) <= 16 && iabs(abs_delta) <= 16) else $display("ERROR!"); |
endtask |
|
task Test2(int POINTS = 8192); |
int atan_ref, ang_delta, abs_ref, abs_res, abs_delta; |
int I, Q; |
automatic bit error = 0; |
|
// automatic IQArrayList v = GenIQ(POINTS/8); |
automatic IQArrayList v = GenIQ(1024); |
|
fork |
begin |
for (int i = 0; i < v.size(); i++) begin |
IS = v.data[i].I; |
QS = v.data[i].Q; |
@(posedge clk); |
end |
end |
begin |
repeat(32+2) @(posedge clk); |
|
for (int i = 0; i < v.size(); i++) begin |
I = v.data[i].I; |
Q = v.data[i].Q; |
|
atan_ref = atan_iq_int(I, Q); |
|
ang_delta = delta(atan_ref, angle); |
if (ang_delta > ang_delta_max) ang_delta_max = ang_delta; |
if (ang_delta < ang_delta_min) ang_delta_min = ang_delta; |
|
pct = rel_pct(atan_ref, angle); |
|
$display("%d {%08h, %08h}: Ref %g deg (%d), RTL %g deg (%d), delta %d (%g pct)", i, I, Q, int_to_deg(atan_ref), atan_ref, int_to_deg(angle), angle, ang_delta, pct); |
|
abs_ref = imag(I, Q); |
abs_res = 32'(abs); |
abs_delta = delta(abs_ref, abs_res); |
if (abs_delta > abs_delta_max) abs_delta_max = abs_delta; |
if (abs_delta < abs_delta_min) abs_delta_min = abs_delta; |
|
$display("\tAbs: Ref %d, RTL %d, delta %d", abs_ref, abs_res, abs_delta); |
|
assert (iabs(ang_delta) <= 16 && iabs(abs_delta) <= 16) |
else |
begin |
error = 1; |
$display("ERROR!"); |
end |
|
@(posedge clk); |
end |
|
if (error) |
$display("Result: ERROR!"); |
else |
$display("Result: OK"); |
end |
join |
|
$display("Calculation precision: [%d, %d] ([%g, %g] sec)", ang_delta_min, ang_delta_max, int_to_deg(ang_delta_min) * 60**2, int_to_deg(ang_delta_max) * 60**2); |
$display("\tAbs: [%d, %d])", abs_delta_min, abs_delta_max); |
|
repeat(100) @(posedge clk); |
$stop(2); |
endtask |
|
// |
wire [31:0][31:0] x; |
wire [30:0][31:0] y; |
wire [31:1][31:0] a; |
|
genvar k; |
generate for (k = 0; k < 32; k++) |
begin :gen_x |
assign x[k] = dut.cordic_inst.x[k]; |
end |
endgenerate |
|
genvar n; |
generate for (n = 0; n < 31; n++) |
begin :gen_y |
assign y[n] = dut.cordic_inst.y[n]; |
end |
endgenerate |
|
genvar m; |
generate for (m = 1; m < 32; m++) |
begin :gen_a |
assign a[m] = dut.cordic_inst.a[m]; |
end |
endgenerate |
|
endmodule :cordic_atan_abs_tb |
/cordic_atan_iq/cordic_atan_iq.m
0,0 → 1,80
|
function [angle, isqrt] = cordic_atan_iq(IS, QS); |
|
IS = int32(IS); |
QS = int32(QS); |
|
tg = double(QS) / double(IS); |
atg = atan(tg) / pi * 180; |
fprintf('Given I = %g, Q = %g, angle = %g degree\n', IS, QS, atg); |
|
sign = IS < 0; |
if sign |
IS = -IS; |
QS = -QS; |
end |
|
% [F Exp_I] = log2(double(IS)); |
% [F Exp_Q] = log2(double(QS)); |
% |
% Exp_I |
% Exp_Q |
% |
% E = max(Exp_I, Exp_Q) + 1; |
% |
% IS = int32(IS * 2^(31 - E)); |
% QS = int32(QS * 2^(31 - E)); |
|
fprintf('I = 0x%08x, Q = 0x%08x\n', IS, QS); |
|
i = 0; |
atan_table(1) = int32(1); |
|
while i == 0 || atan_table(i) ~= 0 |
atan_table(i+1) = int32(2^30 * atan(1/2^i) / (pi/2)); |
i = i + 1; |
end |
|
k = 1; |
for i=1:length(atan_table) |
k = k * 1 / sqrt(1 + 2^(-2 * (i-1))); |
end |
|
x(1) = IS; |
y(1) = QS; |
a(1) = int32(0); |
|
tg = double(y(1)) / double(x(1)); |
atg = atan(tg) / pi * 180; |
fprintf('i = %d: x = %d, y = %d (%g deg), a = %d(%g degree)\n', 0, x(1), y(1), atg, a(1), double(a(1))/2^30 * 90); |
|
for i=2:length(atan_table) % i dont use last table element |
if y(i-1) > 0 |
x(i) = x(i-1) + y(i-1) / 2^(i-2); |
y(i) = -x(i-1) / 2^(i-2) + y(i-1); |
a(i) = a(i-1) - atan_table(i-1); |
fprintf('i = %d: rot = %g deg, ', i-1, -double(atan_table(i-1)) / 2^30 * 90); |
else |
x(i) = x(i-1) - y(i-1) / 2^(i-2); |
y(i) = x(i-1) / 2^(i-2) + y(i-1); |
a(i) = a(i-1) + atan_table(i-1); |
fprintf('i = %d: rot = %g deg, ', i-1, double(atan_table(i-1)) / 2^30 * 90); |
end |
|
tg = double(y(i)) / double(x(i)); |
atg = atan(tg) / pi * 180; |
fprintf('x = %d, y = %d (%g deg), a = %d(%g deg)\n', x(i), y(i), atg, a(i), double(a(i))/2^30 * 90); |
end |
|
angle = -double(a(end))/2^30 * 90; |
if sign |
if angle > 0 |
angle = angle - 180; |
else |
angle = angle + 180; |
end |
end |
|
isqrt = int32(k * double(x(end))); |
|
end |
/cordic_atan_iq/cordic_atan_iq.sv
0,0 → 1,87
`ifndef _cordic_atan_iq_ |
`define _cordic_atan_iq_ |
`include "atan32_table.sv" |
|
// Calc delay 32 clocks |
module cordic_atan_iq(clk, IS, QS, angle, coe_radius); |
import ConstPkg::atan_table; |
localparam STEPS = ConstPkg::STEPS; |
|
input wire clk; // todo: clk_ena |
input wire signed [29:0] IS, QS; |
output signed [31:0] angle; |
output [31:0] coe_radius; // sqrt(I^2 + Q^2) / K |
|
wire isign; |
reg isign_reg; |
reg signed [31:0] x[STEPS], y[STEPS-1]; // + 2 bit for carry (sqrt(2) * (1 + k)) todo: x unsigned and increase input vector width |
reg signed [31:0] a[STEPS-1:1]; |
|
assign isign = IS < 'sh0; |
|
// rotate to working range -90..+90 |
always_ff @(posedge clk) begin |
x[0] <= (isign) ? 32'sh0 - IS : 32'sh0 + IS; |
y[0] <= (isign) ? 32'sh0 + QS : 32'sh0 - QS; // invert y sign for true result sign |
isign_reg <= isign; // save rotate on 180 deg |
end |
|
always_ff @(posedge clk) |
if (y[0] > 'sh0) |
begin |
x[1] <= x[0] + y[0]; |
y[1] <= y[0] - x[0]; |
|
if (isign_reg) |
a[1] <= signed'({1'b0, {31{1'b1}}}) - (atan_table[0] - 1'b1); // rotate 180 - 45 deg |
else |
a[1] <= -atan_table[0]; // rotate -45 deg |
end |
else |
begin |
x[1] <= x[0] - y[0]; |
y[1] <= y[0] + x[0]; |
|
if (isign_reg) |
a[1] <= signed'({1'b1, {31{1'b0}}}) + atan_table[0]; // rotate -180 + 45 deg |
else |
a[1] <= atan_table[0]; // rotate +45 deg |
end |
|
genvar i; |
generate for(i = 2; i < STEPS-1; i++) |
begin :gen |
always_ff @(posedge clk) |
if (y[i-1] > 'sh0) |
begin |
x[i] <= x[i-1] + (y[i-1] >>> (i - 1)); |
y[i] <= y[i-1] - (x[i-1] >>> (i - 1)); |
a[i] <= a[i-1] - atan_table[i-1]; |
end |
else |
begin |
x[i] <= x[i-1] - (y[i-1] >>> (i - 1)); |
y[i] <= y[i-1] + (x[i-1] >>> (i - 1)); |
a[i] <= a[i-1] + atan_table[i-1]; |
end |
end |
endgenerate |
|
always_ff @(posedge clk) |
if (y[STEPS-2] > 'sh0) |
begin |
x[STEPS-1] <= x[STEPS-2] + (y[STEPS-2] >>> (STEPS-2)); |
a[STEPS-1] <= a[STEPS-2] - atan_table[STEPS-2]; |
end |
else |
begin |
x[STEPS-1] <= x[STEPS-2] - (y[STEPS-2] >>> (STEPS-2)); |
a[STEPS-1] <= a[STEPS-2] + atan_table[STEPS-2]; |
end |
|
assign angle = a[STEPS-1]; |
assign coe_radius = x[STEPS-1]; |
|
endmodule : cordic_atan_iq |
|
`endif |
/cordic_atan_iq/cordic_atan_iq_tb.sv
0,0 → 1,151
timeunit 1ns; |
timeprecision 1ns; |
|
`include "AuxFunc.sv" |
`include "AuxClasses.sv" |
`include "atan32_table.sv" |
|
module cordic_atan_iq_tb; |
import AuxFuncPkg::*; |
import AuxClassesPkg::*; |
|
bit clk = 0; |
bit signed [29:0] IS, QS; |
wire signed [31:0] angle; |
wire [31:0] coe_radius; |
|
int ang_delta_max = 0, ang_delta_min = 0; |
int abs_delta_max = 0, abs_delta_min = 0; |
real pct; |
int i, j; |
|
always #10ns clk++; |
|
initial begin |
repeat(10) @(posedge clk); |
|
//Test(20_000_000, 4_000_000); |
//Test(0, V_MAX); |
//Test(V_MIN, 0); |
//Test(V_MIN, V_MAX); |
//Test(0, V_MIN); |
Test2(); |
|
$stop(2); |
end |
|
cordic_atan_iq dut(.*); |
|
task Test(bit signed [29:0] I, Q); |
int atan_ref, ang_delta, abs_ref, abs_res, abs_delta; |
|
IS = I; |
QS = Q; |
repeat(100) @(posedge clk); |
|
atan_ref = atan_iq_int(int'(IS), int'(QS)); |
ang_delta = delta(atan_ref, angle); |
pct = rel_pct(atan_ref, angle); |
|
$display("%d {%08h, %08h}: Ref %g deg (%d), RTL %g deg (%d), delta %d (%g pct)", i, int'(IS), int'(QS), int_to_deg(atan_ref), atan_ref, int_to_deg(angle), angle, ang_delta, pct); |
|
abs_ref = imag(I, Q); |
abs_res = int'(ConstPkg::K * real'(coe_radius)); |
abs_delta = delta(abs_ref, abs_res); |
$display("\tAbs: x[end] = %08h, Ref %d, RTL %d, delta %d", coe_radius, abs_ref, abs_res, abs_delta); |
|
assert (iabs(ang_delta) <= 16 && iabs(abs_delta) <= 16) else $display("ERROR!"); |
endtask |
|
task Test2(); |
int atan_ref, ang_delta, abs_ref, abs_res, abs_delta; |
int I, Q; |
automatic bit error = 0; |
|
// automatic IQArrayList v = GenIQ(); |
automatic IQArrayList v = GenIQ(1024); |
|
fork |
begin |
for (int i = 0; i < v.size(); i++) begin |
IS = v.data[i].I; |
QS = v.data[i].Q; |
@(posedge clk); |
end |
end |
begin |
repeat(32+1) @(posedge clk); |
|
for (int i = 0; i < v.size(); i++) begin |
I = v.data[i].I; |
Q = v.data[i].Q; |
|
atan_ref = atan_iq_int(I, Q); |
|
ang_delta = delta(atan_ref, angle); |
if (ang_delta > ang_delta_max) ang_delta_max = ang_delta; |
if (ang_delta < ang_delta_min) ang_delta_min = ang_delta; |
|
pct = rel_pct(atan_ref, angle); |
|
$display("%d {%08h, %08h}. Angle: Ref %g deg (%d), RTL %g deg (%d), delta %d (%g pct)", i, I, Q, int_to_deg(atan_ref), atan_ref, int_to_deg(angle), angle, ang_delta, pct); |
|
abs_ref = imag(I, Q); |
abs_res = int'(ConstPkg::K * real'(coe_radius)); |
abs_delta = delta(abs_ref, abs_res); |
if (abs_delta > abs_delta_max) abs_delta_max = abs_delta; |
if (abs_delta < abs_delta_min) abs_delta_min = abs_delta; |
|
$display("\tAbs: x[end] = %08h, Ref %d, RTL %d, delta %d", coe_radius, abs_ref, abs_res, abs_delta); |
|
assert (iabs(ang_delta) <= 16 && iabs(abs_delta) <= 16) |
else |
begin |
error = 1; |
$display("ERROR!"); |
end |
|
@(posedge clk); |
end |
|
if (error) |
$display("Result: ERROR!"); |
else |
$display("Result: OK"); |
end |
join |
|
$display("Calculation precision. Angle: [%d, %d] ([%g, %g] sec)", ang_delta_min, ang_delta_max, int_to_deg(ang_delta_min) * 60**2, int_to_deg(ang_delta_max) * 60**2); |
$display("\tAbs: [%d, %d])", abs_delta_min, abs_delta_max); |
|
repeat(100) @(posedge clk); |
$stop(2); |
endtask |
|
// |
wire [31:0][31:0] x; |
wire [30:0][31:0] y; |
wire [31:1][31:0] a; |
|
genvar k; |
generate for (k = 0; k < 32; k++) |
begin :gen_x |
assign x[k] = dut.x[k]; |
end |
endgenerate |
|
genvar n; |
generate for (n = 0; n < 31; n++) |
begin :gen_y |
assign y[n] = dut.y[n]; |
end |
endgenerate |
|
genvar m; |
generate for (m = 1; m < 32; m++) |
begin :gen_a |
assign a[m] = dut.a[m]; |
end |
endgenerate |
|
endmodule :cordic_atan_iq_tb |
/cordic_atan_iq/cordic_atan_test.m
0,0 → 1,11
clc |
|
I = 20e6; |
Q = 4e6; |
|
[angle, isqrt] = cordic_atan_iq(20e6, 4e6); |
a = atan(Q/I) * 180 / pi; |
iq_sqrt = int32(sqrt(I^2 + Q^2)); |
delta = iq_sqrt - isqrt; |
|
fprintf('\nAngle MatLab: %g, Cordic: %g; SQRT MatLab: %d, Cordic: %d, delta %d\n', a, angle, iq_sqrt, isqrt, delta); |