-
-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Trigonometry can be slow #1
Comments
mmm, interesting thoughts, questions pop up
float f = alpha - last
int s = sign(f);
int d = abs(f) / full_turn;
alpha = alpha - s * d * fullturn; this would give a constant time performance. So yes, please make a PR, that allows me to test it more. |
Could also be interesting if the lib could switch between two modi operandi. (just to keep the thought) |
About the effect of the order of the samples on the result. One normally averages angles that are all close to one another like, e.g., compass readings affected by noise. If this is the case, and more specifically, if the set of angles being averaged spans less than 180°, then the result is not affected by the order of the samples. Conversely, if they span more than 180°, the order can affect the outcome. On the other hand, if the angles are scattered all around the compass rose, then the whole concept of “average angle” makes little sense to start with. Example: averaging in the given order:
The first result is just a plain average of the numbers. The second result can be understood by noticing that the sequence unwraps to (180°, 270°, 360°, 450°). In both cases the result is sound if the angles are provided in the order in which they are measured. The assumption is that there are no large jumps (larger than 180°) between two consecutive readings. I will submit a PR, to be considered a “draft”, just for the sake of testing. |
I just was calling it a day then I saw your remarks. (popped the following thought) Think the scenario that angles do not change a lot makes very much sense in Arduino world. to be continued, |
It's a regular, or “batch” average (average of a batch of numbers). A running average could be an interesting option, although I generally prefer the exponentially weighted variant (i.e. 1st order IIR low-pass filter), as it doesn't require as much memory. |
That would be a class on its own, I propose the name "RunningAngle" or "MovingAngle" as I expect users would understand. In the documentation it could be explained in more detail. (OK the link should be sufficient) core code could look like void add(float angle)
{
// unwrap angle first
if (count == 0) EWV = angle;
else EWV += (angle - EWV) * alpha;
}
float getRunningAverage()
{
return EWV;
} |
Or rather EWV = wrap(EWV + wrap(angle - EWV) * alpha); I just found a post where I discuss the different strategies for low-pass filtering an angle. |
Started on a new class implementing runningAngle class with the wrapping ideas above. https://github.com/RobTillaart/runningAngle update |
https://github.com/RobTillaart/runningAngle is alive so I close this issue (keep this class as is for now) Thanks! |
This method of averaging angles is quite elegant, and I have used it myself a few times. It is, however, quite slow on microcontrollers lacking an FPU, especially on the 8-bit AVRs, where
sin()
andcos()
take about 1,600 CPU cycles each.A simpler and faster method is to unwrap the angles. This is the same concept as phase unwrapping. The simple idea is that, as you take a continuous stream of angular readings, you expect consecutive angles to differ by no more than 180°. When this is not the case, you add or subtract 360° to the last reading until you get within ±180° of the previous one.
I tried to implement a version of
AverageAngle
based on this idea:I tested this with a set of angles near 0°/360°, and got a significant speedup:
add()
is about 5 times fastergetAverage()
is about 4 times fasterObviously, the notion of “length” of an angle does not make sense anymore with this approach, although angles could be given “weights”, which are equivalent to lengths at first order.
Would you consider a pull request with this implementation? If so, what to do with the
length
parameter, and with the methodsgetTotalLength()
andgetAverageLength()
?The text was updated successfully, but these errors were encountered: