June 2018 Update

This commit is contained in:
Ingy döt Net 2018-06-22 20:57:24 +00:00
parent ba8067c3b7
commit 22f33d4004
5278 changed files with 84726 additions and 14379 deletions

View file

@ -0,0 +1,10 @@
fft{
N
N1:
(1|2N)0:'Argument must be a power of 2 in length'
evenfft(N0 1)/
oddfft(N1 0)/
kN÷2
Teven×*(0J¯2×(1)×(¯1+k)÷N)
(odd+T),odd-T
}

View file

@ -0,0 +1 @@
fft 1 1 1 1 0 0 0 0

View file

@ -7,7 +7,7 @@ sub fft {
my @evn = fft(@_[grep { not $_ % 2 } 0 .. $#_ ]);
my @odd = fft(@_[grep { $_ % 2 } 1 .. $#_ ]);
my $twd = 2*i* pi / @_;
$odd[$_] *= exp( $_ * $twd ) for 0 .. $#odd;
$odd[$_] *= exp( $_ * -$twd ) for 0 .. $#odd;
return
(map { $evn[$_] + $odd[$_] } 0 .. $#evn ),
(map { $evn[$_] - $odd[$_] } 0 .. $#evn );

View file

@ -0,0 +1,8 @@
clear
set obs 4
gen t=_n
gen x=_n
gen y=0
tsset t
fft y x, gen(v u)
list u v, noobs

View file

@ -0,0 +1,90 @@
/// @Author: Alexandre Felipe (o.alexandre.felipe@gmail.com)
/// @Date: 2018-Jan-25
///
package math_pkg;
// Inspired by the post
// https://community.cadence.com/cadence_blogs_8/b/fv/posts/create-a-sine-wave-generator-using-systemverilog
// import functions directly from C library
//import dpi task C Name = SV function name
import "DPI" pure function real cos (input real rTheta);
import "DPI" pure function real sin(input real y);
import "DPI" pure function real atan2(input real y, input real x);
endpackage : math_pkg
// Encapsulates the functions in a parameterized class
// The FFT is implemented using floating point arithmetic (systemverilog real)
// Complex values are represented as a real vector [1:0], the index 0 is the real part
// and the index 1 is the imaginary part.
class fft_fp #(
parameter LOG2_NS = 7,
parameter NS = 1<<LOG2_NS
);
static function void bit_reverse_order(input real buffer_in[0:NS-1][1:0], output real buffer[0:NS-1][1:0]);
begin
for(reg [LOG2_NS:0] j = 0; j < NS; j = j + 1) begin
reg [LOG2_NS-1:0] ij;
ij = {<<{j[LOG2_NS-1:0]}}; // Right to left streaming
buffer[j][0] = buffer_in[ij][0];
buffer[j][1] = buffer_in[ij][1];
end
end
endfunction
// SystemVerilog FFT implementation translated from Java
static function void transform(input real buffer_in[0:NS-1][1:0], output real buffer[0:NS-1][1:0]);
begin
static real pi = math_pkg::atan2(0.0, -1.0);
bit_reverse_order(buffer_in, buffer);
for(int N = 2; N <= NS; N = N << 1) begin
for(int i = 0; i < NS; i = i + N) begin
for(int k =0; k < N/2; k = k + 1) begin
int evenIndex;
int oddIndex;
real theta;
real wr, wi;
real zr, zi;
evenIndex = i + k;
oddIndex = i + k + (N/2);
theta = (-2.0*pi*k/real'(N));
// Call to the DPI C functions
// (it could be memorized to save some calls but I dont think it worthes)
// w = exp(-2j*pi*k/N);
wr = math_pkg::cos(theta);
wi = math_pkg::sin(theta);
// x = w * buffer[oddIndex]
zr = buffer[oddIndex][0] * wr - buffer[oddIndex][1] * wi;
zi = buffer[oddIndex][0] * wi + buffer[oddIndex][1] * wr;
// update oddIndex before evenIndex
buffer[ oddIndex][0] = buffer[evenIndex][0] - zr;
buffer[ oddIndex][1] = buffer[evenIndex][1] - zi;
// because evenIndex is in the rhs
buffer[evenIndex][0] = buffer[evenIndex][0] + zr;
buffer[evenIndex][1] = buffer[evenIndex][1] + zi;
end
end
end
end
endfunction
// Implements the inverse FFT using the following identity
// ifft(x) = conj(fft(conj(x))/NS;
static function void invert(input real buffer_in[0:NS-1][1:0], output real buffer[0:NS-1][1:0]);
real tmp[0:NS-1][1:0];
begin
// Conjugates the input
for(int i = 0; i < NS; i = i + 1) begin
tmp[i][0] = buffer_in[i][0];
tmp[i][1] = -buffer_in[i][1];
end
transform(tmp, buffer);
// Conjugate and scale the output
for(int i = 0; i < NS; i = i + 1) begin
buffer[i][0] = buffer[i][0]/NS;
buffer[i][1] = -buffer[i][1]/NS;
end
end
endfunction
endclass

View file

@ -0,0 +1,23 @@
/// @Author: Alexandre Felipe (o.alexandre.felipe@gmail.com)
/// @Date: 2018-Jan-25
///
module fft_model_sanity;
initial begin
real x[0:7][1:0]; // input data
real X[0:7][1:0]; // transformed data
real y[0:7][1:0]; // inverted data
for(int i = 0; i < 8; i = i + 1)x[i][0] = 0.0;
for(int i = 4; i < 8; i = i + 1)x[i][1] = 0.0;
for(int i = 0; i < 4; i = i + 1)x[i][0] = 1.0;
fft_fp #(.LOG2_NS(3), .NS(8))::transform(x, X);
$display("Direct FFT");
for(int i = 0; i < 8; i = i + 1) begin
$display("(%f, %f)", X[i][0], X[i][1]);
end
$display("Inverse FFT");
fft_fp #(.LOG2_NS(3), .NS(8))::invert(X, y);
for(int i = 0; i < 8; i = i + 1) begin
$display("(%f, %f)", y[i][0], y[i][1]);
end
end
endmodule

View file

@ -0,0 +1,52 @@
/// @Author: Alexandre Felipe (o.alexandre.felipe@gmail.com)
/// @Date: 2018-Jan-25
///
class fft_definition_checker #(
parameter LOG2_NS = 3,
parameter NS = 1<<LOG2_NS,
parameter NB = 10);
rand logic [NB:0] x_bits[0:NS-1][1:0];
static real TWO_PI = 2.0*math_pkg::atan2(0.0, -1.0);
real w[0:NS-1][1:0];
function new;
foreach(w[i]) begin
w[i][0] = math_pkg::cos(TWO_PI * i / real'(NS));
w[i][1] =-math_pkg::sin(TWO_PI * i / real'(NS));
end
endfunction
function void post_randomize;
real x[0:NS-1][1:0];
real X[0:NS-1][1:0];
real X_ref[0:NS-1][1:0];
real errorEnergy;
begin
// Convert randomized binary numbers to real (floating point)
foreach(x_bits[i]) begin
x[i][0] = x_bits[i][0];
x[i][1] = x_bits[i][1];
end
//// START THE MAGIC HERE ////
fft_fp #(.LOG2_NS(LOG2_NS), .NS(NS))::transform(x, X);
//// END OF THE MAGIC ////
/// Calculate X_ref, the discrete Fourier transform by the definition ///
foreach(X_ref[k]) begin
X_ref[k] = '{0.0, 0.0};
foreach(x[i]) begin
X_ref[k][0] = X_ref[k][0] + x[i][0] * w[(i*k) % NS][0] - x[i][1] * w[(i*k) % NS][1];
X_ref[k][1] = X_ref[k][1] + x[i][0] * w[(i*k) % NS][1] + x[i][1] * w[(i*k) % NS][0];
end
end
// Measure the error
errorEnergy = 0.0;
foreach(X[k]) begin
errorEnergy = errorEnergy + (X_ref[k][0] - X[k][0]) * (X_ref[k][0] - X[k][0]);
errorEnergy = errorEnergy + (X_ref[k][1] - X[k][1]) * (X_ref[k][1] - X[k][1]);
end
$display("FFT of %d integers %d bits (error @ %g)", NS, NB, errorEnergy / real'(NS));
end
endfunction
endclass

View file

@ -0,0 +1,14 @@
/// @Author: Alexandre Felipe (o.alexandre.felipe@gmail.com)
/// @Date: 2018-Jan-25
///
module fft_test_by_definition;
genvar LOG2_NS;
generate for(LOG2_NS = 3; LOG2_NS < 7; LOG2_NS = LOG2_NS + 1) begin
initial begin
fft_definition_checker #(.NB(10), .LOG2_NS(LOG2_NS), .NS(1<<LOG2_NS)) chkInst;
chkInst = new;
repeat(5) assert(chkInst.randomize()); // randomize and check the outputs
end
end
endgenerate
endmodule