AudioRecorder | Interpreting FFT data for Spectrum Analyzer












1















I am building an app that needs to be able to display a real-time spectral analyzer. Here is the version I was able to successfully make on iOS:



Sample Spectral Analyser



I am using Wendykierp JTransforms library to perform the FFT calculations, and have managed to capture audio data and execute the FFT functions. See below:



short sData = new short[BufferElements2Rec];
int result = audioRecord.read(sData, 0, BufferElements2Rec);

try
{
//Initiate FFT
DoubleFFT_1D fft = new DoubleFFT_1D(sData.length);

//Convert sample data from short to double
double fftSamples = new double[sData.length];
for (int i = 0; i < sData.length; i++) {
//IMPORTANT: We cannot simply cast the short value to double.
//As a double is only 2 bytes (values -32768 to 32768)
//We must divide by 32768 before we cast to Double.
fftSamples[i] = (double) sData[i] / 32768;
}

//Perform fft calcs
fft.realForward(fftSamples);

//TODO - Convert FFT data into 20 "bands"

} Catch (Exception e)
{

}


In iOS, I was using a library (Tempi-FFT) which had built in functionality for calculating magnitude, frequency, and providing averaged data for any given number of bands (I am using 20 bands as you can see in the image above). It seems I don't have that luxury with this library and I need to calculate this myself.



Looking for any good examples or tutorials on how to interperate the data returned by the FFT calculations. Here is some sample data I am receiving:



-11387.0, 183.0, -384.9121475854448, -224.66315714636642, -638.0173005872095, -236.2318653974911, -1137.1498541119106, -437.71599514435786, 1954.683405957685, -2142.742125980924 ...


Looking for simple explanation of how to interpret this data. Some other questions I have looked at that I was either unable to understand, or did not provide information on how to determine a given number of bands:



Power Spectral Density from jTransforms DoubleFFT_1D



How to develop a Spectrum Analyser from a realtime audio?










share|improve this question

























  • FFT is definitely not a simple thing. The first link (stackoverflow.com/questions/5010261/…) provides the simplest explanation of how to interperet your output. Give me a little bit and I'll post a specific answer to your question.

    – Sub 6 Resources
    Nov 21 '18 at 19:25











  • Posted an answer. Hope its useful to you!

    – Sub 6 Resources
    Nov 21 '18 at 21:12
















1















I am building an app that needs to be able to display a real-time spectral analyzer. Here is the version I was able to successfully make on iOS:



Sample Spectral Analyser



I am using Wendykierp JTransforms library to perform the FFT calculations, and have managed to capture audio data and execute the FFT functions. See below:



short sData = new short[BufferElements2Rec];
int result = audioRecord.read(sData, 0, BufferElements2Rec);

try
{
//Initiate FFT
DoubleFFT_1D fft = new DoubleFFT_1D(sData.length);

//Convert sample data from short to double
double fftSamples = new double[sData.length];
for (int i = 0; i < sData.length; i++) {
//IMPORTANT: We cannot simply cast the short value to double.
//As a double is only 2 bytes (values -32768 to 32768)
//We must divide by 32768 before we cast to Double.
fftSamples[i] = (double) sData[i] / 32768;
}

//Perform fft calcs
fft.realForward(fftSamples);

//TODO - Convert FFT data into 20 "bands"

} Catch (Exception e)
{

}


In iOS, I was using a library (Tempi-FFT) which had built in functionality for calculating magnitude, frequency, and providing averaged data for any given number of bands (I am using 20 bands as you can see in the image above). It seems I don't have that luxury with this library and I need to calculate this myself.



Looking for any good examples or tutorials on how to interperate the data returned by the FFT calculations. Here is some sample data I am receiving:



-11387.0, 183.0, -384.9121475854448, -224.66315714636642, -638.0173005872095, -236.2318653974911, -1137.1498541119106, -437.71599514435786, 1954.683405957685, -2142.742125980924 ...


Looking for simple explanation of how to interpret this data. Some other questions I have looked at that I was either unable to understand, or did not provide information on how to determine a given number of bands:



Power Spectral Density from jTransforms DoubleFFT_1D



How to develop a Spectrum Analyser from a realtime audio?










