Fourier Transformed Graphic

My work is finally DONE!
After a week and a half of head scratching, troubleshooting, debugging and hard-coding through this problem, I’ve finally come up with the 1.0 version of my Fourier transformed series grapher.

This program allows you to have a random pull of N complex values (I had to code a little Cmplx function in order to make it work) and it can draw the graphic of two functions:

  • the periodic function that is related to the Fourier series of that pull of numbers;
  • the graph of the Fourier transform that rounds about N complex vectors, that round about each other with the same frequency

But I think that seeing it working is much, much better and explicative than words: so here’s a little image of the working program for you:


The graph on the left circles about itself, drawing the first red line, meanwhile the green line draws the waveform of the function itself, so you can visualize both the series (on the right) and the transform (on the left).

Here’s the actual code, split into 2 different files:

First file:


//if you want to modify the number of periodic wave that are combined
//into the Fourier series, you'll change the value of the "startDim" variable

float time=TWO_PI, tOff=0;
static int startDim=13, offset=550;
float[] yVals=new float[startDim];
Cmplx[] vals, funct=new Cmplx[startDim], wave=new Cmplx[startDim];

void keyTyped() {

  //to change the rotation frequency (time)
  if (key=='w') tOff+=0.005;
  if (key=='s') tOff-=0.005;
}

void setup() {

  size(1300, 1000);
  noFill();
  for (int a=0; a<startDim; a++) {

    //setting up the arrays
    wave[a]=new Cmplx();
    yVals[a]=(noise((2.36*a)/31)*pow(a, 3)-5*a)/startDim;
    funct[a]=new Cmplx((noise(5.41*a-0.04)-pow(5*a, 2)+4.52*a)/startDim, yVals[a]);
  }

  //calculating the Discrete Fourier transform of the complex values set
  vals=dft(funct);
}

//this function draws the left side of the graph, but not the function itself
//also, it calculates the X/Y values that the function will assume as a function of the time
Cmplx fourierDraw(float x, float y, Cmplx[] f, float t) {

  for (int i=0; i<f.length; i++) {

    float pX=x, pY=y, n=f[i].freq, r=f[i].amp;
    x+=r*cos(n*t+f[i].phase);
    y-=r*sin(n*t+f[i].phase);

    //draw every circle
    stroke(200);
    circle(pX, pY, r*2);

    //draw the rotating radius
    stroke(0, 0, 255);
    fill(0, 0, 255);
    line(pX, pY, x, y);
    circle(x, y, 2);
    noFill();
  }

  return new Cmplx(x, y);
}

void draw() {

  background(255);
  stroke(0);
  translate(200, height/2);

  //calculate the function
  Cmplx v=fourierDraw(120, 0, vals, time);

  //update the resulting wave graphs
  wave=(Cmplx[])splice(wave, v, 0);
  yVals=splice(yVals, v.im, 0);

  //draw the functions
  stroke(255, 0, 0);

  //left function
  beginShape();
  for (int h=0; h<wave.length; h++) vertex(wave[h].re, wave[h].im);
  endShape();

  //right function
  beginShape();
  for (int h=0; h<yVals.length; h++) vertex(h+offset, yVals[h]);
  endShape();

  //connect the rotating circle and the wave graph with the green line
  stroke(0, 255, 0);
  line(v.re, v.im, offset, yVals[0]);

  //updating global coords
  time+=0.005+tOff;

  //set the maximum number of values of the periodic function to be drawn (memory saving)
  if (yVals.length>width/3) yVals=shorten(yVals);

  //reset of the left-hand function every cycle
  if (time>=TWO_PI || time<=-TWO_PI) {
    time=0;
    for (int a=wave.length-1; a>=0; a--) wave=(Cmplx[])shorten(wave);
  }
}

Second file:

class Cmplx {

  float re, im; //real and imaginary parts of the complex number
  float freq, amp, phase; //I also add the polar coords directly into it

  Cmplx add(Cmplx c) {

    this.re+=c.re;
    this.im+=c.im;
    return this;
  }

  Cmplx mult(Cmplx c) {

    float r=this.re*c.re-this.im*c.im;
    float i=this.re*c.im+this.im*c.re;
    return new Cmplx(r, i);
  }

  //I will need two different constructors for different purposes, one of them is clear
  Cmplx() {
  }

  Cmplx(float a, float b) {

    this.re=a;
    this.im=b;
  }
}

//calculating the DFT of the periodic function
Cmplx[] dft(float[] x) {

  Cmplx[] X=new Cmplx[x.length];
  for (int a=0; a<x.length; a++) X[a]=new Cmplx();
  final int N=X.length;

  for (int k=0; k<N; k++) {

    float r=0, i=0;
    for (int n=0; n<N; n++) {

      final float angle=(TWO_PI*k*n)/N;
      r+=x[n]*cos(angle);
      i+=x[n]*sin(angle);
    }

    r/=N;
    i/=N;
    X[k].re=r;
    X[k].im=i;
    X[k].freq=k;
    X[k].amp=sqrt(pow(r, 2)+pow(i, 2));
    X[k].phase=atan2(i, r);
  }

  return X;
}

//calculating the DFT of the complex Fourier transform
Cmplx[] dft(Cmplx[] x) {

  Cmplx[] X=new Cmplx[x.length];
  for (int a=0; a<x.length; a++) X[a]=new Cmplx();
  final int N=X.length;

  for (int k=0; k<N; k++) {

    final Cmplx sum=new Cmplx();
    for (int n=0; n<N; n++) {

      final float angle=(TWO_PI*k*n)/N;
      Cmplx c=new Cmplx(cos(angle), -sin(angle));
      sum.add(x[n].mult(c));
    }

    sum.re/=N;
    sum.im/=N;
    X[k].re=sum.re;
    X[k].im=sum.im;
    X[k].freq=k;
    X[k].amp=sqrt(pow(sum.re, 2)+pow(sum.im, 2));
    X[k].phase=atan2(sum.im, sum.re);
  }

  return X;
}

In order to make this work, you’ll split the two codes into 2 different Files and name the folder as the “main” file, the first one that contains the setup() and draw() functions in it. Then you’ll compile it and you will be able to run it! Enjoy!

3 Likes

Nice!
Since it’s not symmetrical I was curious about the full cycle, so I took a picture.
Did you think of a name of the curve?