Interpretation of Sonar Raw Data

Hey everyone,
we are using your ‘Ping Sonar Altimeter and Echosounder’ to detect the
underground while measuring on a moving boat.
Back from the site of the measurement campaign we have trouble with the
interpretation of the recorded data. Our intension was to manually
analyse the echo data of the underground where the confidence wasn’t
100%.
To achieve this, we successfully read distance, confidence, scan_length,
scan_start and profile_data and created plots for each ping of the
profile_data. After that, we calculated backwards the index where the
underground was detected. We are using this formula:

scale_factor = (scan_length - scan_start)/199
index_underground = distance / scale_factor
(we converted each length from mm to m, for better usage)

After that, the obtained index is added as a red line to the plot.
Additionally we used a color-map to validate the plotted data with the
given confidence. In our case ‘red’ means 0% confidence and ‘dark blue’
100%. Please see the attached file.
Looking at a row of e.g. 100 pings, we do not see any adjustment of
index_underground even though the intensity of the data clearly does
not match the index_underground. The confidence is always 100%.

Did we do something wrong during the calculation of the
index_underground? Could you please help us to interpret the echo data
correctly?
We are very grateful for any help.

1 Like

Hi @luisa, welcome to the forum :slight_smile:

I’m afraid I’m not really sure what you’re describing. The image you attached seems to be a stack of several graphs, and they don’t have axis labels or a legend.

Is this supposed to indicate that you’re using 200 sample points? If I’m understanding what you’re trying to do here correctly then I don’t think you should be taking off scan_start from scan_length, you should be taking it off from distance, e.g.

\begin{align} n_{samples} &= 200\\ \text{measurement_index} &= \frac{\text{distance} - \text{scan_start}}{\text{scan_length}}\times n_{samples} \end{align}

Are you saying the position of the vertical red line doesn’t move throughout the graph stack? The bottom half shows multiple slightly different positions for it.

Assuming distance is what’s returned by the Ping Sonar, note that the distance estimate is from a target tracking algorithm - it’s calculated from a combination of peak finding and temporal averaging, which means fast changes in actual distance will take a few pings before they show up as a stable and full-confidence result.

thank you @EliotBR :slight_smile:
Yes I’m sorry, the graph without any legend is hard to get.
The x-axis displays the samples of profile_data (from 0 to 200). The values on each ping are plotted as a curve within a range of 0 to 255 (0 bottom, 255 up). On the y-axis is only the ping number. In our case, starting from the top with 2700 to the bottom.
To make this clear: every single plot shows sample indices of profile_data vs sample values of profile_data. The graph shows the plots of 100 pings.

You are right, we used 200 sample points per ping. In our calculation we used 199 because there are only 199 gaps between the sample points (instead of 200).

Let me try to explain on this example what we are aiming for:
We want to determine where exactly the underground was found in profile_data. We are getting the values from the Python API with get_profile.
https://docs.bluerobotics.com/ping-python/classPing_1_1Ping1D_1_1Ping1D.html#a6b36d26dddf45663f1c18f05286c4182
scan_length = 7822
distance = 5241
scan_start = 0 (always zero)

Now we want to calculate the specific sample, where the underground was detected.
By using our formula we get:
scale_factor = 7822 / 199 =~ 39,3
index_underground = 5241 / 39,3 =~ 133
The result of index_underground is in the range of the samples indices in profile_data.

Trying your formula:
measurement_index = (5241 / 200 ) * 7822 =~ 204975
This is far out of the range of samples indices in profile_data.

In this sketch you see the measured data. Based on the target tracking algorithm, we assume that the first really high peak will be chosen as the depth of the underground. But according to our calculation we get the result shown in the sketch.

Now we are curious why we get this result and not the expected one.

If you’re using zero-based indexing (which it seems you are) then 199 is the correct number to use in your calculation, because when the scale_factor is 1 the index should be the last sample, and if you’re counting from 0 then 199 is the 200th sample. The “gaps” reasoning doesn’t really make sense to me, but the number should be fine :slight_smile:

My bad - I forgot to flip the fraction apparently. I’ve updated the equation in my comment, but it’s the same as yours anyway (just in one step instead of two).

Peak finding finds maximal values, not steep slopes (i.e. the peak is on the signal, not its derivative). Consider that a cliff at the bottom of a mountain may be the steepest portion, but it’s not the peak. Presumably that approach helps avoid large variability when trying to detect soft riverbeds/sea floors that may have a slow and smooth density gradient.

I’m unsure what the algorithm does when faced with a saturated signal (a peak with multiple full intensity values in a row, giving a flat top) - it may choose the first top value, or the middle one, or may use the derivatives to try to estimate where the actual top is most likely to be, or something else. Saturated signals are very difficult to calculate meaningful results from, because there’s a lot of missing data (it’s like looking at a photo of a mountain, but the top is cropped off - how can you tell where the peak is?).