share|improve this question

























  • FFT is definitely not a simple thing. The first link (stackoverflow.com/questions/5010261/…) provides the simplest explanation of how to interperet your output. Give me a little bit and I'll post a specific answer to your question.

    – Sub 6 Resources
    Nov 21 '18 at 19:25











  • Posted an answer. Hope its useful to you!

    – Sub 6 Resources
    Nov 21 '18 at 21:12














1












1








1








I am building an app that needs to be able to display a real-time spectral analyzer. Here is the version I was able to successfully make on iOS:



Sample Spectral Analyser



I am using Wendykierp JTransforms library to perform the FFT calculations, and have managed to capture audio data and execute the FFT functions. See below:



short sData = new short[BufferElements2Rec];
int result = audioRecord.read(sData, 0, BufferElements2Rec);

try
{
//Initiate FFT
DoubleFFT_1D fft = new DoubleFFT_1D(sData.length);

//Convert sample data from short to double
double fftSamples = new double[sData.length];
for (int i = 0; i < sData.length; i++) {
//IMPORTANT: We cannot simply cast the short value to double.
//As a double is only 2 bytes (values -32768 to 32768)
//We must divide by 32768 before we cast to Double.
fftSamples[i] = (double) sData[i] / 32768;
}

//Perform fft calcs
fft.realForward(fftSamples);

//TODO - Convert FFT data into 20 "bands"

} Catch (Exception e)
{

}


In iOS, I was using a library (Tempi-FFT) which had built in functionality for calculating magnitude, frequency, and providing averaged data for any given number of bands (I am using 20 bands as you can see in the image above). It seems I don't have that luxury with this library and I need to calculate this myself.



Looking for any good examples or tutorials on how to interperate the data returned by the FFT calculations. Here is some sample data I am receiving:



-11387.0, 183.0, -384.9121475854448, -224.66315714636642, -638.0173005872095, -236.2318653974911, -1137.1498541119106, -437.71599514435786, 1954.683405957685, -2142.742125980924 ...


Looking for simple explanation of how to interpret this data. Some other questions I have looked at that I was either unable to understand, or did not provide information on how to determine a given number of bands:



Power Spectral Density from jTransforms DoubleFFT_1D



How to develop a Spectrum Analyser from a realtime audio?










share|improve this question
















I am building an app that needs to be able to display a real-time spectral analyzer. Here is the version I was able to successfully make on iOS:



Sample Spectral Analyser



I am using Wendykierp JTransforms library to perform the FFT calculations, and have managed to capture audio data and execute the FFT functions. See below:



short sData = new short[BufferElements2Rec];
int result = audioRecord.read(sData, 0, BufferElements2Rec);

try
{
//Initiate FFT
DoubleFFT_1D fft = new DoubleFFT_1D(sData.length);

//Convert sample data from short to double
double fftSamples = new double[sData.length];
for (int i = 0; i < sData.length; i++) {
//IMPORTANT: We cannot simply cast the short value to double.
//As a double is only 2 bytes (values -32768 to 32768)
//We must divide by 32768 before we cast to Double.
fftSamples[i] = (double) sData[i] / 32768;
}

//Perform fft calcs
fft.realForward(fftSamples);

//TODO - Convert FFT data into 20 "bands"

} Catch (Exception e)
{

}


In iOS, I was using a library (Tempi-FFT) which had built in functionality for calculating magnitude, frequency, and providing averaged data for any given number of bands (I am using 20 bands as you can see in the image above). It seems I don't have that luxury with this library and I need to calculate this myself.



Looking for any good examples or tutorials on how to interperate the data returned by the FFT calculations. Here is some sample data I am receiving:



-11387.0, 183.0, -384.9121475854448, -224.66315714636642, -638.0173005872095, -236.2318653974911, -1137.1498541119106, -437.71599514435786, 1954.683405957685, -2142.742125980924 ...


Looking for simple explanation of how to interpret this data. Some other questions I have looked at that I was either unable to understand, or did not provide information on how to determine a given number of bands:



Power Spectral Density from jTransforms DoubleFFT_1D



How to develop a Spectrum Analyser from a realtime audio?







