June 2018 Update
This commit is contained in:
parent
ba8067c3b7
commit
22f33d4004
5278 changed files with 84726 additions and 14379 deletions
10
Task/Fast-Fourier-transform/APL/fast-fourier-transform-1.apl
Normal file
10
Task/Fast-Fourier-transform/APL/fast-fourier-transform-1.apl
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fft←{
|
||||
N←⍴⍵
|
||||
N≤1:⍵
|
||||
(1|2⍟N)≠0:'Argument must be a power of 2 in length'
|
||||
even←fft(N⍴0 1)/⍵
|
||||
odd←fft(N⍴1 0)/⍵
|
||||
k←N÷2
|
||||
T←even×*(0J¯2×(○1)×(¯1+⍳k)÷N)
|
||||
(odd+T),odd-T
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
fft 1 1 1 1 0 0 0 0
|
||||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue