Jameson February 2016

Changing block size causes FFT analysis to fail

I'm trying to record audio and get the frequencies. I can successfully do so with a sampling rate of 44100 and a block size of 2048. The bin size is around 20, I believe. However, if I try to increase the block size to 4096, then rather than get accurate frequencies, I just get the same inaccurate frequency back, with no magnitude/decibels.

My recording task is as follows:

 private class RecordAudio extends AsyncTask<Void, double[], Boolean> {

    @Override
    protected Boolean doInBackground(Void... params) {

        int bufferSize = AudioRecord.getMinBufferSize(frequency,
                channelConfiguration, audioEncoding);
        audioRecord = new AudioRecord(
                MediaRecorder.AudioSource.DEFAULT, frequency,
                channelConfiguration, audioEncoding, bufferSize);
        int bufferReadResult;
        short[] buffer = new short[blockSize];
        double[] toTransform = new double[blockSize];
        try {
            audioRecord.startRecording();
        } catch (IllegalStateException e) {
            Log.e("Recording failed", e.toString());

        }
        while (started) {
            if (isCancelled() || (CANCELLED_FLAG == true)) {

                started = false;
                //publishProgress(cancelledResult);
                Log.d("doInBackground", "Cancelling the RecordTask");
                break;
            } else {
                bufferReadResult = audioRecord.read(buffer, 0, blockSize);

                for (int i = 0; i < blockSize && i < bufferReadResult; i++) {
                    toTransform[i] = (double) buffer[i] / 32768.0; // signed 16 bit
                }

                transformer.ft(toTransform);

                publishProgress(toTransform);

            }

        }
        return true;
    }
    @Override
    protected void onProgressUpdate(double[]...progress) {

        int mPeakPos = 0;
        double mMaxFFTSample = 150.0;
        for (int i = 100;        

Answers


jaket February 2016

You'll need to look closer at the documentation of the RealDoubleFft.ft function. The values going into the function are real but the values coming out are complex FFT coefficients such that toTransform[0] is the real part of the first coefficient, toTransform[1] is the imaginary part of the first coefficient and so on. The final array size is the same but since complex numbers each take up 2 doubles then there are a total of N/2 coefficients where the last one is the coefficient for sampleRate/2.

Next since you are interested in the magnitude you need to compute the magnitude of the complex numbers. For a complex number x = a + bj, the magnitude |x| = sqrt(a*a + b*b)

    double maxMag = 0;
    int peakIndex = 0;
    for (int i = 0; i < progress[0].length/2; i++)
    {
        double re = progress[i*2];
        double im = progress[i*2+1];
        double mag = Math.sqrt(re*re + im*im);
        if (mag > maxMag)
        {
            peakIndex = i;
            maxMag = mag;
        }
    }

    double peakFreq = sampleRate/fftLen * i/2; // might need a bit of tweaking.
    double magInDb  = 20*Math.log10(mag);

Post Status

Asked in February 2016
Viewed 1,507 times
Voted 7
Answered 1 times

Search




Leave an answer