Thresholding data


Thresholding is probably the simplest form of numerical sensor processing.

Basically, a thresholding function applies a very simple function, which is one if the incoming sensor value is greater than a threshold value and zero otherwise. If you like to see things as maths functions, the most basic threshold looks like this:

\[f_{threshold}(x) = \begin{cases} 1 & \text{if } x\geq threshold\\ 0 & \text{otherwise} \end{cases}\]

Here is an example of this most basic of thresholding:

Play with this example above and make some noises at different levels. Can you see any problems with this threshold? Click to see two things that don't work well with this kind of simple threshold.
  • If the value is close to the threshold, the output can jump above and below the threshold, leading the output to jump 0,1,0,1 and back.
  • If we want to use this to detect sensor events, it will only fire if our base ‘quiet’ level is less than the threshold and our ‘loud’ level is greater than the threshold.

De-bounced Thresholds

As we saw above, when the sensor value is close to the threshold value, sensor noise can cause the threshold to oscillate up and down. These oscillations are sometimes referred to as bounce, and ways of fixing them are known as debouncing methods.

When a sensor value is close to the threshold, noise can cause oscillations
Noisy signal causes threshold to oscillate when the sensor value is close to the threshold.

De-bounced thresholds aim to fix this by using two thresholds, one governing up transitions, and the other governing down transitions. If the input value is in between the two thresholds, the output value does not change. In terms of the maths, this looks like:

\[f_{up,down}(x,t) = \begin{cases} 1 & \text{if } x\geq up\\ 0 & \text{if } x\leq down\\ f(t-1) & \text{otherwise} \end{cases}\]

As we can see from the graph below, as long as the typical sensor noise level is lower than the difference between the up and down thresholds, bouncing will no longer occur.

When separate up and down thresholds are used, the threshold output no long oscillates with noisy input.
Debounced thresholds reduce unwanted oscillations in the output.

The code below implements a debounced threshold on the sound sensor. Have a play with this and compare it against the previous example.

Adaptive thresholds

The second problem with thresholds that we described above, that you need to set the correct value for a threshold, can be partially solved by use of adaptive thresholding. Adaptive thresholding sets the threshold based on some characteristic of the sensor data. For example, we might say that our threshold is equal to twice the average of the last 50 readings of the sensor. Or we might use a threshold based on mean and standard deviation, e.g. threshold = mean(last N readings) + standard deviation (last N readings).

The code below uses a deque, which is short for double ended queue, to store the last 50 sensor readings. A deque is like a list, but it has a fixed maximum length, so if you append more than maxlen items to the end of the deque, the item at the other end drops off. We use this to create a history buffer which stores the previous N readings. This is useful for all sorts of things, including for setting adaptive thresholds.