siggen: Fix direction of rotation
The I and Q were swapped in sine_tone, which caused confusion and made the rotation of REG_CARTESIAN clockwise by default. This effectively made the resulting frequency negative. This PR makes the I and Q order consistent with RFNoC and fixes the direction of rotation so that a positive value for REG_PHASE_INC (phase increment) results in a counter-clockwise rotation, which yields a positive frequency. Original-commit: 4e6531f30648ede5be8f93fa49fdcd4973b73813
This commit is contained in:
committed by
Aaron Rossetto
parent
ac0f45bb0e
commit
2e9f7b96ee
@@ -21,7 +21,7 @@ module rfnoc_block_siggen_all_tb;
|
||||
rfnoc_block_siggen_tb #(.CHDR_W(64), .NUM_PORTS(3)) test_siggen_2();
|
||||
rfnoc_block_siggen_tb #(.CHDR_W(128), .NUM_PORTS(2)) test_siggen_3();
|
||||
rfnoc_block_siggen_tb #(.CHDR_W(256), .NUM_PORTS(1)) test_siggen_4();
|
||||
|
||||
|
||||
endmodule : rfnoc_block_siggen_all_tb
|
||||
|
||||
|
||||
|
||||
@@ -75,9 +75,9 @@ localparam REG_GAIN_LEN = 16;
|
||||
// real and imaginary components are treated as 16-bit signed fixed point
|
||||
// values with 15 fractional bits.
|
||||
//
|
||||
// [31:16] Real/I component
|
||||
// [15: 0] Imaginary/Q component
|
||||
//
|
||||
// [31:16] X/I/Real component
|
||||
// [15: 0] Y/Q/Imaginary component
|
||||
|
||||
localparam REG_CONSTANT = 'h10;
|
||||
//
|
||||
localparam REG_CONSTANT_LEN = 32;
|
||||
@@ -86,10 +86,11 @@ localparam REG_CONSTANT_LEN = 32;
|
||||
// REG_PHASE_INC (R/W)
|
||||
//
|
||||
// Sets the phase increment, in "scaled radians", for the sine waveform
|
||||
// generator. This is the amount by which REG_CARTESIAN is rotated each clock
|
||||
// cycle. In other words, it controls the rate of rotation, or the frequency,
|
||||
// of the sine wave. The range of the phase value is -1.0 to +1.0. In scaled
|
||||
// radians, the value range -1 to +1 corresponds to -Pi to Pi in radians.
|
||||
// generator. This is the amount by which REG_CARTESIAN is rotated
|
||||
// counter-clockwise each clock cycle. In other words, it controls the rate of
|
||||
// rotation, or the frequency, of the sine wave. The range of the phase value
|
||||
// is -1.0 to +1.0. In scaled radians, the value range -1 to +1 corresponds to
|
||||
// -Pi to Pi in radians.
|
||||
//
|
||||
// In other words, the normalized frequency (in cycles/sample) of the
|
||||
// sinusoidal output is equal to 0.5*REG_PHASE_INC.
|
||||
@@ -123,11 +124,11 @@ localparam REG_PHASE_INC_LEN = 16;
|
||||
// fixed point with 2 integer and 14 fractional bits, which is accurate.
|
||||
// However, since we treat the output as sc16 (15 fractional bits), we need to
|
||||
// double the value of the CARTESIAN inputs to get the output we want for sc16.
|
||||
// This is mathematically inequivalent to simply saying the CARTESIAN inputs
|
||||
// have 15 fractional bits instead of 14.
|
||||
// This is mathematically equivalent to simply saying the CARTESIAN inputs have
|
||||
// 15 fractional bits instead of 14.
|
||||
//
|
||||
// [31:16] : Y (Imaginary) component
|
||||
// [15: 0] : X (Real) component
|
||||
// [31:16] : X/I/Real component
|
||||
// [15: 0] : Y/Q/Imaginary component
|
||||
//
|
||||
localparam REG_CARTESIAN = 'h18;
|
||||
//
|
||||
|
||||
@@ -54,7 +54,7 @@ module rfnoc_block_siggen_tb #(
|
||||
|
||||
// Maximum real (floating point) values allowed for the different fixed
|
||||
// point formats (for range checking). All of the fixed point values are
|
||||
// signed 16-bit.
|
||||
// signed 16-bit.
|
||||
localparam real MAX_GAIN_R = (2.0**15-1) / (2.0**GAIN_FRAC);
|
||||
localparam real MIN_GAIN_R = -(2.0**15) / (2.0**GAIN_FRAC);
|
||||
localparam real MAX_CONST_R = (2.0**15-1) / (2.0**CONST_FRAC);
|
||||
@@ -242,7 +242,9 @@ module rfnoc_block_siggen_tb #(
|
||||
endfunction : fixed_to_real
|
||||
|
||||
|
||||
// Compute the next sine value we expect based on the previous
|
||||
// Compute the next sine value we expect based on the previous. This should
|
||||
// be a point (X,Y) rotated counter-clockwise around the origin, where X is
|
||||
// in the MSBs and Y is in the LSBs.
|
||||
function automatic logic [31:0] next_sine_value(
|
||||
logic [31:0] sample,
|
||||
logic [15:0] phase_inc
|
||||
@@ -252,10 +254,10 @@ module rfnoc_block_siggen_tb #(
|
||||
y = fixed_to_real(sample[15: 0], CART_FRAC);
|
||||
phase = fixed_to_real(phase_inc, PHASE_FRAC) * PI;
|
||||
|
||||
// Compute the rotated coordinates
|
||||
new_x = x*$cos(phase) + y*$sin(phase);
|
||||
new_y = -x*$sin(phase) + y*$cos(phase);
|
||||
|
||||
// Compute the counter-clockwise rotated coordinates
|
||||
new_x = x*$cos(phase) - y*$sin(phase);
|
||||
new_y = x*$sin(phase) + y*$cos(phase);
|
||||
|
||||
return { real_to_fixed(new_x, CART_FRAC), real_to_fixed(new_y, CART_FRAC) };
|
||||
endfunction : next_sine_value
|
||||
|
||||
@@ -320,7 +322,7 @@ module rfnoc_block_siggen_tb #(
|
||||
end
|
||||
|
||||
// Dump all the packets that were received
|
||||
while (blk_ctrl.num_received(port)) begin
|
||||
while (blk_ctrl.num_received(port)) begin
|
||||
blk_ctrl.recv_items(port, items);
|
||||
end
|
||||
endtask : flush_output
|
||||
@@ -376,7 +378,7 @@ module rfnoc_block_siggen_tb #(
|
||||
int spp = SPP,
|
||||
logic signed [15:0] const_re = 16'h7FFF, // 0.99997
|
||||
logic signed [15:0] const_im = 16'h7FFF, // 0.99997
|
||||
logic signed [15:0] phase_inc = real_to_fixed(0.5, 13), //real_to_fixed(2.0/16, 13), // 2*pi/16 radians
|
||||
logic signed [15:0] phase_inc = real_to_fixed(2.0/16, 13), // 2*pi/16 radians
|
||||
logic signed [15:0] cart_x = real_to_fixed(1.0, 14),
|
||||
logic signed [15:0] cart_y = real_to_fixed(0.0, 14)
|
||||
);
|
||||
@@ -387,7 +389,7 @@ module rfnoc_block_siggen_tb #(
|
||||
write_reg(port, REG_CONSTANT, {const_re, const_im});
|
||||
end else if (mode == WAVE_SINE) begin
|
||||
write_reg(port, REG_PHASE_INC, phase_inc);
|
||||
write_reg(port, REG_CARTESIAN, {cart_y, cart_x});
|
||||
write_reg(port, REG_CARTESIAN, {cart_x, cart_y});
|
||||
end
|
||||
write_reg(port, REG_ENABLE, 1);
|
||||
|
||||
@@ -400,7 +402,7 @@ module rfnoc_block_siggen_tb #(
|
||||
|
||||
// Verify the length
|
||||
`ASSERT_ERROR(
|
||||
items.size() == spp,
|
||||
items.size() == spp,
|
||||
"Packet length didn't match configured SPP"
|
||||
);
|
||||
|
||||
@@ -447,7 +449,7 @@ module rfnoc_block_siggen_tb #(
|
||||
);
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -596,7 +598,7 @@ module rfnoc_block_siggen_tb #(
|
||||
|
||||
max_val = 16'sh7FFF;
|
||||
min_val = 16'sh8000;
|
||||
|
||||
|
||||
// Test max gain with min and max sample values
|
||||
run_waveform(.port(port), .mode(WAVE_CONST), .gain(max_val),
|
||||
.const_re(max_val), .const_im(min_val));
|
||||
@@ -610,7 +612,7 @@ module rfnoc_block_siggen_tb #(
|
||||
run_waveform(
|
||||
.port(port),
|
||||
.mode(WAVE_CONST),
|
||||
.const_re(real_to_fixed(0.5, CONST_FRAC)),
|
||||
.const_re(real_to_fixed(0.5, CONST_FRAC)),
|
||||
.const_im(real_to_fixed(0.25, CONST_FRAC)),
|
||||
.gain(real_to_fixed(0.5, GAIN_FRAC))
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user