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 ?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With