Get ultrasound from android using frequency

I want to receive ultrasound from any android device from the ultrasound example at 18kHz to 19kHz.

I am using the below code to calculate the frequency but it doesn't seem to give me the correct frequency. The frequency I remains between 11 kHz and 13 kHz.

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 am using two phones: one is sending ultrasound with this app , and the other for receiving this ultrasound. I used this question as a starting point where I took the FFT and Complex classes .

What's wrong with my code?

+3


source to share


2 answers


To get a correct estimate of the un-smoothed frequency, you need to use a sampling rate higher (10-20% higher to avoid filter dropping) than twice the highest frequency in the audio input, thus more than twice as much as you want to find.

This is due to the required Nyquist norm in the sampling theorem.



So, if you want to find a 19 kHz signal, you need a sampling rate close to 48000.

+4


source


Steps 7 and 8 are not entirely correct - you need to use the highest FFT bin index 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 @ hotpaw2 pointed out, your sample rate is too low at 8 kHz - it should be at least 44.1 kHz, preferably 48 kHz.

+3


source







All Articles