Ok so I am thinking about creating a moving average on my PID control loop, but I can’t think how I would do it in robotc. I understand how averaging like this works but I can’t for the life of me think about how to start coding it.
If anyone could give me some tips that would be great. Please don’t post a full code i would rather work as much of it out for myself as then I’ll understand it properly.
Keep an array of numbers that is to be your average over a number of values. Initialize all of the array values to 0. we’ll call this array your_variable of size max_points which we’ll set to 4. your_variable[max_points]
Have a counter for which array value you want to keep track of who gets the next value. Let’s use i and initialize to 0. Each time you get a new point, replace your_variable* to overwrite the last one in *. When i gets tot he size of the array, set it back to 0, otherwise increase i.
For a simple average, loop through the array items, add them up, and divide by the number of items in the array.
Or choose what kind of average you want. To have the latest have more influence, choose a weighted moving average or exponential moving average.
**
As @Team80_Giraffes have said there are many options of how you can compute the moving average.
My favorite is exponential smoothing which needs only one variable and one extra line of code:
float wSmooth = 0;
while(1)
{
int w = SensorValue[foo];
wSmooth = (3*wSmooth + w)/4;
// do something with wSmooth
delay(20);
}
However, I couldn’t blindly recommend it to you, because I don’t know what you are trying to average and what kind of noise you are trying to filter out or smooth.
For example, if you are reading quad encoder measurements and all the noise nicely falls in the 10 RPM range then exponential smoothing will work very well for you. Not only it is simpler to implement, but it will give more weight to the latest reading over the older data.
If you see large instrumental errors, like every once in a while getting 4563456345 or -345234532 instead of nice values around 100, then median smoothing may be what you need.
But, if your sensors are not that bad, you could make exponential smoothing slightly more robust against the outliers:
float wSmooth = 0;
while(1)
{
int w = SensorValue[foo];
if( abs(w-wSmooth) < 10.0 ) // is measurement inside expected sensor noise level?
wSmooth = (3*wSmooth + w)/4; // yes - gladly accept it
else
wSmooth = (7*wSmooth + w)/8; // no - be cautious and trust older averaged value more
// do something with wSmooth
delay(20);
}
Once again, if you tell us what exactly you are trying to average, or even better, log the data and post the graph, then we could give you more precise advice.
Thanks. I am using quads but the jitter is more like +_10% (about 100 RPM). I have a dual flywheel the two are separate. i am measuring ticks per millisecond which is then converted to RPM (I like working with bigger numbers.) I have made the flywheel as mechanically sound as possible, so i just assumed that was the jitter to expect. But if you’re saying ±10RPM then i am confused.
I am unsure why you have equated w to a sensorvalue (presumably an encoder).
I’m afraid i don’t know how to work with arrays in robotc, so although @Team80_Giraffes sound very helpful i don’t know how to implement them
@Error404:Robot Not Found, you are correct, you get a for catching a couple of sloppy mistakes in my post. Lets just pretend there is a magik “foo” sensor that reports w = 100 RPM when flywheel runs at its nominal speed and has no more than +/- 5 RPM of noise.
Seriously, though, past weekend our launcher speed control performance went from “quite good” to “borderline erratic” when technik jr changed delay interval from 50 to 10 msec while, at the same time, refusing to acknowledge the importance of handling roundoff errors.
Apparently, “not-your-TBH” code, that technik jr is proud of writing, becomes unstable over shorter intervals, when noise in the measurements exceeds some threshold. That was the reason, I run a number of experiments demonstrating the noise in the measurements to any denier.
Calculating velocity over 1 msec interval must be killing you with the roundoff errors. Here is a couple of graphs from the two experiments, where velocity was computed based on the difference between quad encoder readings over 5 msec and 20 msec intervals:
You can clearly see the blocky nature and significantly larger noise level in the experiment with 5 msec interval.
Since you asked not to post the entire code I will just give you partial solution, and let you figure out what else needs to be done:
float w, wSmooth = 0;
int w1, w2=0, w3=0, w4=0, w5=0;
while(1)
{
w1 = SensorValue[foo];
w = (w1-w5)/20.0;
wSmooth = (3*wSmooth + w)/4;
// do something with w and wSmooth
// do something to shift old sensor values around
delay(5);
}
thank you very much this is extremely helpful. my current delay is 20ms
To initialize an array, you would put this at the top of your code (or task, function, whatever scope you want the array declared at):
type varName[sizeArray];
//Example:
float vel[5];
//This declares 5 float variables of the name vel
To access a member of an array (any variable that’s part of one), you put this where a normal variable would go:
vel[0] //first member of array
vel[1]
vel[2]
vel[3]
vel[4] //last member of array
Keep in mind that the last member of the array is one less than the number initialized. Because RobotC does not support initializing arrays to 0, you should put this at the beginning of your code, probably in your init() function:
for(int i = 0; i < arraySize; i++) {
vel* = 0;
}
Also, a for loop (or an if statement within incremented variable) is a useful way to add the values together, like this:
for(int i = 0; i < arraySize; i++) {
velSum += vel*;
if(i > 0) {
vel* = vel*;
}
}
To make this an if statement to allow the program to continue running, initialize i (or any other variable name) outside the loop, and increment it at the end of the if statement. Then, after the if statement, put an else statement to reset i to 0.****