FFT confusion using JTransform - java

I have been reading all the posts in SO about FTT and using JTransform. I have a Real Data and it has the size of N. I would like to pass it to FFT so that I can calculate the magnitude at every frequency.
I have it done in matlab using the FFT function and I am trying to do the same in Java. My question is:
Do use RealForward or RealForwardFull? Or possibly creating another array with 0 imag and pass it to complex forward?
How big is the resulting FTT?

When you compute the DFT of an N - element array of real numbers, your result will be an N - element array of complex numbers.Now looking at the JTransform Documentation, in Jtransforms these complex numbers are represented as a pair of 2 real numbers (one representing the Real part and the other the imaginary) so your FFT result will actually be twice as long as your FFT input.
RealForwardFull computes the FFT of an array and returns all FFT coefficients whilst RealForward will only return half of the coefficients.The reason RealForward might suite some peoples needs is because the FFT has a symmetrical property, so by knowing just half of the coefficients you can obtain the rest of the coefficients using symmetrical properties of the FFT.

Related

Efficient or an alternative way to store data in a key / value style in Java

I wrote a program that takes a String and gives it's binary representation ( for example the letter "a" to 01000001) and emit a tone with frequency that denotes that binary representation. The frequency to be used in matching with the given binary representation relies on a TreeMap.
The second program listens for the tones, does some fft and other calculations to determine which frequency it was. Now after finding the corresponding frequency it has to translate it back to binary (01000001) to be formatted to ASCII and therefore re-construct the String. My problem is, the binary combinations and their matching frequencies are hard coded in a TreeMap used by both programs. This means 512 pairs had to be written in the source file that looks a little something like
ToneMap() {
// binary representation and the matching frequency
frequency.put("00000000", 400);
frequency.put("00000001", 433);
frequency.put("00000010", 466);
frequency.put("00000011", 499);
frequency.put("00000100", 532);
frequency.put("00000101", 565);
frequency.put("00000110", 598);
frequency.put("00000111", 631);
frequency.put("00001000", 664);
frequency.put("00001001", 697);
frequency.put("00001010", 730);
frequency.put("00001011", 763);
// followed by a lot more
This is obviously very wrong and inefficient. What are the alternatives to storing / generating the byte / frequency pairs on both programs without having to rely on a hard coded TreeMap.
With the help of #jontro, see comment.
Since the starting range and ending range are known ( 400hz and 9000hz). The retrieved frequency can be used with the range to find the index of that frequency and thus the byte representation
// 33 is difference between adjacent frequencies,
// the value of index is 8 which translates to 1000 using
Integer.toBinaryString( (664-400)/33)
//and from the original ToneMap, shows the value obtained from the above code is correct
frequency.put("00001000", 664);

Getting FFT frequency from noisy data?

I have an array (size 128) of data that I am using FFT on. I am trying to find the frequency of the data through the FFT spectrum. The problem is that the formula freq = i * Fs / N doesn't seem to be working. My data is quite noisy and I don't know if it is because of my noisy data or because I am doing something else wrong. Below is my raw data:
And this is the spectrum that results from the transform:
I am getting two maximum peaks of equal magnitude at index 4 and 128 in the output array. The frequency of the data should be around 1.1333 Hz, but I am getting 5-6 or completely wrong values when I use the formula:
freq = i * Fs / N;
where i is the array index of the largest magnitude peak, Fs is the sampling rate in Hz, and N is the data size.
Using my data, you get freq = (4 * 11.9) / 128 = 0.37 Hz, which is very off from what is expected.
If my calculation is correct, are there any ways to improve my data? Or, are my calculations for frequency incorrect?
Lets first make sure you are looking at the actual magnitudes. FFTs would return complex values associated with each frequency bins. These complex values are typically represented by two values: one for the real part and another for the imaginary part. The magnitude of a frequency component can then be obtained by computing sqrt(real*real+imaginary*imaginary).
This should give you half as many values and the corresponding spectrum (with the magnitudes expressed in decibels):
As you can see there is a strong peak near 0Hz. Which is consistent with your raw data having a large average value, as well as an increasing trend from time 0 to ~4.2s (both of which being larger than the oscillations' amplitude). If we were to remove these low frequency contributions (with for example a high-pass filter with cutoff frequency around 0.25Hz) we would get the following fluctuation data:
with the corresponding spectrum:
As you can see the oscillation frequency can much more readily be observed in bin 11, which gives you freq = (11 * 11.9) / 128 = 1Hz.
Note however that whether removing these frequency components bellow 0.25HZ is an improvement of your data depends on whether those frequency components are of interest for your application (possibly not since you seem to be interested in relatively faster fluctuations).
You need to remove the DC bias (average of all samples) before the FFT to measure frequencies near 0 Hz (or near the FFT's 0th result bin). Applying a window function (von Hann or Hamming window) after removing the DC bias and before the FFT may also help.

FFT realforward vs realforwardfull in example

I am exploring the JTransforms FFT and I tried FFT.realForward() and FFT.realForwardFull() and I got these results:
RealForward
16.236587494
-2.3513066039999995 <----------------?
1.8268368691062924
-1.1179067733368138
6.698362081000001
5.353354667
-6.146021583106291
-12.013420149336813
RealForwardFull
16.236587494
0.0 <------------------
1.8268368691062924
-1.1179067733368138
6.698362081000001
5.353354667
-6.146021583106291
-12.013420149336813
-2.3513066039999995 <-----------------
0.0 <-------------
-6.146021583106291
12.013420149336813
6.698362081000001
-5.353354667
1.8268368691062924
1.1179067733368138
So, as you can see, realforwardFull() gave a different imaginary for the first number and add a new pair. Shouldn't realforward() produce the same results minus any duplication?
Because the FFT of a real signal is symmetrical, both the k=0 and k=N/2 components are real-only (you can see that in the "full" output). So they're packed together in the "non-full" output.
This output layout is explained in the JavaDoc.
(Note: FFTW does the same thing.)
For information on how your FFT output data is represented look at the JTransforms documentation HERE
For RealForwardFull the output is the Full FFT data the usual way, i.e N-Complex numbers, with the real and imaginary components interleaved.
For RealForward the output is arranged as follows: -The first two elements are the real components of the first ( k = 0 ) and the middle ( k = N/2 ) FFT coefficients respectively, the rest of the FFT coefficients are then given after that with the real and imaginary components interleaved.
Like Oli CharlesWorth has mentioned, the imaginary component of the k = 0 and k = N/2 terms will be zero because the input signal is real, so Realforward does not return them.It only returns the minimum information enough for you to be able to reconstruct the full spectrum.

looking for a single index to show the similarity in point matching algorithm

I did read the Point set registration and would like to implement it for my simple line matching. However, I only got very basic maths knowledge and cannot really understand the equations on the page.
Assuming I am able to extract points from 2 images, searching nearest pair by brute force looping and got a list of pairs with corresponding distances.
What is the next step to calculate a single index by utilizing the above data obtained?
The idea I currently come up with is to simply average all the distance. I believe this are many better approach. Or I should capture more data for the calculation?
Your instincts are almost correct.
Generally, the metric is the sum of squared distances; with the goal of finding the least-squares fit (minimizing the sum of all the individual square distances). Essentially this minimizes the standard deviation (actually it minimizes variance, but same end effect).
So take all your corresponding pairs, calculate the distance squared between them (fast calculation, no sqrt involved; faster than calculating actual distances) add them up and the lower the better. If your point sets differ in count you may wish to divide by the count to get a proper variance value.
This metric applies to pretty much any registration algorithm.
By the way, if you already have a point correspondance and you know there is no scaling/skewing, you might also be interested in Horn's method, which is a closed-form (non-iterative) algorithm that just spits out the least-squared fit directly. It's very efficient.
(P.S. For a very simple explanation of why the variance is a better indicator than the mean distance, check out this page).

Fourier Transform and Fourier Descriptors to extract shapes features on Java

I am trying to build a simple system to recognize simple shapes using Fourier descriptors:
I am using this implementation of Fast fourier transform on my program: (link below)
http://www.wikijava.org/wiki/The_Fast_Fourier_Transform_in_Java_%28part_1%29
fft(double[] inputReal, double[] inputImag, boolean direction)
inputs are: real and imag part (which are essentially x,y coordinates of boundary parameter I have)
and outputs are the transformed real and imag numbers.
question: How can i use the output (transformed real,imag ) as a invariant descriptors of my simple shapes?
This was what I thought :
calculate R = sqrt( real^2 + imag^2 ) for each N steps.
divide each R by R[1] = the normalization factor to make it invariant.
The problem is I get very different R values for slightly different images (such as slight rotations applied, etc)
In other words :
My descriptors are not invariant... I think I am doing something wrong with getting the R value.
There is some theory you need to know first about Fourier Descriptors: it's an extremely interesting technique, but should be devised correctly. What you want is invariance; invariance for rotation, translation, maybe even affine transforms. To allow good comparison with other sets of Fourier descriptors you should take following things in consideration:
if you want invariance to translation, do not use the DC-term, that is the first element in your resulting array of Fourier coefficients
if you want invariance to scaling, make the comparison ratio-like, for example by dividing every Fourier coefficient by the DC-coefficient. f*[1] = f[1]/f[0], f*[2]/f[0], and so on.
if you want invariance to the start point of your contour, only use absolute values of the resulting Fourier coefficients.
Only the first 5 to 8 Fourier coefficients are useful when comparing the coefficients of two different objects; higher coefficients only go into the details of your contour which mostly isn't very useful information. (it's the global form that matters)
Let's say you have 2 objects, and their Fourier descriptors. The resulting array of Fourier coefficients can be of a different size, meaning that the 'frequency interval' of the resulting frequency content is different for both shapes. You can't compare apples with pears. Zero-pad your shortest contour to match the size of the longest contour, and then calculate the Fourier descriptors. Now you have analogy between coefficients and a good comparison.
Hope this helps. Btw, user-made FFT solutions are not to be trusted in my opinion. Go for the solutions libraries reach out. If working with images, OpenCV provides Fourier transform utilities.
If you are looking to match different shapes, try using different shape descriptors from MPEG-7 standard. You will probably need a classifier, take a look at SVM, Boosting, Neural Networks ...: http://docs.opencv.org/modules/ml/doc/ml.html

Categories

Resources