Smoothing the altitude readings

Greg Wilson
5 min readJan 14, 2018

--

This article, part of the Arduino Radio Control Model Plane Altitude Hold series, describes dealing with jitter in the altitude readings.

Jitter

Even when the altimeter is motionless, successive readings can differ from each other. I’ve observed readings moving by +/- 3 metres. This jitter in the indicated altitude could cause problems for the altitude hold device.

To assess the jitter in my prototype device, I took it for a walk up and down a small slope, then back to the middle of the slope. The raw data is shown in the chart below. The device always returns an integer, explaining the stripes visible in the chart.

Some jitter is expected. If the true altitude was 7.5m, then the device could be expected to return 7m sometimes and 8m sometimes. The actual measurements differed by more than that.

Exponential moving averages

There are lots of ways to average out the measurements. I prefer to use an exponential moving average technique. It is simpler to implement than weighted or simple moving averages.

The general idea is that the new estimated measurement is calculated by taking a large proportion of the old estimate, and adding a complementary proportion of the latest measurement.

For example, we might calculate the new estimate as (99% x 100m) + (1% x 105m) yielding 100.05m (assuming the old estimate was 100m, the new measurement was 105m and a smoothing factor of 1%).

Effect of different smoothing factors

Smaller smoothing factors (such as the 1% used in the example) lead to smoother estimates, but they are delayed compared to the movements in the measurements.

The chart below shows the use of various smoothing factors(10%, 5% and 2.5%). The fast smoothing (orange colour) is jerkier but more responsive. The slow smoothing (yellow colour) is smoother but slower than the other lines.

Program

The program I used to gather the data is shown below. It is based on the programs used already in this series.

The float variables fAltSmoothF, fAltSmoothM and fAltSmoothS represent the altitude estimates using fast, medium and slow smoothing factors respectively.

/* Demonstrates one way to read altitude data from an an I2C 
* device, specifically using:
* - Arduino Nano
* - Wire library
* - Eagletree Altimeter Microsensor v3
*
* The raw data is smoothed with an exponential moving
* average to reduce the effect of any spurious readings.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY
* OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
// We'll use the Wire library for I2C operations
#include <Wire.h>
// This value is from the online documentation for the
// altimeter device
byte byteAltimeterAddr = 0xE8;
// A smaller value makes the smoothing more
float fSmoothing = 0.05;
// Altitudes
float fAltSmoothF, fAltSmoothM, fAltSmoothS;
// This item toggles debugging behaviour on or off.
// Comment the item out to disable debugging messages.
#define debug
// Set up debugging behaviours
#ifdef debug
#define debug_print(x) Serial.print (x)
#define debug_println(x) Serial.println (x)
#else
#define debug_print(x)
#define debug_println(x)
#endif
/**
* Prepares for altimeter reading using the Wire library.
*/
void setup() {
// Join I2C bus (address optional for master)
Wire.begin();
// The Wire library only needs seven-bit device addresses
byteAltimeterAddr = byteAltimeterAddr >> 1;
// Set initial value
fAltSmoothF = i2c_read_altimeter();
fAltSmoothM = fAltSmoothF;
fAltSmoothS = fAltSmoothF;
#ifdef debug
// Start serial communication so we can see the results
Serial.begin(57600);
#endif
debug_println("Time\tRaw\tFast\tMedium\tSlow");
}
/**
* Reads the altimeter many times, then
* shows some summary data if debug mode is enabled.
*/
void loop() {
int iAltRaw = -1000;

iAltRaw = i2c_read_altimeter();
fAltSmoothF = ema(fAltSmoothF, iAltRaw, fSmoothing*2);
fAltSmoothM = ema(fAltSmoothM, iAltRaw, fSmoothing);
fAltSmoothS = ema(fAltSmoothS, iAltRaw, fSmoothing/2);
debug_print(millis());
debug_print("\t");
debug_print(iAltRaw);
debug_print("\t");
debug_print(fAltSmoothF);
debug_print("\t");
debug_print(fAltSmoothM);
debug_print("\t");
debug_println(fAltSmoothS);
delay(150);
}
/**
* Read the altimeter and return the result.
* The EagleTree Altimeter Microsensor v3 returns
* a value using the measurement units that are set
* on the device itself, and can be feet or metres.
* My device is set to metres.
* The measurement will be between 0 and 3048 metres,
* so an integer return value is suitable.
* A return value of -100 indicates an error.
*/
int i2c_read_altimeter() {
int iAltitude = -100;
byte byteFirst, byteSecond;

// Send the read command to the device
Wire.beginTransmission(byteAltimeterAddr);
Wire.write(byte(0x07));
Wire.endTransmission(false);
// Request a 2-byte response from the device
Wire.requestFrom(byteAltimeterAddr, (byte) 2);
if (Wire.available() >= 2) {
// Calculate and return the iAltitude
byteFirst = Wire.read();
byteSecond = Wire.read();
iAltitude = byteSecond * 256 + byteFirst;
}
return iAltitude;
}
/**
* Calculate an exponential moving average.
*/
float ema(float fOld, int iNew, float fFactor) {
return (1.0 - fFactor) * fOld +
fFactor * (float) iNew;
}

Simulating more situations

I used a spreadsheet to simulate more cases. The cases were based on an aircraft following a sine wave, with an altimeter that reported an altitude with some random error, and exponential smoothing.

Here’s an example of the spreadsheet output.

It shows that, even with an error-prone altimeter, it is possible to generate useful altitude estimates using an exponential moving average technique.

Conclusion

An exponential moving average technique appears to be useful in overcoming the jitteriness of the altimeter measurements.

--

--

Greg Wilson

Hopeless at orienteering, rubbish at flying radio controlled planes, but enjoys both activities anyway.