android fft audiorecord






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 21 '18 at 23:17







JCutting8

















asked Sep 24 '18 at 13:47









JCutting8JCutting8

13412




13412













  • FFT is definitely not a simple thing. The first link (stackoverflow.com/questions/5010261/…) provides the simplest explanation of how to interperet your output. Give me a little bit and I'll post a specific answer to your question.

    – Sub 6 Resources
    Nov 21 '18 at 19:25











  • Posted an answer. Hope its useful to you!

    – Sub 6 Resources
    Nov 21 '18 at 21:12



















  • FFT is definitely not a simple thing. The first link (stackoverflow.com/questions/5010261/…) provides the simplest explanation of how to interperet your output. Give me a little bit and I'll post a specific answer to your question.

    – Sub 6 Resources
    Nov 21 '18 at 19:25











  • Posted an answer. Hope its useful to you!

    – Sub 6 Resources
    Nov 21 '18 at 21:12

















FFT is definitely not a simple thing. The first link (stackoverflow.com/questions/5010261/…) provides the simplest explanation of how to interperet your output. Give me a little bit and I'll post a specific answer to your question.

– Sub 6 Resources
Nov 21 '18 at 19:25





FFT is definitely not a simple thing. The first link (stackoverflow.com/questions/5010261/…) provides the simplest explanation of how to interperet your output. Give me a little bit and I'll post a specific answer to your question.

– Sub 6 Resources
Nov 21 '18 at 19:25













Posted an answer. Hope its useful to you!

– Sub 6 Resources
Nov 21 '18 at 21:12





Posted an answer. Hope its useful to you!

– Sub 6 Resources
Nov 21 '18 at 21:12












1 Answer
1






active

oldest

votes


















1





+50









Your question can be split into two parts: finding the magnitude of all frequencies (interpreting the output) and averaging the frequencies into bands




Finding the magnitude of all frequencies:



I won't go into the intricacies of the Fast Fourier Transform/Discrete Fourier Transform (if you would like to gain a basic understanding see this video), but know that there is a real and an imaginary part of each output.



The documentation of the realForward function describes where both the imaginary and the real parts are located in the output array (I'm assuming you have an even sample size):




a[2*k] = Re[k], 0 <= k < n / 2
a[2*k+1] = Im[k], 0 < k < n / 2
a[1] = Re[n/2]



a is equivalent to your fftSamples, which means we can translate this documentation into code as follows (I've changed Re and Im to realPart and imaginaryPart respectively):



int n = fftSamples.length;

double realPart = new double[n / 2];
double imaginaryPart = new double[n / 2];

for(int k = 0; k < n / 2; k++) {
realPart[k] = fftSamples[k * 2];
imaginaryPart[k] = fftSamples[k * 2 + 1];
}

realPart[n / 2] = fftSamples[1];


Now we have the real and imaginary parts of each frequency. We could plot these on an x-y coordinate plane using the real part as the x value and the imaginary part as the y value. This creates a triangle, and the length of the triangle's hypotenuse is the magnitude of the frequency. We can use the pythagorean theorem to get this magnitude:



double spectrum = new double[n / 2];

for(int k = 1; k < n / 2; k++) {
spectrum[k] = Math.sqrt(Math.pow(realPart[k], 2) + Math.pow(imaginaryPart[k], 2));
}

spectrum[0] = realPart[0];


Note that the 0th index of the spectrum doesn't have an imaginary part. This is the DC component of the signal (we won't use this).



Now, we have an array with the magnitudes of each frequency across your spectrum (If your sampling frequency is 44100Hz, this means you now have an array with the magnitudes of the frequencies between 0Hz and 44100Hz, and if you have 441 values in your array, then each index value represents a 100Hz step.)




Averaging the frequencies into bands:



Now that we've converted the FFT output to data that we can use, we can move on to the second part of your question: finding the averages of different bands of frequencies. This is relatively simple. We just need to split the array into different bands and find the average of each band. This can be generalized like so:



int NUM_BANDS = 20; //This can be any positive integer.
double bands = new double[NUM_BANDS];
int samplesPerBand = (n / 2) / NUM_BANDS;

for(int i = 0; i < NUM_BANDS; i++) {
//Add up each part
double total;
for(int j = samplesPerBand * i ; j < samplesPerBand * (i+1); j++) {
total += spectrum[j];
}
//Take average
bands[i] = total / samplesPerBand;
}





Final Code:



And that's it! You now have an array called bands with the average magnitude of each band of frequencies. The code above is purposefully not optimized in order to show how each step works. Here is a shortened and optimized version:



int numFrequencies = fftSamples.length / 2;

double spectrum = new double[numFrequencies];

for(int k = 1; k < numFrequencies; k++) {
spectrum[k] = Math.sqrt(Math.pow(fftSamples[k*2], 2) + Math.pow(fftSamples[k*2+1], 2));
}

spectrum[0] = fftSamples[0];

int NUM_BANDS = 20; //This can be any positive integer.
double bands = new double[NUM_BANDS];
int samplesPerBand = numFrequencies / NUM_BANDS;

for(int i = 0; i < NUM_BANDS; i++) {
//Add up each part
double total;
for(int j = samplesPerBand * i ; j < samplesPerBand * (i+1); j++) {
total += spectrum[j];
}
//Take average
bands[i] = total / samplesPerBand;
}

//Use bands in view!




This has been a really long answer, and I haven't tested the code yet (though I do plan to). Feel free to comment if you find any mistakes.






share|improve this answer
























  • Super helpful answer, thank you. In addition, I was also doing something else incorrectly. For anyone else looking to do something similar - the way I convert my values from short to double for the purpose of the FFT calculation is incorrect. One must account for the fact that a short is 2 bytes (range from -32768 to 32768) hence one must divide the short by 32768 before casting to double. If you do not do this you will get unexpected behaviour/output from the FFT calculation.

    – JCutting8
    Nov 21 '18 at 23:11













  • Yeah, that would cause some issues. :)

    – Sub 6 Resources
    Nov 21 '18 at 23:54












Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52480832%2faudiorecorder-interpreting-fft-data-for-spectrum-analyzer%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1