If you’re getting a lot of saturation (which looks to be the case in your plots) then it would be helpful to reduce the gain, and/or reduce the transmit duration. It may be worth turning on auto_mode, but if that’s already on then it seems to be performing somewhat poorly for your use-case, in which case you should try switching to manual mode (disable auto_mode), so you can set a more appropriate gain manually. Note that in manual mode you also need to control the scan range yourself.

As a note, if you’ve found and tested some alternative algorithm that gives more accurate distance estimates, you can of course apply that on the profiles in post-processing and use those results instead - it just won’t necessarily agree with the estimates provided by the sonar. You’re also welcome to share and discuss algorithms here if you’d like to :slight_smile:

Thank you @EliotBR for your interesting answer. That explains our trouble very well…

As far as we can tell now, auto_mode was turned on. We will test the manual mode as soon as possible and then I’ll share our results.

Do I understand you correctly that our data is not really reliable for an exact underground detection?
Would it be possible to change the value of the confidence in such a case? 100% confidence in our case is hard to believe with your explanation.

The firmware doesn’t have any configuration options for the confidence, so that’s at least not immediately possible.

The control algorithm is closed source, and I don’t have access to it so unfortunately don’t know how it calculates its confidence estimate. You make a valid point that 100% confidence doesn’t seem very logical when a peak is effectively impossible to find in a region of saturated data, so I’ve raised this internally to see if that can be changed. Until there’s a new firmware available with a change like that though, that won’t be possible for your device except in post-processing with your own algorithm.

Following up on this, that’s something that can be fixed, but because it’s not a particularly common issue I’ve been told it’s not a high priority for us at the moment.

I’ve raised an issue for it here, so you can track any progress on it :slight_smile:

1 Like

Hello @EliotBR !

I’ve been reading a few topics lately to try and understand some aspects of raw profile data. I’ve done the same style of graphs, but here with only the plot of values I’ve been able to recover from measurements taken in the air. Here’s an example of a measurement taken at a height of 0.7 m from a flat surface.

However, there’s one thing I don’t understand about these famous graphs. What can be recovered are 200 points corresponding to the intensity of returns taken at regular intervals. What puzzles me a little is that if I repeat this measurement with a surface 2 m away (in theory, because measurement in air doesn’t work as well as in water), I’ll also have 200 return values. So, on the one hand, I have 200 values for a distance of 0.7 m and, on the other, 200 values for a distance of 2 m. So, how do I know the time interval between each of these 200 values? My aim would be to understand this x-axis as a function of time and not of the number of points (1-200). Is there any way of finding out what time interval elapses between each of these 200 points? I think I’m missing something, but what I’d really like to do is to be able to scale this axis as a function of time, rather than just successive points. I imagine that the time interval between each of these points is indeed regular, but I’m trying to understand its value in the time domain. Also, what do the values 0 to 250 on the y-axis correspond to? How are they set?

Ps: I’d like to take this opportunity to ask if there is a radiation pattern for Ping2D? In general, this is indicated in the data sheet, but I can’t find one here. Here’s an example of a radiation pattern found at a Chinese transducer manufacturer (not to mention them). If you can give me this information, it would be a great help in my research.
image

Hi @Lulu :slight_smile:

Each profile message includes fields for scan_length [mm] and profile_data_length [unitless] (number of samples in the profile), and the internal speed of sound value is user defined (1,500,000 mm/s by default[1]), so the sampling duration (similar to camera exposure) for a given sample is just

\Delta t_s = \frac{\text{scan_length}}{\text{profile_data_length}\cdot v_s}

Is there a particular reason for this? It’s generally more intuitive to scale by distance, using the scan_length for scaling and the scan_start as an offset.

The “return strength measurement data” (as described by the profile message documentation) is an array of bytes (0-255) representing the energy/strength of the transducer vibration during each sample period.

In case it’s of interest,

You’ll note that those values are saturated while the transducer is transmitting (at the start of the scans, including some extra time for the vibrations of the device to die down after a pulse is sent), and then low while waiting for echoes, with later values being determined by the strength of echoes (or noise in the transducer’s frequency range).

We’ve done some testing around this, but the data needs some cleaning up before we can provide a beam plot, and we don’t currently have an estimate of when that will be completed/released.

By the way, our Ping2 Sonar is the second major version of a 1D sensor (which is why it uses the ping1d message set) - ping2D would be a multibeam or something. We have found the name to be confusing though, so we’re intending to change it (likely to Ping Sonar v2 or something) to reduce that confusion in future.


  1. although you might have adjusted it to suit your water conditions, or set it to ~343,000 mm/s if you’re trying to get reasonable distance estimates in air ↩︎

Hello @EliotBR ! Thank you again for your fast reply :slight_smile:

Each profile message includes fields for scan_length [mm] and profile_data_length [unitless] (number of samples in the profile), and the internal speed of sound value is user defined (1,500,000 mm/s by default), so the sampling duration (similar to camera exposure) for a given sample is just

