You could use slew rate limitation. It means you limit the difference between consecutive samples.
For illustration, let's assume B-bit integers, and two's complement format used for signed values. This means that for the unsigned type, the representable range is 0 to 2B-1, inclusive, and for the signed type, -2B-1 to 2B-1-1, inclusive. A possible slew rate limit could be 2b-1-1, which would mean that the maximum swing in the source from 0 to 2B-1 or vice versa would take three samples to occur in the output (two, if the range is one smaller). High fast peaks are rounded. But as long as successive changes in the input stays within the slew rate limit, the input is reproduced exactly.
In practice, a function that implements a slew rate limit also needs one additional unsigned integer to track the rate-limited value:
Code:
#include <limits.h>
#define SLEWLIMIT (UINT_MAX/2U)
#if SLEWLIMIT > INT_MAX || -SLEWLIMIT < INT_MIN
#error SLEWLIMIT is too large for the signed int type.
#endif
int delta(unsigned int *const valueptr, const unsigned int sample)
{
const unsigned int value = *valueptr;
if (sample > value) {
if (sample - value < SLEWLIMIT) {
*valueptr = sample;
return sample - value;
} else {
*valueptr += SLEWLIMIT;
return (int)SLEWLIMIT;
}
} else
if (sample < value) {
if (value - sample < SLEWLIMIT) {
*valueptr = sample;
return -(int)(value - sample);
} else {
*valueptr -= SLEWLIMIT;
return -(int)SLEWLIMIT;
}
} else
return 0;
}
You supply the above function with a pointer to the slew-rate-limited sample value (an unsigned int) and each new sample, and it tells you the slew-rate limited difference to the previous sample.
If you use Linux or Mac OS X, or you have awk installed, you can see what a slew rate limitation does to an input signal. Create input-file with one integer sample per line, and run
Code:
awk 'BEGIN { R = 5 ; c = 0 ; n = 0 }
NF>0 { p = c ; i = int($1) ; n += 1 ;
if (i - p > R) c =p + R;
else if (p - i > R) c = p - R;
else c = i;
printf "%d %s %d %d\n", n, $1, c, c-p
}' input-file > output-file
and the output-file will have a running index in the first column (sample number), the input sample in the second column, the slew-rate limited sample (same as *valueptr above) in the third column, and the slew-rate limited delta in the fourth column. The value of R is the slew rate limit (5 in the above example).
It is very illustrative to use e.g. Gnuplot to compare the two,
Code:
gnuplot -p -e 'plot "output-file" u 1:2 t "original" w lines lc 1, "output-file" u 1:3 t "limited" w lines lc -1'