I want to round a number to the nearest 0.005 value.
Eg, the number is 0.243 so this rounds to 0.245 and 0.242 rounds to 0.240
You often see this on GPS systems where the distance only shows every 100m etc.
I’ve tried various approaches and can’t get it to round up exactly. This is driving a PWM output and I am seeing a candle like flickering due to the input signal being a little noisy at low brightness settings. I have an averaging filter but it still manages to leak to the output. I am trying to round this so that small input changes don’t cause the output PWM to toggle between 2 values.
Not all floating numbers may be exactly represented with a finite number of bits.
While rounding, you may reduce the jitter, but not fully suppress it, because at some point a change of 1 LBS bit of the raw data will change the rounded value by 0.005.
You may multiply your data by 200 and cast to integer and perform the process using integer values, but it may be only a partial solution.
If your integer value changes, you may somewhat delay the change of the PWM value until the new value appears stable, avoiding the flickering due to bit noise.
I kind of guessed it was a floating point issue. The trouble is that the PWM driver expects a number between 0 and 1.0 and would have been better if this was 0-100 for percentage.
A pulse width input that toggles only 1 digit causes the output to change, causing the flickering effect. Something like 25 to 26 causes the reading to go from 0.059999998658895493 at 25 and 0.06 at 26. That is more than enough to cause flickering as it toggles between them.
No one is going to like the flickering effect.
I may have to consider monitoring the readings over time and try to limit small changes. It’s only at low brightness that this happens.
You could try to increase your Input before rounding.
if you want to round to 0.05, just add up to 0.005 to you number.
This should work, if the consumer of you number simply cuts off the reamining Digits.
If your PWM (the output) is 12 bits, then convert the input value of your sensor as an integer NNew with the range [0…1023] and copy nNew to Nset
send NSet/1024.0 to the PWM and clear a counter.
While the input is again measured you convert the same way in NNew
If the result equals the formerly sent value (i.e. NNew == NSet) clear the counter and goto 2) because there is no need to set the PWM.
if the counter is zero (first measure after setting the PWM),
copy the new converterd value, NNew to NOld, don’t sent it to the PWM and increment the counter and goto 2).
if the sign of (NNew - NSet) is not the same as (NOld - NSet),
clear the counter, and copy Nset to NOld, it was some noise, goto 2).
Increment the counter
if the counter reaches some count (i.e. some time has elapsed) OR
(abs(NNew - Nset) > some value greather than the expected noise)
copy NNew to NSet GoTo 1) the change appears consistent
do nothing goto 2)
It is not about mathematics, it is a more general issue with any measure in any domain in the real world: there is noise.
In the presenrt case, it may translate to flickering if the input source is “constant” or changes with a slow rate.
The proposed solution avoids high frequency flickering, while, OTOH, allowing a fast response to a real change.
Like @ SouthernStars says this isn’t really a rounding or math issue, it is a system frequency response issue, i.e., balancing your system’s ability to respond to changes quickly without being overly sensitive to noise. Regardless of how you round the values going into or coming out of your averaging filter the output of the averaging filter can sit at some value that will cause the PWM to flicker even with a very small change on the input to the filter. Increasing the time constant of your averaging filter is about the only thing you can do to reduce the flicker but as SouthernStars mentioned your system frequency response will go down. If you don’t need to respond to changes quickly, that might not be a problem. Unless you have some external way to differentiate between real changes in the measured value and noise you’re kind of stuck. Ad hoc methods to look at the output and restrict changes over time are probably the same thing as increasing the filter time constant but with less predictable results. You may be able to improve the situation somewhat with a fancier filter. What kind of averaging filter are you using?