patterncppMinor
stability of an exponential moving average
Viewed 0 times
stabilitymovingaverageexponential
Problem
I used the following code:
We started testing this code on customer facilities, but got the feedback that val
#include
class UltrasonicRecorder
{
public:
UltrasonicRecorder(int referenceValue, Input referenceInput) :
_referenceValue(referenceValue),
_referenceInput(referenceInput)
{}
std::vector GetData();
void RecordData(Input);
int CompensateTemperatur(int);
private:
double _compensation;
int _referenceValue;
Input _referenceInput;
std::vector _data;
};
std::vector UltrasonicRecorder::GetData()
{
std::vector ret;
std::swap(ret, _data);
return ret;
}
void UltrasonicRecorder::RecordData(Input input)
{
int value = (ANALOG_VALUE_RANGE - 1) - GetAnalogValue(input);
value = CompensateTemperature(value);
_data.push_back(value);
}
int UltrasonicRecorder::CompensateTemperature(int value)
{
int measuredValue = GetAnalogValue(_referenceInput);
if(measuredValue > 0)
{
static const double delta = 1.0e-6;
_compensation = (1.0 - delta) * _compensation +
delta * _referenceValue / (double)measuredValue;
}
return static_cast(value * _compensation);
}int GetAnalogValue(Input) returns a 12 bit value from a ultrasonic sensor measuring distance (0-4095, ANALOG_VALUE_RANGE = 4096). double _compensation; is a member of the encapsulating class. _referenceValue is the initial reference value from _referenceInput (normally it has a low fluctuation, with a value somewhere in the middle of the 12 bit range, but it changes with temperature). RecordData() is called every 2 milliseconds (more or less, running on Windows). So a high update rate for the reference value, but I wanted a gradual compensation over time. Therefore I used an exponential moving average, the delta is empirically determined and may need to be changed later. GetData() is called approximately every second to flush _data and use the record for further evaluation.We started testing this code on customer facilities, but got the feedback that val
Solution
How about initializing the compensation factor so that it doesn't have to do the convergence from an undefined state?
Edit: Your EWMA is correct. Your woes of compounding errors are unfounded. As you always "move towards" the measurement value, any compounding errors will be limited. In fact the compound error will at any point in time be less than:
UltrasonicRecorder(int referenceValue, Input referenceInput) :
_referenceValue(referenceValue),
_referenceInput(referenceInput)
{
_compensation = 1.0; // This!
}Edit: Your EWMA is correct. Your woes of compounding errors are unfounded. As you always "move towards" the measurement value, any compounding errors will be limited. In fact the compound error will at any point in time be less than:
(sum{i=0,infty} (1-delta)^i)*ULP(ANALOG_VALUE_RANGE) ~ 2^-(52-12) / delta ~ 10^-6Code Snippets
UltrasonicRecorder(int referenceValue, Input referenceInput) :
_referenceValue(referenceValue),
_referenceInput(referenceInput)
{
_compensation = 1.0; // This!
}(sum{i=0,infty} (1-delta)^i)*ULP(ANALOG_VALUE_RANGE) ~ 2^-(52-12) / delta ~ 10^-6Context
StackExchange Code Review Q#39694, answer score: 3
Revisions (0)
No revisions yet.