I'm building an application that requires determining the arrival time of an audio signal with a very high degree of accuracy (within 1ms would be ideal) using commodity smartphone hardware. I found another user on this site who had the same requirements (minus the smartphones), and the answer given was truly excellent. That question is here:
How to send / receive a short impulse in an extremely noisy signal with high timing accuracy?
I've basically implemented what's recommended in that post... I generated some random binary data and used BPSK modulation to encode it. I used a 1600hz carrier, and 80 bits at 160 bits/second, so that the resulting audio snippet was 500ms long. (Forgive me if my terminology isn't 100% right, DSP is new to me.) Looks like this...
I've been playing this out using commodity smartphone hardware, and recording it on another smartphone. I've then been cross-correlating the original BPSK audio with the recorded audio file to find the exact time that the signal started (i.e., the time that the cross-correlation is highest).
I've found that, under very tightly controlled conditions where there's little opportunity for reverberations (e.g., outside in a field), I get highly accurate timing values. However, when I'm indoors, I find that the timings produced are almost always late. The recorded audio signal will look something like the following:
I've noticed several things about the recording:
- When the signal first starts to depart from background noise, it has several ms of "weirdness" before it starts to settle into the actual 1600hz waveform.
- When the signal switches phase 180 degrees, there will be several ms of "weirdness" again, rather than a clean switch from one phase to the other.
- The sound continues to reverberate around the room for 50-100ms after the end of the main signal.
When I compute the cross-correlation of the original signal with the recorded signal, I frequently get something like this around the onset time...
Notice that the cross-correlation peaks on two separate occasions, and that those occasions are about 10ms apart. What I'm suspecting is that (in the pictured case) the sound is reflecting in the room and that the loudest reflection is arriving about 10ms behind the direct-path sound with nearly-equivalent (actually, slightly higher!) amplitude. This would explain why my timings are usually late - the cross-correlation is identifying a reflected signal rather than the direct-path signal. I'm also sure that the impulse response of the cheap smartphone speakers and microphones are not helping the situation - they probably have quite a bit of delay and distortion in them.
Is there anything I can/should be doing to help identify the direct-path sound and ignore the reflections? Unfortunately, I won't know the acoustics of the room in advance, so I can't convolve the original signal with the room impulse response. Is there anything else I can do to separate these arrival times?
The only idea I've had is a simple heuristic - if the cross-correlation values peak multiple times, those peaks are within X ms of each other, and the amplitude of those peaks is within Y% of each other, always choose the earlier one, assuming the later is a reflection.
Anything else I should be thinking about? Some sort of filtering?
EDIT IN RESPONSE TO telemeister's THOROUGH ANSWER:
Auto-correlation for my BPSK signal looks good - one peak with two side lobes.
The suggestion to use a higher frequency for better resolving power was helpful - switching from 1600hz to 6400 hz seemed to make things more accurate.
However, I'm still finding that the cross-correlation often peaks shockingly late. For example, take a look at this recording. This is a device recording itself playing a 6400hz BPSK signal. The position of the cursor in Audacity marks the place where the signal starts to deviate from background noise (at least, to the naked eye).
However, take a look at the cross-correlation output, with the exact same moment marked by the cursor in Audacity.
What you'll notice is that the cross-correlation peaks ~100 samples after the audio recording starts to deviate from background noise. And, based on the cross-correlation, anyway, there doesn't seem to be any echo in this case - there's no follow-up spikes in the cross-correlation, whether weaker or stronger.
How should I interpret this, especially given that this is the device recording itself? It doesn't seem to be a reflection. Is it something else? Speaker or microphone taking a second to start fully representing the signal? Something getting up to a resonant frequency? Not sure if this even is answerable, but I'm curious to know if anybody has thoughts.