Ultrasonic TDoA / ToA Measurement?

I am trying to make an ultrasonic flowmeter. The device has two ultrasonic tranducers (resonance frequency of about 200kHz) that sample one ultrasonic signal in the upstream directon and then immediately after one signal in the downstream direction. I know a correlation between the upstream and downstream signals might be enough but the problem is that we don't have a lot of processing power available. We have signals that are 1024 samples long each and a full cross correlation would take too long to process. The maximum sampling Rate is about 6MHz if that helps.

Since I don't come from an audio background, I am also finding it hard to figure out at what point the signal really 'arrives' and how to detect it at the resolution that I need. With the SNR that I have, it seems like the exact startng point would be lost in the noise?

No matter what I try, I seem to end up with too many wrong measurements where the time measured is exactly one wave period away from the correct value.

I know this question is far too vague but I would really appreciate any ideas on how I could understand the problem better!

Here's what the signals look like: So the main questions are:

1. What is the exact time of arrival of these two signals at the ultrasonic transducer?
2. What is the differential time of arrival between both the signals?
• You should check first if the correlation works, on a PC using matlab or numpy, not on the target device. Once confirmed, it then becomes an optimization problem. You don't mention the kind of performance that you have available, but the obvious way to accelerate a correlation is using an FFT, which transforms the complexity from an O(n * n) to an O(n log n) problem. If that's still too slow with 1024 samples, you could reduce the number of samples to, say, 512, and check if the results are still good enough. Mar 1, 2021 at 23:34
• Hey Tom, thank you for your answer! This is helpful, I will get to it right now! I know convolution translates to a multiplication in the frequency domain but how does correlation look in the frequency domain? I tried to read up on it but I did not quite understand how to practically perform correlation this way.. Do you have any hints or resources for me? Mar 2, 2021 at 9:04

The FFT-based cross-correlation is done as follows:

TX = np.fft.fft(tx)
RX = np.fft.fft(rx)
CORR = np.multiply(TX, np.conjugate(RX))
corr = np.real(np.fft.ifft(corr))


Here is a NumPy script that tries a solution.

It does the following:

• create a TX and delayed RX signal that similar to your waveform (a sine wave modulated by an envelope cosine with zeros at the front and the back and noise superimposed
• calculate the cross-correlation with SciPy's signal.correlate
• calculate the cross-correlation with FFTs
• find and print out the location of maximum correlation
• if all went well, the resulting number should be the same as the delay between TX and RX

In the graph below, you see the time domain test signal at the top, and the correlation result at the bottom (blue = signal.correlate, orange = FFT-based).

As you can see, there's a shift between the blue and the orange result. Figuring out why is an exercise for the reader (I'm learning this stuff myself). It has to do with cyclical convolutions, zero padding etc. You should be able to get a better understanding than what I'm able to offer by googling "FFT convolution". Here is one such Google result that talks more about this.

In my script, instead of doing it fundamentally right, I went the pragmatic road and changed some fixed constant to make the convolution and the FFT convolution come up with the same result.

The full script finds the maximum value of the 2 correlations, like this:

    max_corr = np.argmax(corr)-len(tx)//2
max_corr_fft = np.argmax(corr_fft) - len(corr_fft)


And prints the result:

max corr: -129
max corr fft: -129


129 matches the delay that was used to generate the RX signal.

• This is a quite nice answer but you should also provide the definition of fft_decim that you use for the reader to be able to try your implementation. Additionally, just for reference, there is a command/function both in MATLAB and Numpy called fftshift, which is the one you could use in order to "flip"/shift the resultant fft-based cross-correlation (unless of course you refer to something else :|). Mar 2, 2021 at 19:51
• I've removed fft_decim from the answer. It's still in the full gist script, with a comment of what it can be used for. Mar 2, 2021 at 23:33
• Thank you so much, Tom! Mar 3, 2021 at 13:35