2014-10-31 36 views
3

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

我使用下面的代码来计算频率,但它似乎并没有得到我正确的频率。我得到的频率停留在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作为起始点,我接受了FFT复杂类。

我的代码有什么问题?

+0

不错的主意。你能否为我解释一下:'int freq =(int)(max_magnitude * sampleRate/bufferSize);'。 – FelixMarcus 2014-10-31 15:59:12

+0

我用这个答案[链接](http://stackoverflow.com/a/7675171/1770833):请参阅代码的最后一行 – Drakkin 2014-10-31 16:02:35

+0

错误在步骤7和8 - 您需要最大量级的*索引*以确定频率,而不是幅度本身。更仔细地看链接答案中的伪代码。 – 2014-11-01 08:37:54

回答

4

为了得到正确的无锯齿频率估计值,必须使用比音频输入中的最高频率高两倍的采样率(可能大10%至20%以避免滤波器滚降),因此是您想要找到的最高频率的两倍以上。

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

所以,如果你想找到一个19千赫的信号,就需要一个接近48000的采样率。

3

步骤7和8是不完全正确 - 你需要为了与最大的幅度为使用FFT仓的指数确定频率:

// 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。

+0

谢谢你的回答。我将采样率设置为48kHz,并按照您的说法改变步骤7和8。当我在没有发出声音的情况下尝试时,频率听起来不错,40 - 200 Hz。但是当我从第二部手机产生19kHz的超声波时,我没有得到好的数值,有时我得到23kHz。你知道一部手机是否真的可以产生超声吗?你认为从我的计算机扬声器中产生超声会更好吗? – Drakkin 2014-11-03 08:33:27

+1

手机,电脑等中的大多数消费级传感器(麦克风和扬声器)在高于〜15 kHz的频率下都很困难,因为它们并非真正用于“高保真”应用。你可能会发现很难在这个频率范围内做任何可靠的事情。 – 2014-11-03 08:35:42

+0

@PaulR嘿哥们,你知道为什么有时候max_magnitude_index会返回很大的价值吗?频率然后不正确,就像我有500赫兹,应用程序有时计算它为45000/49000和其他大数字? – Peter 2016-08-22 12:08:59