OpenCores
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
    /cordic_atan_iq
    from Rev 1 to Rev 2
    Reverse comparison

Rev 1 → Rev 2

/AuxClasses.sv
0,0 → 1,43
`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}}};
 
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
/AuxFunc.sv
0,0 → 1,82
`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 absi(int value);
if (value < 0) value = -value;
return value;
endfunction
 
endpackage :AuxFuncPkg
 
`endif
/atan32_table_gen.m
0,0 → 1,47
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 = %g;\n', k);
fprintf(fid, ' parameter int K_INT = 32''h%08x;\n', int32(round(k * 2^30)));
fprintf(fid, '// for sin and cos start calculation from vector {K_INT, 0}\n');
fprintf(fid, '// last table value dont use for atan calculation\n\n');
 
fprintf(fid, ' 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.m
0,0 → 1,73
 
function angle = 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;
atg_table(1) = int32(1);
 
while i == 0 || atg_table(i) ~= 0
atg_table(i+1) = int32(2^30 * atan(1/2^i) / (pi/2));
i = 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(atg_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) - atg_table(i-1);
fprintf('i = %d: rot = %g deg, ', i-1, -double(atg_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) + atg_table(i-1);
fprintf('i = %d: rot = %g deg, ', i-1, double(atg_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
 
end
/cordic_atan_iq.sv
0,0 → 1,57
`ifndef _cordic_atan_iq_
`define _cordic_atan_iq_
`include "atan32_table.sv"
 
module cordic_atan_iq(clk, IS, QS, angle);
import ConstPkg::atan_table;
localparam STEPS = ConstPkg::STEPS; // todo: add to m gen
 
input wire clk; // todo: clk_ena
input wire signed [29:0] IS, QS;
output reg signed [31:0] angle;
wire sign;
reg [STEPS-1:0] sign_dly;
reg signed [31:0] x[STEPS], y[STEPS]; // + 1 bit for carry
reg signed [31:0] a[STEPS];
assign sign = IS < 'sh0;
always_ff @(posedge clk) begin
x[0] <= (sign) ? 32'sh0 - IS : 32'sh0 + IS;
y[0] <= (sign) ? 32'sh0 - QS : 32'sh0 + QS;
a[0] <= '0;
sign_dly <= {sign_dly[STEPS-2:0], sign}; // remember the sign
end
genvar i;
generate for(i = 1; i < STEPS; 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 (sign_dly[STEPS-1])
if (a[STEPS-1] <= 'sh0)
angle <= {1'b1, 31'h0} - a[STEPS-1];
else
angle <= {1'b0, {31{1'b1}}} - (a[STEPS-1] - 1'b1);
else
angle <= -a[STEPS-1];
 
endmodule : cordic_atan_iq
 
`endif
/cordic_atan_iq_tb.sv
0,0 → 1,108
timeunit 1ns;
timeprecision 1ns;
 
`include "AuxFunc.sv"
`include "AuxClasses.sv"
 
module cordic_atan_iq_tb;
import AuxFuncPkg::*;
import AuxClassesPkg::*;
 
bit clk = 0;
bit signed [29:0] IS, QS;
wire signed [31:0] angle;
int cur_delta, delta_max = 0, 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_int;
IS = I;
QS = Q;
repeat(100) @(posedge clk);
atan_int = atan_iq_int(int'(IS), int'(QS));
cur_delta = delta(atan_int, angle);
pct = rel_pct(atan_int, 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_int), atan_int, int_to_deg(angle), angle, cur_delta, pct);
assert (absi(cur_delta) < 100) else $display("ERROR!");
endtask
task Test2();
int atan_int;
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+2) @(posedge clk);
for (int i = 0; i < v.size(); i++) begin
I = v.data[i].I;
Q = v.data[i].Q;
atan_int = atan_iq_int(I, Q);
cur_delta = delta(atan_int, angle);
if (cur_delta > delta_max) delta_max = cur_delta;
if (cur_delta < delta_min) delta_min = cur_delta;
pct = rel_pct(atan_int, angle);
$display("%d {%08h, %08h}: Ref %g deg (%d), RTL %g deg (%d), delta %d (%g pct)", i, I, Q, int_to_deg(atan_int), atan_int, int_to_deg(angle), angle, cur_delta, pct);
assert (absi(cur_delta) < 100)
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)", delta_min, delta_max, int_to_deg(delta_min) * 60**2, int_to_deg(delta_max) * 60**2);
repeat(100) @(posedge clk);
$stop(2);
endtask
endmodule :cordic_atan_iq_tb
/cordic_atan_test.m
0,0 → 1,4
clc
 
angle = cordic_atan_iq(20e6, 4e6)
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.