Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get ultrasound from android using frequency

I want to get ultrasound from any Android device from example an ultrasound with a frequency between 18KHz and 19KHz.

I use the code below to calculate frequency but it doesn't seems to get me the correct frequency. The frequency i get stay between 11 KHz and 13KHz.

private void        calculateFrequency()
{
    // 1 - Initialize audio
    int channel_config = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    int format = AudioFormat.ENCODING_PCM_16BIT;
    int sampleRate = 8000;
    int bufferSize = 2048;

    if (bufferSize < AudioRecord.getMinBufferSize(sampleRate, channel_config, format))
        bufferSize = AudioRecord.getMinBufferSize(sampleRate, channel_config, format);
    AudioRecord audioInput = new AudioRecord(AudioSource.MIC, sampleRate, channel_config, format, bufferSize);

    // 2 - Get sound
    byte[] audioBuffer = new byte[bufferSize];
    audioInput.startRecording();
    int nbRead = audioInput.read(audioBuffer, 0, bufferSize);
    audioInput.stop();
    audioInput.release();

    // 3 - Transform to double array
    double[] micBufferData = new double[bufferSize];
    final int bytesPerSample = 2; // As it is 16bit PCM
    final double amplification = 100.0; // choose a number as you like
    for (int index = 0, floatIndex = 0; index < nbRead - bytesPerSample + 1; index += bytesPerSample, floatIndex++) {
        double sample = 0;
        for (int b = 0; b < bytesPerSample; b++) {
            int v = audioBuffer[index + b];
            if (b < bytesPerSample - 1 || bytesPerSample == 1) {
                v &= 0xFF;
            }
            sample += v << (b * 8);
        }
        double sample32 = amplification * (sample / 32768.0);
        micBufferData[floatIndex] = sample32;
    }

    // 4 - Create complex array
    Complex[] fftTempArray = new Complex[bufferSize];
    for (int i=0; i<bufferSize; i++)
    {
        fftTempArray[i] = new Complex(micBufferData[i], 0);
    }

    // 5 - Calculate FFT
    Complex[] fftArray = FFT.fft(fftTempArray);

    // 6 - Calculate magnitude
    double[] magnitude = new double[bufferSize / 2];
    for (int i = 0; i < (bufferSize / 2); i++)
    {
        magnitude[i] = Math.sqrt(fftArray[i*2].re() * fftArray[i*2].re() + fftArray[i*2].im() * fftArray[i*2].im());
    }

    // 7 - Get maximum magnitude
    double max_magnitude = -1;
    for (int i = 0; i < bufferSize / 2; i++)
    {
        if (magnitude[i] > max_magnitude)
        {
            max_magnitude = magnitude[i];
        }
    }

    // 8 - Calculate frequency
    int freq = (int)(max_magnitude * sampleRate / bufferSize);

    ((TextView) findViewById(R.id.textView1)).setText("FREQUENCY = " + freq + "Hz");
}

I'm using two phones : one the send ultrasound with this app and the other one to get this ultrasound. I used this question as start point where I Took FFT and Complex classes.

What's wrong with my code ?

like image 691
Drakkin Avatar asked Mar 18 '23 00:03

Drakkin


2 Answers

In order to get a correct non-aliased frequency estimate, one has to use a sample rate more (perhaps 10% to 20% greater to avoid filter roll-off) than twice the highest frequency in the audio input, thus more than twice the highest frequency you want to find.

This is due to the required Nyquist rate of the sampling theorem.

So if you want to find a 19 kHz signal, a sampling rate closer to 48000 is required.

like image 104
hotpaw2 Avatar answered Mar 23 '23 18:03

hotpaw2


Steps 7 and 8 are not quite right - you need to use the index of the FFT bin with the largest magnitude in order to determine the frequency:

    // 7 - Get maximum magnitude
    double max_magnitude = -1;
    int max_magnitude_index = -1;
    for (int i = 0; i < bufferSize / 2; i++)
    {
        if (magnitude[i] > max_magnitude)
        {
            max_magnitude = magnitude[i];
            max_magnitude_index = i;
        }
    }

    // 8 - Calculate frequency
    int freq = (int)(max_magnitude_imdex * sampleRate / bufferSize);

And as noted by @hotpaw2, your sample rate is way too low at 8 kHz - it would need to be at least 44.1 kHz, preferably 48 kHz.

like image 22
Paul R Avatar answered Mar 23 '23 18:03

Paul R