Δts=scan_length/(profile_data_length⋅vs)

Ok great! I understand better. That said, I have a few questions about the therms of this formula. The first is scan_length. I have trouble understanding this variable. For example, I have a measurement that gives me a distance of 0.65 m (with 100% confidence) and the corresponding scan_lenght is 1002 mm. Why are these two values different? Do they correspond to different things?

The second term is profile data length. In your message, I get the impression that this value can be changed by the user. However, in a previous post, you said : “As I understand it our Ping Sonar firmware is hardcoded to send 200 bins in each ‘profile’ array, regardless of the configured range, which is why we specify the range resolution as “0.5% of range” in the technical details on the product page.” So, my question is : can it be changed and if so, what is the python command ?

Is there a particular reason for this? It’s generally more intuitive to scale by distance, using the scan_length for scaling and the scan_start as an offset.

It’s quite special, but my approach is to reconstruct what I call the “full wave form”, which is rather counter-intuitive because your objective is to be able to provide an answer in terms of distance. My approach is therefore the opposite, and is to be able to reconstitute the shape of the signal (in the time domain).

You’ll note that those values are saturated while the transducer is transmitting (at the start of the scans, including some extra time for the vibrations of the device to die down after a pulse is sent), and then low while waiting for echoes, with later values being determined by the strength of echoes (or noise in the transducer’s frequency range).

Do you think that by setting the gain differently, I could get rid of this saturation while the transducer is emitting? I’d like to get rid of it because in my quest to reconstruct the signal, it distorts my data (due to the extreme values that come out) ?

Thank you for your very enlightening answers. I learn something new every day !

Yes - the sonar’s target distance estimate is based on the values it’s measuring (both within a profile, and over time), whereas the scan_length is the distance range over which a given profile includes samples. Perhaps this diagram will help to explain the breakdown of the different variables involved:

Note that the scan_start is typically 0 mm, but that is possible to control with the set_range function, if you’re operating the sonar in manual mode (using set_mode_auto(0)).

No, it is not directly user-controllable with the current protocol specification. That said, that may change in future, and the protocol does not disallow the firmware from changing it, so since it’s included with each profile messages I thought it made more sense to include the variable in the calculation instead of substituting it for a hardcoded value that may not always be correct.

In my diagram example I decided to keep things clear and save on drawing time, so only drew 24 samples.

Ok, so basically static instances of the “Return Plot” shown in Ping Viewer, but without the mirroring over the axis? :slight_smile:

Distance and time are effectively interchangeable here, because the speed of sound is assumed to be constant, so the only difference is a constant scaling factor.

Reducing the receiver gain (and setting a lower transmit duration) both reduce the measured ring-down time of the device, but it’s not practical to completely avoid a saturated signal at the start, because the sound wave spreads out and gets absorbed as it travels, so the start is the strongest the signal will ever be.

If you know that the region of space you care about is some minimum distance away then you can at least avoid having the saturated region within the profile data you look at by either ignoring the samples that are closer than that in your code, or starting the sampling after that region with the scan_start setting.

1 Like

Hi @EliotBR ! Thank you again !

Ok great ! Can i use this in my thesis to explain how measures are taken ? Now I can output grahics with a temporal x-axis, thanks to you (image 1). Having said that, I’m still wondering whether the strength response from 0 to 255 is a response in terms of pressure (dB) or not ? I’m interested to know how it’s obtained.

Ok, so basically static instances of the “Return Plot” shown in Ping Viewer, but without the mirroring over the axis? :slight_smile:

That’s exactly what I’m trying to have ! If you know of an easier way to do it, I’d love to hear about it. At the moment, I’m stuck because the values of the return strength measurements go from 0 to 255 (see image 1) whereas I’d like both positive and negative values (amplitude values). My ultimate goal would be to be able to provide this kind of graph with positive and negative values (full wave form, image 2) but I still don’t understand how to get there. That’s why I’m wondering if you have any leads.

Image 1 :

Image 2 :
image

To give some context to my work: I’m doing a dissertation at the Catholic University of Leuven on the detection and classification of buried water mines. The project also includes a signal filtration phase, which is why I’m asking you for so much help. The idea is to be able to adapt existing GPR (Ground-Penetrating Radar) methods to underwater detection. Here’s an article I based my project on, which was also written by my promoter: “Lambot, S., Slob, E. C., van den Bosch, I., Stockbroeckx, B., & Vanclooster, M. (2004). Modeling of ground-penetrating radar for accurate characterization of subsurface electric properties. IEEE transactions on geoscience and remote sensing, 42(11), 2555-2568.".

I realize the analogy between acoustic (elastic) waves and electro-magnetic waves. If I succeed, I’ll be able to publish my article and mention your sensor. I am convinced that the use of this affordable sensor can be demonstrated in defense applications (military and civilian). In a few months’ time, I’ll be publishing an article in a scientific journal if our team succeeds in this analogy.
I will keep you posted about the results if you are still interested in it :slight_smile: