Hi all,
The project I am trying out is to do acoustic ranging using a Teensy 4 + speaker + I2S microphone. The issue I need help with is the large variance in the time elapsed between the sound being sent and heard.
I am using 2 threads, one to play the 8khz sine tone periodically and another running FFT to detect the pulse. When the amplitude of the speaker is raised, I set an "elapsedMicros sincePing" timer variable to 0, and when the other microphone hears it in the other thread I display that time. In theory this time can be used to calculate the distance of the speaker to the microphone by using the speed of sound in air. These are the results I am getting for now:-
(When a few cm away from the mic)
(when about 30cm away from the mic)
These numbers don't really make sense since they are inconsistent, and become more so once the speaker is moved further away.
I think I have a few things I can check to make sure there isn't something in the background which is a problem, like for example the frequency the FFT is being computed at being constant? Or maybe there is a better way of getting the elapsed time between the signals? Any inputs would be appreciated. Thanks!
-Akshay
The project I am trying out is to do acoustic ranging using a Teensy 4 + speaker + I2S microphone. The issue I need help with is the large variance in the time elapsed between the sound being sent and heard.
Code:
/*
SD -> pin 8 (in1)/pin 5 (in2)
L/R -> GND/VCC (left/right channel)
WS -> pin 20 (LRCLK1)/pin 3 (LRCLK2)
SCK -> pin21 (BCLK1)/pin 4 (BCLK2)
*/
/*
Sample rate is 44.1khz
Therefore max frequency is 22.05khz
For FFT1024 we have each bin = 22.05/512 = 43.06 hz
For FFT256 we have each bin = 22.05/128 = 172.26 hz
for 8khz bin 45-49 for FFT256
For 8khz 184-189 for FFT1024
*/
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <TimeLib.h>
#include "TeensyThreads.h"
// GUItool: begin automatically generated code
AudioSynthWaveformSine sine1;
AudioAmplifier amp1;
AudioOutputI2S2 i2s2;
AudioInputI2S i2s1; //xy=500,322
AudioAnalyzeFFT1024 fft1024_1; //xy=701,316
AudioAnalyzeFFT256 fft256_1;
//AudioConnection patchCord1(i2s1, 0, fft1024_1, 0);
AudioConnection patchCord1(i2s1, 0, fft256_1, 0);
AudioConnection patchCord2(sine1, 0, amp1, 0);
AudioConnection patchCord3 (amp1, 0, i2s2, 0);
IntervalTimer pulse;
// GUItool: end automatically generated code
const float freq = 8000.0;
const float amp = 0.8;
const float g = 0.5;
elapsedMillis sincebeep;
elapsedMillis sincesilence;
int t1;
int t2;
bool first_ping = false;
elapsedMicros sincePing;
const double air_speed = 0.0343;
void setup() {
//Serial.begin(9600);
AudioMemory(70);
while (!Serial) ; // wait until Arduino Serial Monitor opens
setSyncProvider(getTeensy3Time);
if (timeStatus() != timeSet)
Serial.println("Unable to sync with the RTC");
else
Serial.println("RTC has set the system time");
//while (!Serial && millis () < 3000);
// delay (6000);
//AudioNoInterrupts();
//AudioMemory (2);
amp1.gain (0.8);
sine1.amplitude(0.0);
sine1.frequency(freq);
//AudioInterrupts();
Serial.println("setup done");
// Timer1.initialize(10000000);
// Timer3.initialize(11000000);
// Timer1.attachInterrupt(beepStart);
// Timer3.attachInterrupt(beepEnd);
threads.addThread(beep);
threads.addThread(FFT);
// pulse.begin(beep, 500000); //call beep every 5 secs
}
void printDigits(int digits) {
// utility function for digital clock display: prints preceding colon and leading 0
Serial.print(":");
if (digits < 10)
Serial.print('0');
Serial.print(digits);
}
void digitalClockDisplay() {
// digital clock display of the time
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.print(" ");
Serial.print(day());
Serial.print(" ");
Serial.print(month());
Serial.print(" ");
Serial.print(year());
Serial.println();
}
time_t getTeensy3Time()
{
return Teensy3Clock.get();
}
//void beepStart()
//{
// sine1.amplitude(0.8);
// sincePing = 0;
//}
//
//void beepEnd()
//{
// sine1.amplitude(0.0);
//}
void beep()
{
while (1) {
if (sincebeep >= 50)
{
sine1.amplitude(0.0);
sincebeep = sincebeep - 50;
}
if (sincesilence >= 10000)
{
sine1.amplitude(0.8);
sincePing = 0;
sincesilence = sincesilence - 10000;
first_ping = false;
}
threads.yield();
}
}
void FFT()
{ while (1) {
t1 = micros();
if (fft256_1.available()) {
// Serial.println(fft256_1.read(45,49)*100);
if (fft256_1.read(45, 49) * 100 > 0.4 && first_ping == false)
{
digitalClockDisplay();
Serial.print("heard ping, delay of :");
// long long int t3 = t2-t1;
noInterrupts();
Serial.println(sincePing);
interrupts();
t2 = micros();
// Serial.println(t2-t1);
double time_in_usec = sincePing;
double dist = air_speed * (time_in_usec);
// Serial.print("distance :");
// Serial.println(dist);
first_ping = true;
}
}
}
}
//loop time check
void loop() {
}
I am using 2 threads, one to play the 8khz sine tone periodically and another running FFT to detect the pulse. When the amplitude of the speaker is raised, I set an "elapsedMicros sincePing" timer variable to 0, and when the other microphone hears it in the other thread I display that time. In theory this time can be used to calculate the distance of the speaker to the microphone by using the speed of sound in air. These are the results I am getting for now:-
(When a few cm away from the mic)
Code:
13:41:13 1 5 2020
heard ping, delay of :22005
13:41:23 1 5 2020
heard ping, delay of :22025
13:41:33 1 5 2020
heard ping, delay of :22005
13:41:43 1 5 2020
heard ping, delay of :10603
13:41:53 1 5 2020
heard ping, delay of :31624
13:42:03 1 5 2020
heard ping, delay of :28204
13:42:13 1 5 2020
heard ping, delay of :26005
13:42:23 1 5 2020
heard ping, delay of :23805
13:42:33 1 5 2020
heard ping, delay of :22005
13:42:43 1 5 2020
heard ping, delay of :22005
13:42:53 1 5 2020
heard ping, delay of :22005
(when about 30cm away from the mic)
Code:
13:49:46 1 5 2020
heard ping, delay of :44005
13:50:16 1 5 2020
heard ping, delay of :31257
13:50:26 1 5 2020
heard ping, delay of :27837
13:50:36 1 5 2020
heard ping, delay of :25637
13:50:45 1 5 2020
heard ping, delay of :22218
13:50:56 1 5 2020
heard ping, delay of :22005
13:51:06 1 5 2020
heard ping, delay of :22006
13:51:16 1 5 2020
heard ping, delay of :22005
13:51:26 1 5 2020
heard ping, delay of :22005
13:51:36 1 5 2020
heard ping, delay of :32001
13:51:46 1 5 2020
heard ping, delay of :29801
These numbers don't really make sense since they are inconsistent, and become more so once the speaker is moved further away.
I think I have a few things I can check to make sure there isn't something in the background which is a problem, like for example the frequency the FFT is being computed at being constant? Or maybe there is a better way of getting the elapsed time between the signals? Any inputs would be appreciated. Thanks!
-Akshay