+50









Your question can be split into two parts: finding the magnitude of all frequencies (interpreting the output) and averaging the frequencies into bands




Finding the magnitude of all frequencies:



I won't go into the intricacies of the Fast Fourier Transform/Discrete Fourier Transform (if you would like to gain a basic understanding see this video), but know that there is a real and an imaginary part of each output.



The documentation of the realForward function describes where both the imaginary and the real parts are located in the output array (I'm assuming you have an even sample size):




a[2*k] = Re[k], 0 <= k < n / 2
a[2*k+1] = Im[k], 0 < k < n / 2
a[1] = Re[n/2]



a is equivalent to your fftSamples, which means we can translate this documentation into code as follows (I've changed Re and Im to realPart and imaginaryPart respectively):



int n = fftSamples.length;

double realPart = new double[n / 2];
double imaginaryPart = new double[n / 2];

for(int k = 0; k < n / 2; k++) {
realPart[k] = fftSamples[k * 2];
imaginaryPart[k] = fftSamples[k * 2 + 1];
}

realPart[n / 2] = fftSamples[1];


Now we have the real and imaginary parts of each frequency. We could plot these on an x-y coordinate plane using the real part as the x value and the imaginary part as the y value. This creates a triangle, and the length of the triangle's hypotenuse is the magnitude of the frequency. We can use the pythagorean theorem to get this magnitude:



double spectrum = new double[n / 2];

for(int k = 1; k < n / 2; k++) {
spectrum[k] = Math.sqrt(Math.pow(realPart[k], 2) + Math.pow(imaginaryPart[k], 2));
}

spectrum[0] = realPart[0];


Note that the 0th index of the spectrum doesn't have an imaginary part. This is the DC component of the signal (we won't use this).



Now, we have an array with the magnitudes of each frequency across your spectrum (If your sampling frequency is 44100Hz, this means you now have an array with the magnitudes of the frequencies between 0Hz and 44100Hz, and if you have 441 values in your array, then each index value represents a 100Hz step.)




Averaging the frequencies into bands:



Now that we've converted the FFT output to data that we can use, we can move on to the second part of your question: finding the averages of different bands of frequencies. This is relatively simple. We just need to split the array into different bands and find the average of each band. This can be generalized like so:



int NUM_BANDS = 20; //This can be any positive integer.
double bands = new double[NUM_BANDS];
int samplesPerBand = (n / 2) / NUM_BANDS;

for(int i = 0; i < NUM_BANDS; i++) {
//Add up each part
double total;
for(int j = samplesPerBand * i ; j < samplesPerBand * (i+1); j++) {
total += spectrum[j];
}
//Take average
bands[i] = total / samplesPerBand;
}





Final Code:



And that's it! You now have an array called bands with the average magnitude of each band of frequencies. The code above is purposefully not optimized in order to show how each step works. Here is a shortened and optimized version:



int numFrequencies = fftSamples.length / 2;

double spectrum = new double[numFrequencies];

for(int k = 1; k < numFrequencies; k++) {
spectrum[k] = Math.sqrt(Math.pow(fftSamples[k*2], 2) + Math.pow(fftSamples[k*2+1], 2));
}

spectrum[0] = fftSamples[0];

int NUM_BANDS = 20; //This can be any positive integer.
double bands = new double[NUM_BANDS];
int samplesPerBand = numFrequencies / NUM_BANDS;

for(int i = 0; i < NUM_BANDS; i++) {
//Add up each part
double total;
for(int j = samplesPerBand * i ; j < samplesPerBand * (i+1); j++) {
total += spectrum[j];
}
//Take average
bands[i] = total / samplesPerBand;
}

//Use bands in view!




This has been a really long answer, and I haven't tested the code yet (though I do plan to). Feel free to comment if you find any mistakes.






share|improve this answer
























  • Super helpful answer, thank you. In addition, I was also doing something else incorrectly. For anyone else looking to do something similar - the way I convert my values from short to double for the purpose of the FFT calculation is incorrect. One must account for the fact that a short is 2 bytes (range from -32768 to 32768) hence one must divide the short by 32768 before casting to double. If you do not do this you will get unexpected behaviour/output from the FFT calculation.

    – JCutting8
    Nov 21 '18 at 23:11













  • Yeah, that would cause some issues. :)

    – Sub 6 Resources
    Nov 21 '18 at 23:54
















