Just another update

This commit is contained in:
Ingy döt Net 2015-02-20 00:35:01 -05:00
parent a25938f123
commit 00a190b0a6
6591 changed files with 94363 additions and 23227 deletions

View file

@ -1 +1,10 @@
The purpose of this task is to calculate the FFT (Fast Fourier Transform) of an input sequence. The most general case allows for complex numbers at the input and results in a sequence of equal length, again of complex numbers. If you need to restrict yourself to real numbers the output should be the magnitude (i.e. sqrt(re²+im²)) of the complex result. The classic version is the recursive CooleyTukey FFT. [http://en.wikipedia.org/wiki/CooleyTukey_FFT_algorithm Wikipedia] has pseudocode for that. Further optimizations are possible but not required.
{{omit from|GUISS}}
The purpose of this task is to calculate the FFT (Fast Fourier Transform)
of an input sequence. <br>
The most general case allows for complex numbers at the input
and results in a sequence of equal length, again of complex numbers.
If you need to restrict yourself to real numbers, the output should
be the magnitude (i.e. sqrt(re²+im²)) of the complex result.
The classic version is the recursive CooleyTukey FFT. [http://en.wikipedia.org/wiki/CooleyTukey_FFT_algorithm Wikipedia] has pseudocode for that.
Further optimizations are possible but not required.

View file

@ -0,0 +1,50 @@
#include <stdio.h>
#include <math.h>
#include <complex.h>
double PI;
typedef double complex cplx;
void _fft(cplx buf[], cplx out[], int n, int step)
{
if (step < n) {
_fft(out, buf, n, step * 2);
_fft(out + step, buf + step, n, step * 2);
for (int i = 0; i < n; i += 2 * step) {
cplx t = cexp(-I * PI * i / n) * out[i + step];
buf[i / 2] = out[i] + t;
buf[(i + n)/2] = out[i] - t;
}
}
}
void fft(cplx buf[], int n)
{
cplx out[n];
for (int i = 0; i < n; i++) out[i] = buf[i];
_fft(buf, out, n, 1);
}
void show(const char * s, cplx buf[]) {
printf("%s", s);
for (int i = 0; i < 8; i++)
if (!cimag(buf[i]))
printf("%g ", creal(buf[i]));
else
printf("(%g, %g) ", creal(buf[i]), cimag(buf[i]));
}
int main()
{
PI = atan2(1, 1) * 4;
cplx buf[] = {1, 1, 1, 1, 0, 0, 0, 0};
show("Data: ", buf);
fft(buf, 8);
show("\nFFT : ", buf);
return 0;
}

View file

@ -1,5 +1,5 @@
import std.stdio, std.numeric;
void main() {
import std.stdio, std.numeric;
[1.0, 1, 1, 1, 0, 0, 0, 0].fft.writeln;
}

View file

@ -1,6 +1,6 @@
import std.stdio, std.algorithm, std.range, std.math;
const(creal)[] fft(in creal[] x) /*pure nothrow*/ {
const(creal)[] fft(in creal[] x) pure /*nothrow*/ @safe {
immutable N = x.length;
if (N <= 1) return x;
const ev = x.stride(2).array.fft;
@ -10,6 +10,6 @@ const(creal)[] fft(in creal[] x) /*pure nothrow*/ {
return l.chain(r).array;
}
void main() {
void main() @safe {
[1.0L+0i, 1, 1, 1, 0, 0, 0, 0].fft.writeln;
}

View file

@ -1,13 +1,13 @@
import std.stdio, std.algorithm, std.range, std.math, std.complex;
auto fft(T)(in T[] x) /*pure nothrow*/ {
auto fft(T)(in T[] x) pure /*nothrow @safe*/ {
immutable N = x.length;
if (N <= 1) return x;
const ev = x.stride(2).array.fft;
const od = x[1 .. $].stride(2).array.fft;
alias E = std.complex.expi;
auto l = iota(N / 2).map!(k=> ev[k] + cast(T)E(-2*PI*k/N) * od[k]);
auto r = iota(N / 2).map!(k=> ev[k] - cast(T)E(-2*PI*k/N) * od[k]);
auto l = iota(N / 2).map!(k => ev[k] + T(E(-2* PI * k/N)) * od[k]);
auto r = iota(N / 2).map!(k => ev[k] - T(E(-2* PI * k/N)) * od[k]);
return l.chain(r).array;
}

View file

@ -0,0 +1,66 @@
/*
complex fast fourier transform and inverse from
http://rosettacode.org/wiki/Fast_Fourier_transform#C.2B.2B
*/
function icfft(amplitudes)
{
var N = amplitudes.length;
var iN = 1 / N;
//conjugate if imaginary part is not 0
for(var i = 0 ; i < N; ++i)
if(amplitudes[i] instanceof Complex)
amplitudes[i].im = -amplitudes[i].im;
//apply fourier transform
amplitudes = cfft(amplitudes)
for(var i = 0 ; i < N; ++i)
{
//conjugate again
amplitudes[i].im = -amplitudes[i].im;
//scale
amplitudes[i].re *= iN;
amplitudes[i].im *= iN;
}
return amplitudes;
}
function cfft(amplitudes)
{
var N = amplitudes.length;
if( N <= 1 )
return amplitudes;
var hN = N / 2;
var even = [];
var odd = [];
even.length = hN;
odd.length = hN;
for(var i = 0; i < hN; ++i)
{
even[i] = amplitudes[i*2];
odd[i] = amplitudes[i*2+1];
}
even = cfft(even);
odd = cfft(odd);
var a = -2*Math.PI;
for(var k = 0; k < hN; ++k)
{
if(!(even[k] instanceof Complex))
even[k] = new Complex(even[k], 0);
if(!(odd[k] instanceof Complex))
odd[k] = new Complex(odd[k], 0);
var p = k/N;
var t = new Complex(0, a * p);
t.cexp(t).mul(odd[k], t);
amplitudes[k] = even[k].add(t, odd[k]);
amplitudes[k + hN] = even[k].sub(t, even[k]);
}
return amplitudes;
}
//test code
//console.log( cfft([1,1,1,1,0,0,0,0]) );
//console.log( icfft(cfft([1,1,1,1,0,0,0,0])) );

View file

@ -0,0 +1,50 @@
/*
basic complex number arithmetic from
http://rosettacode.org/wiki/Fast_Fourier_transform#Scala
*/
function Complex(re, im)
{
this.re = re;
this.im = im || 0.0;
}
Complex.prototype.add = function(other, dst)
{
dst.re = this.re + other.re;
dst.im = this.im + other.im;
return dst;
}
Complex.prototype.sub = function(other, dst)
{
dst.re = this.re - other.re;
dst.im = this.im - other.im;
return dst;
}
Complex.prototype.mul = function(other, dst)
{
//cache re in case dst === this
var r = this.re * other.re - this.im * other.im;
dst.im = this.re * other.im + this.im * other.re;
dst.re = r;
return dst;
}
Complex.prototype.cexp = function(dst)
{
var er = Math.exp(this.re);
dst.re = er * Math.cos(this.im);
dst.im = er * Math.sin(this.im);
return dst;
}
Complex.prototype.log = function()
{
/*
although 'It's just a matter of separating out the real and imaginary parts of jw.' is not a helpful quote
the actual formula I found here and the rest was just fiddling / testing and comparing with correct results.
http://cboard.cprogramming.com/c-programming/89116-how-implement-complex-exponential-functions-c.html#post637921
*/
if( !this.re )
console.log(this.im.toString()+'j');
else if( this.im < 0 )
console.log(this.re.toString()+this.im.toString()+'j');
else
console.log(this.re.toString()+'+'+this.im.toString()+'j');
}

View file

@ -1,9 +1,8 @@
sub fft {
return @_ if @_ == 1;
my @evn = fft( @_[0,2...^* >= @_] );
my @odd = fft( @_[1,3...^* >= @_] );
my $twd = 2i * pi / @_; # twiddle factor
@odd[$_] *= exp( $_ * $twd ) for ^@odd;
my @evn = fft( @_[0, 2 ... *] );
my @odd = fft( @_[1, 3 ... *] ) Z*
(1, * * cis( 2 * pi / @_ ) ... *);
return @evn »+« @odd, @evn »-« @odd;
}

View file

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

View file

@ -3,9 +3,11 @@ from cmath import exp, pi
def fft(x):
N = len(x)
if N <= 1: return x
even = fft(x[0::2])
odd = fft(x[1::2])
return [even[k] + exp(-2j*pi*k/N)*odd[k] for k in xrange(N/2)] + \
[even[k] - exp(-2j*pi*k/N)*odd[k] for k in xrange(N/2)]
even = fft2(x[0::2])
odd = fft2(x[1::2])
T= [exp(-2j*pi*k/N)*odd[k] for k in xrange(N/2)]
return [even[k] + T[k] for k in xrange(N/2)] + \
[even[k] - T[k] for k in xrange(N/2)]
print fft([1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0])
print( ' '.join("%5.3f" % abs(f)
for f in fft([1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0])) )

View file

@ -1,5 +1,5 @@
>>> from numpy.fft import fft
>>> from numpy import array
>>> a = array((0.0, 0.924, 0.707, -0.383, -1.0, -0.383, 0.707, 0.924, 0.0, -0.924, -0.707, 0.383, 1.0, 0.383, -0.707, -0.924))
>>> a = array([1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0])
>>> print( ' '.join("%5.3f" % abs(f) for f in fft(a)) )
0.000 0.001 0.000 8.001 0.000 0.001 0.000 0.001 0.000 0.001 0.000 0.001 0.000 8.001 0.000 0.001
4.000 2.613 0.000 1.082 0.000 1.082 0.000 2.613

View file

@ -1,56 +1,60 @@
/*REXX pgm does a fast Fourier transform (FFT) on a set of complex nums.*/
numeric digits length( pi() ) - 1 /*limited by PI function result. */
arg data; if data='' then data='1 1 1 1 0' /*no data? Then use default*/
data=translate(data, 'J', "I") /*allow use of i as well as j */
arg data /*the ARG verb uppercases DATA */
if data='' then data=1 1 1 1 0 /*No data? Then use the default.*/
data=translate(data, 'J', "I") /*allow use of I as well as J */
size=words(data); pad=left('',6) /*PAD: for indenting/padding SAYs*/
do sig=0 until 2**sig>=size ;end /* # args exactly a power of 2?*/
do j=size+1 to 2**sig;data=data 0;end /*add zeroes until a power of 2.*/
size=words(data); call hdr /*┌─────────────────────────────┐*/
do p=0 until 2**p>=size ; end /* # args exactly a power of 2? */
do j=size+1 to 2**p;data=data 0; end /*add zeroes until a power of 2. */
size=words(data); ph=p%2; call hdr /*┌─────────────────────────────┐*/
/*│ Numbers in data can be in │*/
do j=0 for size /*│ 7 formats: real │*/
_=word(data,j+1) /*│ real,imag │*/
parse var _ #.1.j ',' #.2.j /*│ ,imag │*/
if right(#.1.j,1)=='J' then /*│ nnnJ │*/
parse var #.1.j #2.j "J" @.1.j /*│ nnnj │*/
do p=1 for 2 /*omitted?*/ /*│ nnnI │*/
#.p.j=word(#.p.j 0, 1) /*│ nnni │*/
end /*p*/ /*└─────────────────────────────┘*/
parse var _ #.1.j ',' #.2.j /*│ ,imag │*/
if right(#.1.j,1)=='J' then parse , /*│ nnnJ │*/
var #.1.j #2.j "J" @.1.j /*│ nnnj │*/
do m=1 for 2 /*omitted?*/ /*│ nnnI │*/
#.m.j=word(#.m.j 0, 1) /*│ nnni │*/
end /*m*/ /*└─────────────────────────────┘*/
say pad " FFT in " center(j+1,7) pad nice(#.1.j) nice(#.2.j,'i')
end /*j*/
say; say; tran=2*pi()/2**sig; !.=0
hsig=2**sig%2; counterA=2**(sig-sig%2); pointer=counterA; doubler=1
say; say; tran=2*pi()/2**p; !.=0
hp=2**p%2; counterA=2**(p-ph); pointer=counterA; doubler=1
do p-ph; halfpointer=pointer%2
do sig-sig%2; halfpointer=pointer%2
do i=halfpointer by pointer to counterA-halfpointer
_=i-halfpointer; !.i=!._+doubler
_=i-halfpointer; !.i=!._+doubler
end /*i*/
doubler=doubler*2; pointer=halfpointer
end /*sig-sig%2*/
do j=0 to 2**sig%4; cmp.j=cos(j*tran); _m=hsig-j; cmp._m=-cmp.j
_p=hsig+j; cmp._p=-cmp.j
end /*j*/
doubler=doubler*2; pointer=halfpointer
end /*p-ph*/
counterB=2**(sig%2)
do j=0 to 2**p%4; cmp.j=cos(j*tran); _m=hp-j; cmp._m=-cmp.j
_p=hp+j; cmp._p=-cmp.j
end /*j*/
do i=0 for counterA; p=i*counterB
do j=0 for counterB; h=p+j; _=!.j*counterB+!.i; if _<=h then iterate
counterB=2**ph
do i=0 for counterA; q=i *counterB
do j=0 for counterB; h=q+j; _=!.j*counterB+!.i; if _<=h then iterate
parse value #.1._ #.1.h #.2._ #.2.h with #.1.h #.1._ #.2.h #.2._
end /*j*/ /* [↓] switch two sets of values*/
end /*j*/ /* [] switch two sets of values*/
end /*i*/
double=1; do sig ; w=2**sig%2%double
do k=0 for double ; lb=w*k ; lh=lb+2**sig%4
do j=0 for w ; a=j*double*2+k ; b=a+double
r=#.1.a; i=#.2.a ; c1=cmp.lb*#.1.b ; c4=cmp.lb*#.2.b
c2=cmp.lh*#.2.b ; c3=cmp.lh*#.1.b
#.1.a=r+c1-c2 ; #.2.a=i+c3+c4
#.1.b=r-c1+c2 ; #.2.b=i-c3-c4
double=1; do p ; w=hp%double
do k=0 for double; lb=w*k ; lh=lb+2**p%4
do j=0 for w ; a=j*double*2+k ; b=a+double
r=#.1.a; i=#.2.a ; c1=cmp.lb*#.1.b ; c4=cmp.lb*#.2.b
c2=cmp.lh*#.2.b ; c3=cmp.lh*#.1.b
#.1.a=r+c1-c2 ; #.2.a=i+c3+c4
#.1.b=r-c1+c2 ; #.2.b=i-c3-c4
end /*j*/
end /*k*/
double=double+double
end /*sig*/
end /*p*/
call hdr
do i=0 for size
say pad " FFT out " center(i+1,7) pad nice(#.1.i) nice(#.2.i,'j')

View file

@ -0,0 +1,3 @@
#lang racket
(require math)
(array-fft (array #[1. 1. 1. 1. 0. 0. 0. 0.]))

View file

@ -3,8 +3,8 @@ def fft(vec)
evens_odds = vec.partition.with_index{|_,i| i.even?}
evens, odds = evens_odds.map{|even_odd| fft(even_odd)*2}
evens.zip(odds).map.with_index do |(even, odd),i|
even + odd * Math::E ** Complex(0, 2 * Math::PI * (-i)/ vec.size)
even + odd * Math::E ** Complex(0, -2 * Math::PI * i / vec.size)
end
end
fft([1,1,1,1,0,0,0,0]).each{|c| p c}
fft([1,1,1,1,0,0,0,0]).each{|c| puts "%9.6f %+9.6fi" % c.rect}

View file

@ -0,0 +1,25 @@
import scala.math.{ Pi, cos, sin, cosh, sinh, abs }
case class Complex(re: Double, im: Double) {
def +(x: Complex): Complex = Complex(re + x.re, im + x.im)
def -(x: Complex): Complex = Complex(re - x.re, im - x.im)
def *(x: Double): Complex = Complex(re * x, im * x)
def *(x: Complex): Complex = Complex(re * x.re - im * x.im, re * x.im + im * x.re)
def /(x: Double): Complex = Complex(re / x, im / x)
override def toString(): String = {
val a = "%1.3f" format re
val b = "%1.3f" format abs(im)
(a,b) match {
case (_, "0.000") => a
case ("0.000", _) => b + "i"
case (_, _) if im > 0 => a + " + " + b + "i"
case (_, _) => a + " - " + b + "i"
}
}
}
def exp(c: Complex) : Complex = {
val r = (cosh(c.re) + sinh(c.re))
Complex(cos(c.im), sin(c.im)) * r
}

View file

@ -0,0 +1,25 @@
def _fft(cSeq: Seq[Complex], direction: Complex, scalar: Int): Seq[Complex] = {
if (cSeq.length == 1) {
return cSeq
}
val n = cSeq.length
assume(n % 2 == 0, "The Cooley-Tukey FFT algorithm only works when the length of the input is even.")
val evenOddPairs = cSeq.grouped(2).toSeq
val evens = _fft(evenOddPairs map (_(0)), direction, scalar)
val odds = _fft(evenOddPairs map (_(1)), direction, scalar)
def leftRightPair(k: Int): Pair[Complex, Complex] = {
val base = evens(k) / scalar
val offset = exp(direction * (Pi * k / n)) * odds(k) / scalar
(base + offset, base - offset)
}
val pairs = (0 until n/2) map leftRightPair
val left = pairs map (_._1)
val right = pairs map (_._2)
left ++ right
}
def fft(cSeq: Seq[Complex]): Seq[Complex] = _fft(cSeq, Complex(0, 2), 1)
def rfft(cSeq: Seq[Complex]): Seq[Complex] = _fft(cSeq, Complex(0, -2), 2)

View file

@ -0,0 +1,5 @@
val data = Seq(Complex(1,0), Complex(1,0), Complex(1,0), Complex(1,0),
Complex(0,0), Complex(0,2), Complex(0,0), Complex(0,0))
println(fft(data))
println(rfft(fft(data)))

View file

@ -1,32 +0,0 @@
object FFT extends App {
import scala.math._
case class Complex(re: Double, im: Double = 0.0) {
def +(x: Complex): Complex = Complex((this.re+x.re),(this.im+x.im))
def -(x: Complex): Complex = Complex((this.re-x.re),(this.im-x.im))
def *(x: Complex): Complex = Complex(this.re*x.re-this.im*x.im,this.re*x.im+this.im*x.re)
}
def fft(f: List[Complex]): List[Complex] = {
import Stream._
require((f.size==0)||(from(0) map {x=>pow(2,x).toInt}).takeWhile(_<2*f.size).toList.exists(_==f.size)==true,"list size "+f.size+" not allowed!")
f.size match {
case 0 => Nil
case 1 => f
case n => {
val cis: Double => Complex = phi => Complex(cos(phi),sin(phi))
val e = fft(f.zipWithIndex.filter(_._2%2==0).map(_._1))
val o = fft(f.zipWithIndex.filter(_._2%2!=0).map(_._1))
import scala.collection.mutable.ListBuffer
val lb = new ListBuffer[Pair[Int, Complex]]()
for (k <- 0 to n/2-1) {
lb += Pair(k,e(k)+o(k)*cis(-2*Pi*k/n))
lb += Pair(k+n/2,e(k)-o(k)*cis(-2*Pi*k/n))
}
lb.toList.sortWith((x,y)=>x._1<y._1).map(_._2)
}
}
}
fft(List(Complex(1),Complex(1),Complex(1),Complex(1),Complex(0),Complex(0),Complex(0),Complex(0))).foreach(println)
}