【问题标题】:Get ultrasound from android using frequency使用频率从android获取超声波
【发布时间】:2014-12-27 23:51:24
【问题描述】:

我想从任何 Android 设备获取超声波,例如频率在 18KHz 和 19KHz 之间的超声波。

我使用下面的代码来计算频率,但它似乎没有让我得到正确的频率。我得到的频率保持在 11 KHz 和 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");
}

我正在使用两部手机:一部使用this app 发送超声波,另一部用于获取超声波。 我使用这个question 作为我学习 FFTComplex 类的起点。

我的代码有什么问题?

【问题讨论】:

  • 好主意。你能帮我解释一下吗:int freq = (int)(max_magnitude * sampleRate / bufferSize);.
  • 我用了这个答案link:见最后一行代码
  • 错误出现在第 7 步和第 8 步中 - 您需要最大幅度的 index 来确定频率,而不是幅度本身。仔细看看链接答案中的伪代码。
  • 您的采样率必须超过每个 nyquist 感兴趣频率的两倍。
  • 你如何修复幅度指数中的错误值?它有时像 i = max_length_of_magnitude 和频率中的值 = 46000+

标签: java android signal-processing fft audiorecord


【解决方案1】:

为了获得正确的非混叠频率估计,必须使用比音频输入中最高频率两倍的采样率(可能大 10% 到 20% 以避免滤波器滚降),因此更多比您想要找到的最高频率的两倍。

这是由于采样定理所需的奈奎斯特率。

因此,如果您想找到 19 kHz 的信号,则需要接近 48000 的采样率。

【讨论】:

    【解决方案2】:

    第 7 步和第 8 步不太正确 - 您需要使用最大幅度的 FFT bin 的 index 来确定频率:

        // 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);
    

    正如@hotpaw2 所指出的,您的采样率在 8 kHz 时太低了 - 它至少需要为 44.1 kHz,最好是 48 kHz。

    【讨论】:

    • 感谢您的回答。我将采样率设置为 48kHz,并按照您所说的更改了步骤 7 和 8。当我在不产生声音的情况下尝试它时,频率听起来不错 40 - 200 Hz。但是当我从第二部手机产生 19kHz 的超声波时,我没有得到好的值,有时我得到 23kHz。你知道手机真的能产生超声波吗?您认为从我的计算机扬声器产生超声波会更好吗?
    • 电话、计算机等中的大多数消费级换能器(麦克风和扬声器)在约 15 kHz 以上的频率下会遇到困难,因为它们并不是真正为“高保真”用途而设计的。您可能会发现在这个频率范围内很难做任何可靠的事情。
    • @PaulR 嘿伙计,你知道为什么有时 max_magnitude_index 会返回很大的值吗?如果我有 500 赫特,那么频率就不对了,应用程序有时会将其计算为 45000/49000 和其他大数字?
    • @Peter:听起来像一个错误——也许用你的代码和尽可能多的背景信息发布一个新问题?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-18
    • 2021-06-07
    • 1970-01-01
    • 1970-01-01
    • 2017-05-22
    • 2019-05-20
    • 1970-01-01
    相关资源
    最近更新 更多