Filippo V Filippo V - 16 days ago 5
Apache Configuration Question

How to use complex coefficient in apache FFT

I'm working with a basic example of FFT with Apache Commons library. I have two classes:

public class Fourier {
private static XYSeries data;
private static XYSeriesCollection collection;

Fourier(){
collection =new XYSeriesCollection();
createSquare();
createFourier();
showGraph();
}

private static void createSquare(){
data=new XYSeries("Dati");
for(double i=-8;i<8;i+=1d/128){
data.add(i,((i<-4||(i<4&&i>0)?1:0)));
//data.add(i,(i<0?i+1:-i+1));
}
collection.addSeries(data);
}

private static void createFourier(){
double[] arrayFourier= new double[data.getItemCount()];
for(int i=0;i<data.getItemCount();i++){
arrayFourier[i]=data.getDataItem(i).getYValue();
}
FastFourierTransformer transformer=new FastFourierTransformer(DftNormalization.STANDARD);
Complex[] coeff=transformer.transform(arrayFourier, TransformType.INVERSE);
double norm = 0;
for(Complex Z: coeff){
System.out.println(Z.abs()+"\t"+Z.toString());
norm+=(Z.abs())*(Z.abs());
}
System.out.println(norm);

XYSeries fourier=new XYSeries("Fourier");
FourierSeries series=new FourierSeries(coeff,8);
for(double i=data.getMinX();i<data.getMaxX();i+=0.05){
fourier.add(i,series.getSeries(i));
}
collection.addSeries(fourier);

}

private static void showGraph(){
JFreeChart chart = ChartFactory.createXYLineChart("Fourier", "x", "f(x)", collection, PlotOrientation.VERTICAL, true, false, false);
ChartFrame window=new ChartFrame("Fourier", chart, false);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.pack();
window.setVisible(true);
}

public static void main(String[] args) {
Thread t=new Thread(new Runnable() {

@Override
public void run() {
new Fourier();
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.exit(0);
}
});
t.start();
}

}


and another one

public class FourierSeries {
Complex[] coeff;
double T;

public FourierSeries(Complex[] coeff, double T) {
this.coeff=coeff;
this.T=T;
}

public double getSeries(double x){
double k=Math.PI/T;
double value=0; //primo coefficiente
int i=0;
/*for(Complex iter:coeff){
if (i!=0&&i<coeff.length/2.) {
if (i % 2 == 0) {
value += iter.abs() * Math.cos(k * i * x);
System.out.println(iter.abs()+"cos"+i);
} else {
value += iter.abs() * Math.sin(k * i * x); //npari (i dispari) modulo*cos()
System.out.println(iter.abs()+"sin"+i);
}
}
i++;
}*/
for (Complex iter : coeff) {
if(i<coeff.length/2.)
value+=iter.getReal()*Math.cos(x*k*i)+iter.getImaginary()*Math.sin(x*k*i);
i++;
}
return value;
}
}


I introduce in my
createSquare()
method a function (square wave).

In order I do the following actions:

I perform the FFT.

Can you explain me how the array returned by
transform.transform(array, TransformType)
is composed?

Why the Fourier series is not correctly drawn?

The inverse series is correctly a square wave with same frequency as initial wave, but not correctly scaled on y-axsis. What is wrong? This is the output:
This is the output

Answer

In transforming the complex form of the Fourier series to the real form, you have to treat the constant term differently. Or in the case of the code in question, you have to correct the non-constant coefficients by a factor of 2. So that you get 0.5 +- 0.5 as result, not 0.5 +- 0.25 as is currently the case.

As for index m>=1 you combine two complex conjugate pairs, the resulting real terms are

(a+i*b)*exp(i*m*k*x) + (a-i*b)*exp(-i*m*k*x) 

= 2*a*cos(m*k*x) - 2*b*sin(m*k*x)

your Fourier series computation should look like

    value = coeff[0].getReal();
    for (int m=1; m<coeff.length/2; m++) {
        value += 2*coeff[m].getReal()*Math.cos(x*k*m) 
               - 2*coeff[m].getImaginary()*Math.sin(x*k*m);
    }