1





+50









Your question can be split into two parts: finding the magnitude of all frequencies (interpreting the output) and averaging the frequencies into bands




Finding the magnitude of all frequencies:



I won't go into the intricacies of the Fast Fourier Transform/Discrete Fourier Transform (if you would like to gain a basic understanding see this video), but know that there is a real and an imaginary part of each output.



The documentation of the realForward function describes where both the imaginary and the real parts are located in the output array (I'm assuming you have an even sample size):




a[2*k] = Re[k], 0 <= k < n / 2
a[2*k+1] = Im[k], 0 < k < n / 2
a[1] = Re[n/2]



a is equivalent to your fftSamples, which means we can translate this documentation into code as follows (I've changed Re and Im to realPart and imaginaryPart respectively):



int n = fftSamples.length;

double realPart = new double[n / 2];
double imaginaryPart = new double[n / 2];

for(int k = 0; k < n / 2; k++) {
realPart[k] = fftSamples[k * 2];
imaginaryPart[k] = fftSamples[k * 2 + 1];
}

realPart[n / 2] = fftSamples[1];


Now we have the real and imaginary parts of each frequency. We could plot these on an x-y coordinate plane using the real part as the x value and the imaginary part as the y value. This creates a triangle, and the length of the triangle's hypotenuse is the magnitude of the frequency. We can use the pythagorean theorem to get this magnitude:



double spectrum = new double[n / 2];

for(int k = 1; k < n / 2; k++) {
spectrum[k] = Math.sqrt(Math.pow(realPart[k], 2) + Math.pow(imaginaryPart[k], 2));
}

spectrum[0] = realPart[0];


Note that the 0th index of the spectrum doesn't have an imaginary part. This is the DC component of the signal (we won't use this).



Now, we have an array with the magnitudes of each frequency across your spectrum (If your sampling frequency is 44100Hz, this means you now have an array with the magnitudes of the frequencies between 0Hz and 44100Hz, and if you have 441 values in your array, then each index value represents a 100Hz step.)




Averaging the frequencies into bands:



Now that we've converted the FFT output to data that we can use, we can move on to the second part of your question: finding the averages of different bands of frequencies. This is relatively simple. We just need to split the array into different bands and find the average of each band. This can be generalized like so:



int NUM_BANDS = 20; //This can be any positive integer.
double bands = new double[NUM_BANDS];
int samplesPerBand = (n / 2) / NUM_BANDS;

for(int i = 0; i < NUM_BANDS; i++) {
//Add up each part
double total;
for(int j = samplesPerBand * i ; j < samplesPerBand * (i+1); j++) {
total += spectrum[j];
}
//Take average
bands[i] = total / samplesPerBand;
}





Final Code:



And that's it! You now have an array called bands with the average magnitude of each band of frequencies. The code above is purposefully not optimized in order to show how each step works. Here is a shortened and optimized version:



int numFrequencies = fftSamples.length / 2;

double spectrum = new double[numFrequencies];

for(int k = 1; k < numFrequencies; k++) {
spectrum[k] = Math.sqrt(Math.pow(fftSamples[k*2], 2) + Math.pow(fftSamples[k*2+1], 2));
}

spectrum[0] = fftSamples[0];

int NUM_BANDS = 20; //This can be any positive integer.
double bands = new double[NUM_BANDS];
int samplesPerBand = numFrequencies / NUM_BANDS;

for(int i = 0; i < NUM_BANDS; i++) {
//Add up each part
double total;
for(int j = samplesPerBand * i ; j < samplesPerBand * (i+1); j++) {
total += spectrum[j];
}
//Take average
bands[i] = total / samplesPerBand;
}

//Use bands in view!




This has been a really long answer, and I haven't tested the code yet (though I do plan to). Feel free to comment if you find any mistakes.






share|improve this answer
























  • Super helpful answer, thank you. In addition, I was also doing something else incorrectly. For anyone else looking to do something similar - the way I convert my values from short to double for the purpose of the FFT calculation is incorrect. One must account for the fact that a short is 2 bytes (range from -32768 to 32768) hence one must divide the short by 32768 before casting to double. If you do not do this you will get unexpected behaviour/output from the FFT calculation.

    – JCutting8
    Nov 21 '18 at 23:11













  • Yeah, that would cause some issues. :)

    – Sub 6 Resources
    Nov 21 '18 at 23:54














1





+50







1





+50



1




+50





Your question can be split into two parts: finding the magnitude of all frequencies (interpreting the output) and averaging the frequencies into bands




Finding the magnitude of all frequencies:



I won't go into the intricacies of the Fast Fourier Transform/Discrete Fourier Transform (if you would like to gain a basic understanding see this video), but know that there is a real and an imaginary part of each output.



The documentation of the realForward function describes where both the imaginary and the real parts are located in the output array (I'm assuming you have an even sample size):




a[2*k] = Re[k], 0 <= k < n / 2
a[2*k+1] = Im[k], 0 < k < n / 2
a[1] = Re[n/2]



a is equivalent to your fftSamples, which means we can translate this documentation into code as follows (I've changed Re and Im to realPart and imaginaryPart respectively):



int n = fftSamples.length;

double realPart = new double[n / 2];
double imaginaryPart = new double[n / 2];

for(int k = 0; k < n / 2; k++) {
realPart[k] = fftSamples[k * 2];
imaginaryPart[k] = fftSamples[k * 2 + 1];
}

realPart[n / 2] = fftSamples[1];


Now we have the real and imaginary parts of each frequency. We could plot these on an x-y coordinate plane using the real part as the x value and the imaginary part as the y value. This creates a triangle, and the length of the triangle's hypotenuse is the magnitude of the frequency. We can use the pythagorean theorem to get this magnitude:



double spectrum = new double[n / 2];

for(int k = 1; k < n / 2; k++) {
spectrum[k] = Math.sqrt(Math.pow(realPart[k], 2) + Math.pow(imaginaryPart[k], 2));
}

spectrum[0] = realPart[0];


Note that the 0th index of the spectrum doesn't have an imaginary part. This is the DC component of the signal (we won't use this).



Now, we have an array with the magnitudes of each frequency across your spectrum (If your sampling frequency is 44100Hz, this means you now have an array with the magnitudes of the frequencies between 0Hz and 44100Hz, and if you have 441 values in your array, then each index value represents a 100Hz step.)




Averaging the frequencies into bands:



Now that we've converted the FFT output to data that we can use, we can move on to the second part of your question: finding the averages of different bands of frequencies. This is relatively simple. We just need to split the array into different bands and find the average of each band. This can be generalized like so:



int NUM_BANDS = 20; //This can be any positive integer.
double bands = new double[NUM_BANDS];
int samplesPerBand = (n / 2) / NUM_BANDS;

for(int i = 0; i < NUM_BANDS; i++) {
//Add up each part
double total;
for(int j = samplesPerBand * i ; j < samplesPerBand * (i+1); j++) {
total += spectrum[j];
}
//Take average
bands[i] = total / samplesPerBand;
}





Final Code:



And that's it! You now have an array called bands with the average magnitude of each band of frequencies. The code above is purposefully not optimized in order to show how each step works. Here is a shortened and optimized version:



int numFrequencies = fftSamples.length / 2;

double spectrum = new double[numFrequencies];

for(int k = 1; k < numFrequencies; k++) {
spectrum[k] = Math.sqrt(Math.pow(fftSamples[k*2], 2) + Math.pow(fftSamples[k*2+1], 2));
}

spectrum[0] = fftSamples[0];

int NUM_BANDS = 20; //This can be any positive integer.
double bands = new double[NUM_BANDS];
int samplesPerBand = numFrequencies / NUM_BANDS;

for(int i = 0; i < NUM_BANDS; i++) {
//Add up each part
double total;
for(int j = samplesPerBand * i ; j < samplesPerBand * (i+1); j++) {
total += spectrum[j];
}
//Take average
bands[i] = total / samplesPerBand;
}

//Use bands in view!




This has been a really long answer, and I haven't tested the code yet (though I do plan to). Feel free to comment if you find any mistakes.






share|improve this answer













Your question can be split into two parts: finding the magnitude of all frequencies (interpreting the output) and averaging the frequencies into bands




Finding the magnitude of all frequencies:



I won't go into the intricacies of the Fast Fourier Transform/Discrete Fourier Transform (if you would like to gain a basic understanding see this video), but know that there is a real and an imaginary part of each output.



The documentation of the realForward function describes where both the imaginary and the real parts are located in the output array (I'm assuming you have an even sample size):




a[2*k] = Re[k], 0 <= k < n / 2
a[2*k+1] = Im[k], 0 < k < n / 2
a[1] = Re[n/2]



a is equivalent to your fftSamples, which means we can translate this documentation into code as follows (I've changed Re and Im to realPart and imaginaryPart respectively):



int n = fftSamples.length;

double realPart = new double[n / 2];
double imaginaryPart = new double[n / 2];

for(int k = 0; k < n / 2; k++) {
realPart[k] = fftSamples[k * 2];
imaginaryPart[k] = fftSamples[k * 2 + 1];
}

realPart[n / 2] = fftSamples[1];


Now we have the real and imaginary parts of each frequency. We could plot these on an x-y coordinate plane using the real part as the x value and the imaginary part as the y value. This creates a triangle, and the length of the triangle's hypotenuse is the magnitude of the frequency. We can use the pythagorean theorem to get this magnitude:



double spectrum = new double[n / 2];

for(int k = 1; k < n / 2; k++) {
spectrum[k] = Math.sqrt(Math.pow(realPart[k], 2) + Math.pow(imaginaryPart[k], 2));
}

spectrum[0] = realPart[0];


Note that the 0th index of the spectrum doesn't have an imaginary part. This is the DC component of the signal (we won't use this).



Now, we have an array with the magnitudes of each frequency across your spectrum (If your sampling frequency is 44100Hz, this means you now have an array with the magnitudes of the frequencies between 0Hz and 44100Hz, and if you have 441 values in your array, then each index value represents a 100Hz step.)




Averaging the frequencies into bands:



Now that we've converted the FFT output to data that we can use, we can move on to the second part of your question: finding the averages of different bands of frequencies. This is relatively simple. We just need to split the array into different bands and find the average of each band. This can be generalized like so:



int NUM_BANDS = 20; //This can be any positive integer.
double bands = new double[NUM_BANDS];
int samplesPerBand = (n / 2) / NUM_BANDS;

for(int i = 0; i < NUM_BANDS; i++) {
//Add up each part
double total;
for(int j = samplesPerBand * i ; j < samplesPerBand * (i+1); j++) {
total += spectrum[j];
}
//Take average
bands[i] = total / samplesPerBand;
}





Final Code:



And that's it! You now have an array called bands with the average magnitude of each band of frequencies. The code above is purposefully not optimized in order to show how each step works. Here is a shortened and optimized version:



int numFrequencies = fftSamples.length / 2;

double spectrum = new double[numFrequencies];

for(int k = 1; k < numFrequencies; k++) {
spectrum[k] = Math.sqrt(Math.pow(fftSamples[k*2], 2) + Math.pow(fftSamples[k*2+1], 2));
}

spectrum[0] = fftSamples[0];

int NUM_BANDS = 20; //This can be any positive integer.
double bands = new double[NUM_BANDS];
int samplesPerBand = numFrequencies / NUM_BANDS;

for(int i = 0; i < NUM_BANDS; i++) {
//Add up each part
double total;
for(int j = samplesPerBand * i ; j < samplesPerBand * (i+1); j++) {
total += spectrum[j];
}
//Take average
bands[i] = total / samplesPerBand;
}

//Use bands in view!




This has been a really long answer, and I haven't tested the code yet (though I do plan to). Feel free to comment if you find any mistakes.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 21 '18 at 21:08









Sub 6 ResourcesSub 6 Resources

938620




938620













  • Super helpful answer, thank you. In addition, I was also doing something else incorrectly. For anyone else looking to do something similar - the way I convert my values from short to double for the purpose of the FFT calculation is incorrect. One must account for the fact that a short is 2 bytes (range from -32768 to 32768) hence one must divide the short by 32768 before casting to double. If you do not do this you will get unexpected behaviour/output from the FFT calculation.

    – JCutting8
    Nov 21 '18 at 23:11













  • Yeah, that would cause some issues. :)

    – Sub 6 Resources
    Nov 21 '18 at 23:54



















  • Super helpful answer, thank you. In addition, I was also doing something else incorrectly. For anyone else looking to do something similar - the way I convert my values from short to double for the purpose of the FFT calculation is incorrect. One must account for the fact that a short is 2 bytes (range from -32768 to 32768) hence one must divide the short by 32768 before casting to double. If you do not do this you will get unexpected behaviour/output from the FFT calculation.

    – JCutting8
    Nov 21 '18 at 23:11













  • Yeah, that would cause some issues. :)

    – Sub 6 Resources
    Nov 21 '18 at 23:54

















Super helpful answer, thank you. In addition, I was also doing something else incorrectly. For anyone else looking to do something similar - the way I convert my values from short to double for the purpose of the FFT calculation is incorrect. One must account for the fact that a short is 2 bytes (range from -32768 to 32768) hence one must divide the short by 32768 before casting to double. If you do not do this you will get unexpected behaviour/output from the FFT calculation.

– JCutting8
Nov 21 '18 at 23:11







Super helpful answer, thank you. In addition, I was also doing something else incorrectly. For anyone else looking to do something similar - the way I convert my values from short to double for the purpose of the FFT calculation is incorrect. One must account for the fact that a short is 2 bytes (range from -32768 to 32768) hence one must divide the short by 32768 before casting to double. If you do not do this you will get unexpected behaviour/output from the FFT calculation.

– JCutting8
Nov 21 '18 at 23:11















Yeah, that would cause some issues. :)

– Sub 6 Resources
Nov 21 '18 at 23:54





Yeah, that would cause some issues. :)

– Sub 6 Resources
Nov 21 '18 at 23:54




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52480832%2faudiorecorder-interpreting-fft-data-for-spectrum-analyzer%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

How to change which sound is reproduced for terminal bell?

Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents

Can I use Tabulator js library in my java Spring + Thymeleaf project?