I am working on a project to draw a given figure using epicycles (by DFT). I am following this website: https://www.instructables.com/Drawing-With-Discrete-Fourier-Transform/ but I don't seem to be getting correct values for the amplitudes because for any sample of points, the amplitude increases in the end (at higher frequencies) while I don't think it should - at least not according to the examples in the website.
The function takes a double[][] as input containing x and y coordinates of sample points and Points.n is the number of sample points. Here is my DFT function:
public class Dft {
public static double[][] dft(double[][] psamples){
double[][] result = new double[Points.n][2];
for (int i = 0; i < Points.n; i++){
Complex x_i = new Complex(0, 0);
for (int j = 0; j < Points.n; j++){
Complex sample = new Complex(psamples[j][0], psamples[j][1]);
double root = Math.PI*2*i*j/Points.n;
Complex unity = new Complex(Math.cos(root), -Math.sin(root));
x_i = Complex.add(x_i, Complex.multiply(sample, unity));
}
result[i][0] = x_i.amp()/Points.n; //amplitude
result[i][1] = x_i.angle(); //phase change
//frequency is equal to the index number i
System.out.println(i + " amp: " + result[i][0] + " phase change: " + result[i][1]);
}
return result;
}
}
The Complex class is :
public class Complex {
double[] num = {0,0};
public Complex(double a, double b){
num[0] = a;
num[1] = b;
}
public void setReal(double a){
num[0] = a;
}
public void setImaginary(double b){
num[1] = b;
}
public double getReal(){
return num[0];
}
public double getImaginary(){
return num[1];
}
public static Complex add(Complex a, Complex b){
Complex result = new Complex(a.getReal()+b.getReal(), a.getImaginary() + b.getImaginary());
return result;
}
public static Complex euler(double r, double theta){
Complex result = new Complex(r*Math.cos(theta), r*Math.sin(theta));
return result;
}
public static Complex multiply(Complex a, Complex b){
Complex result = new Complex(a.getReal()*b.getReal() - a.getImaginary()*b.getImaginary(), a.getReal()*b.getImaginary() + a.getImaginary()*b.getReal());
return result;
}
public double amp(){
double result = Math.sqrt(num[0]*num[0] + num[1]*num[1]);
return result;
}
public double angle(){
if (num[0] == 0){
if (num[1]>0) return Math.PI/2;
else if (num[1]<0) return -Math.PI/2;
else return 0;
}
else {
double result = Math.atan2(num[1],num[0]);
return result;
}
}
}
not coding in JAVA but I was curious so I tried it in C++/VCL
load some 2D polygon data
I used SVG hand-drawed image (in my SVG editor):
and stored the data as set of 2D points (see
pic[]in data.h below)do 1D DFFT on input polygon (complex input and output)
each 2D point is represented as single complex number. As I used DFFT (DFT was ~1sec too slow to my taste) the input data must be power of 2 size so "pad" themissing data (I duplicated last point).
during rendering do iDFT (complex input and output) and render line/circle in each inner loop iteration
however this step is different from iDFT as we do not use the outer loop and instead we select only single output (not computing whole array). The selected index is like animation time/parameter. However the change must be discrete (you can not interpolate between 2 values without more heavy computations).
Here simplified (without SVG importer, with fixed size and static data and removed all unimportant stuff) C++/VCL example:
here the data.h (both input and output so you can cross compare):
and preview:
Now you just add the sorting of circles by radius if you want (now they are sorted by frequency)...