Right, that probably just means the noise isn’t very consistent across pings (which would make sense), so when you’re using a smaller step size then the sonar display shows narrower bars, and the noise is less obvious.
Thanks for the colours. Here’s a comparison of those with a couple of the Ping Viewer schemes (and a custom one that I like to use):
Note that I’ve set the distance to minimum, and the maximum transmit duration for purposes of easier colour comparisons.
Looking back at your videos it seems like you have some light green values in the noise, so clearly it’s quite strong (almost the strongest). That’s definitely not a normal display in the sensor, so reducing the electrical noise should help quite a bit with your visibility
Our colour schemes that come default with Ping Viewer only specify a small number of colours, which get interpolated between for the 255 intensity values. The code you shared seems to instead only use the 16 specified values, and truncate/bucket the data to fit across those colours. Your code also seems to use a BGR colour-ordering, whereas Ping Viewer uses RGB.
To test with the equivalent of our ‘thermal blue’ theme you can use the following:
self.colour_range = {
0: (95, 34, 5),
1: (90, 69, 31),
2: (86, 105, 58),
3: (82, 141, 85),
4: (73, 173, 115),
5: (52, 197, 155),
6: (31, 220, 195),
7: (10, 243, 235),
8: (0, 233, 237),
9: (0, 191, 203),
10: (0, 149, 169),
11: (0, 106, 135),
12: (1, 79, 120),
13: (3, 58, 110),
14: (5, 36, 101),
15: (8, 15, 92)
}
To create that I wrote the following Python code, which interpolates a larger number of colours from a small specified set, using numpy, and scipy’s interpolation:
from scipy.interpolate import interp1d
import numpy as np
from pprint import pprint
def rgb_bgr_swap(colours):
""" Returns an Nx3 numpy array of colours with columns 0 and 2 swapped. """
swapped = colours.copy()
swapped[:, 0], swapped[:,2] = colours[:,2], colours[:,0]
return swapped
class Interpolator:
def __init__(self, colours, input_max=255, input_min=0):
self.colours = np.asarray(colours)
self.input_max = input_max
self.input_min = input_min
self._interp = interp1d(np.linspace(input_min, input_max, len(colours)), colours.T)
def __call__(self, query_points, output_dtype=np.uint8):
return self._interp(query_points).T.astype(output_dtype)
thermal_blue = np.array([
[5, 34, 95],
[106, 168, 79],
[255, 255, 0],
[127, 96, 0],
[92, 15, 8]
])
thermal_blue_bgr = rgb_bgr_swap(thermal_blue)
interp = Interpolator(thermal_blue_bgr, 15)
result = interp(np.arange(16))
pprint({i: colour for i, colour in enumerate(result)}, indent=4)
That Interpolator
class could also be used to do the interpolation instead of the existing dictionary approach from the code you shared, but that would require some modification of how your existing code works, instead of just swapping out the colours that get used.