mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
0.2.0 runningAngle
This commit is contained in:
parent
cd358a3b2b
commit
434f8e1adb
@ -6,7 +6,7 @@ jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: arduino/arduino-lint-action@v1
|
||||
with:
|
||||
library-manager: update
|
||||
|
@ -8,7 +8,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 2.6
|
||||
|
@ -10,7 +10,7 @@ jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: json-syntax-check
|
||||
uses: limitusus/json-syntax-check@v1
|
||||
with:
|
||||
|
@ -6,12 +6,27 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
|
||||
## [0.2.0] - 2023-02-22
|
||||
- add **void setMode0()** ==> -180..180
|
||||
- add **void setMode1()** ==> 0..360
|
||||
- add **uint8_t getMode()** return 0 or 1.
|
||||
- add RA_DEFAULT_WEIGHT to **setWeight()**
|
||||
- change return type of **setWeight()** to bool (return false if clipped).
|
||||
- add RA_MIN_WEIGHT + RA_MAX_WEIGHT as constants
|
||||
- add examples
|
||||
- update readme.md
|
||||
- move code from .h to .cpp
|
||||
- update GitHub actions
|
||||
- update license 2023
|
||||
- minor edits
|
||||
|
||||
----
|
||||
|
||||
## [0.1.5] - 2022-11-23
|
||||
- add changelog.md
|
||||
- add RP2040 to build-CI
|
||||
- minor edits
|
||||
|
||||
|
||||
## [0.1.4] - 2022-05-29
|
||||
- add GRADIANS support
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-2022 Rob Tillaart
|
||||
Copyright (c) 2020-2023 Rob Tillaart
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -43,6 +43,16 @@ raised by Edgar Bonet.
|
||||
[an issue]: https://github.com/RobTillaart/AverageAngle/issues/1
|
||||
|
||||
|
||||
#### Related
|
||||
|
||||
- https://github.com/RobTillaart/Angle
|
||||
- https://github.com/RobTillaart/AngleConvertor
|
||||
- https://github.com/RobTillaart/AverageAngle
|
||||
- https://github.com/RobTillaart/RunningAngle
|
||||
- https://github.com/RobTillaart/RunningAverage
|
||||
- https://github.com/RobTillaart/RunningMedian
|
||||
|
||||
|
||||
## Smoothing coefficient
|
||||
|
||||
The output of the filter is efficiently computed as a weighted average
|
||||
@ -50,16 +60,27 @@ of the current input and the previous output:
|
||||
|
||||
output = α × current\_input + (1 − α) × previous\_output
|
||||
|
||||
The smoothing coefficient, α, is the weight of the current input in the
|
||||
average. It is called “weight” within the library, and should be set to
|
||||
a value between 0.001 and 1. The larger the weight, the weaker the
|
||||
smoothing. A weight α = 1 provides no smoothing at all, as the
|
||||
filter's output is a just a copy of its input.
|
||||
The smoothing coefficient, α, is the weight of the current input in the average.
|
||||
It is called “weight” within the library, and should be set to a value between
|
||||
0.001 and 1. The larger the weight (closer to 1), the weaker the smoothing,
|
||||
so noise will affect the average quite a bit.
|
||||
Closer to zero, new values only affect the average minimal.
|
||||
- A weight α = 1 provides no smoothing at all, as the
|
||||
filter's output will be a copy of the input.
|
||||
- A weight α = 0 will return only the first value added.
|
||||
Therefore the weight should be minimal 0.001.
|
||||
|
||||
The filter has a smoothing performance similar to a simple running
|
||||
average over N = 2/α − 1 samples. For example, α = 0.2 is similar to
|
||||
averaging over the last 9 samples.
|
||||
|
||||
It is important to do test runs to find the optimal coefficient (range)
|
||||
for your application. One should be aware that the frequency of adding
|
||||
new angles will affect the time to stabilize the output.
|
||||
|
||||
Note also that it is possible to change the weight run-time.
|
||||
This can be needed e.g. if the accuracy of the input improves over time.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
@ -69,15 +90,16 @@ First, create a filter as an instance of `runningAngle`:
|
||||
runningAngle my_filter(runningAngle::DEGREES);
|
||||
```
|
||||
|
||||
The parameter of the constructor should be either
|
||||
`runningAngle::DEGREES` or `runningAngle::RADIANS`. It is optional and
|
||||
defaults to degrees.
|
||||
The parameter of the constructor should be
|
||||
`runningAngle::DEGREES`, `runningAngle::RADIANS` or `runningAngle::GRADIANS`.
|
||||
This parameter is optional and defaults to degrees.
|
||||
|
||||
Then, set the “weight” smoothing coefficient:
|
||||
|
||||
```c++
|
||||
my_filter.setWeight(0.2);
|
||||
```
|
||||
Note: the weight defaults to 0.80 so no need to set
|
||||
|
||||
Finally, within the main sketch's loop, feed the raw angle readings to
|
||||
the filter's `add()` method:
|
||||
@ -87,16 +109,22 @@ float heading = get_a_compass_reading_somehow();
|
||||
float smoothed_heading = my_filter.add(heading);
|
||||
```
|
||||
|
||||
The method returns the smoothed reading within ± 180° (i.e. ± π rad).
|
||||
The method returns the smoothed reading within ± 180° (i.e. ± π radians) by default.
|
||||
|
||||
See the “examples” folder for a more complete example.
|
||||
The returned value is easily mapped upon 0..360 by adding 360 degrees ( 2π )
|
||||
to the average if the average < 0.
|
||||
Other mappings including scaling are of course possible.
|
||||
|
||||
Degree character = ALT-0176
|
||||
Note: Degree character ° = ALT-0176 (windows)
|
||||
|
||||
|
||||
## Interface
|
||||
|
||||
### AngleType
|
||||
```cpp
|
||||
#include "runningAngle.h"
|
||||
```
|
||||
|
||||
#### AngleType
|
||||
|
||||
- **enum AngleType { DEGREES, RADIANS, GRADIANS }** used to get type math right.
|
||||
|
||||
@ -106,37 +134,78 @@ A full circle is defined as:
|
||||
- GRADIANS = 400°
|
||||
|
||||
GRADIANS are sometimes called GON.
|
||||
|
||||
There also exists a type milli-radians which is effectively the
|
||||
same as RADIANS \* 1000. It won't be supported.
|
||||
same as RADIANS \* 1000. This won't be supported.
|
||||
mRad and other angle-types can be converted here - https://github.com/RobTillaart/AngleConvertor
|
||||
|
||||
|
||||
### runningAngle
|
||||
#### runningAngle
|
||||
|
||||
- **runningAngle(AngleType type = DEGREES)** constructor, default to DEGREES
|
||||
- **float add(float angle)** adds value using a certain weight,
|
||||
except the first value after a reset is used as initial value.
|
||||
- **runningAngle(AngleType type = DEGREES)** constructor, default to DEGREES.
|
||||
- **float add(float angle)** adds a new value using a defined weight.
|
||||
Except for the first value after a reset, which is used as initial value.
|
||||
The **add()** function returns the new average.
|
||||
- **void reset()** resets the internal average and weight to start clean again.
|
||||
- **void reset()** resets the internal average to 0 and weight to start "clean" again.
|
||||
If needed one should call **setWeight()** again!
|
||||
- **float getAverage()** returns the current average value.
|
||||
- **void setWeight(float weight)** sets the weight of the new added value.
|
||||
Value will be constrained between 0.001 and 1.00
|
||||
- **float getWeight()** returns the current set weight.
|
||||
- **void setWeight(float weight = RA_DEFAULT_WEIGHT)** sets the weight of the new added value.
|
||||
Value will be constrained between 0.001 and 1.0.
|
||||
Default weight = RA_DEFAULT_WEIGHT == 0.80.
|
||||
- **float getWeight()** returns the current / set weight.
|
||||
- **AngleType type()** returns DEGREES, RADIANS or GRADIANS.
|
||||
- **float wrap(float angle)** wraps an angle to <-180..+180> <-PI..PI> <-200..200> depending on the type set.
|
||||
- **float wrap(float angle)** wraps an angle to \[-180..+180> \[-PI..PI>
|
||||
or \[-200..200> depending on the type set.
|
||||
|
||||
|
||||
## Operation
|
||||
#### Mode
|
||||
|
||||
See examples
|
||||
- **void setMode0()** average interval = \[-180..180>
|
||||
- **void setMode1()** average interval = \[0..360>
|
||||
- **uint8_t getMode()** returns current mode = 0 or 1.
|
||||
|
||||
|
||||
## Performance add()
|
||||
|
||||
Being the most important worker function, doing float math.
|
||||
(based on time-add.ino on UNO)
|
||||
|
||||
| version | mode | CPU cycles | us per add | relative |
|
||||
|:---------:|:------:|-------------:|-------------:|-----------:|
|
||||
| 0.1.5 | 0 | 681 | 42.5625 us | 100% |
|
||||
| 0.2.0 | 0 | 681 | 42.5625 us | 100% |
|
||||
| 0.2.0 | 1 | 681 | 42.5625 us | 100% |
|
||||
|
||||
|
||||
## Future
|
||||
|
||||
- get some numbers about the noise in the angles (stats on the delta?)
|
||||
#### Must
|
||||
|
||||
- improve documentation.
|
||||
|
||||
#### Should
|
||||
|
||||
- should **add()** return the average? (yes)
|
||||
- or make a **fastAdd()** that doesn't?
|
||||
|
||||
#### Could
|
||||
|
||||
- add examples.
|
||||
- compass HMC6352 lib or simulator.
|
||||
- AS5600 angle measurement sensor
|
||||
- update unit tests.
|
||||
|
||||
|
||||
#### Wont
|
||||
|
||||
- get statistics about the noise in the angles (stats on the delta?).
|
||||
- not the goal of this lib ==> use statistics library
|
||||
- optimize **wrap()** to be generic => no loop per type.
|
||||
- needs variables for -180 / 180 / 360 (RAM vs PROGMEM)
|
||||
- derived class for degrees only? (max optimization)
|
||||
- runtime change of type
|
||||
- conversion
|
||||
- no, too specific scenario.
|
||||
- conversion needed?
|
||||
- add mixed types. 45° + 3 radians = ??
|
||||
|
||||
|
||||
==> user can do this.
|
||||
|
||||
|
@ -0,0 +1,54 @@
|
||||
//
|
||||
// FILE: runningAngle_0_360.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo mapping average from -180..180 to 0..360
|
||||
|
||||
|
||||
#include "runningAngle.h"
|
||||
|
||||
uint32_t start, stop;
|
||||
|
||||
|
||||
runningAngle heading(runningAngle::DEGREES);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
|
||||
start = millis();
|
||||
for (int32_t a = 0; a < 36000; a++)
|
||||
{
|
||||
heading.reset();
|
||||
float angle = a * 0.01;
|
||||
heading.add(angle);
|
||||
|
||||
float average = heading.getAverage();
|
||||
// map output 0..359.999
|
||||
if (average < 0)
|
||||
{
|
||||
average += 360.0;
|
||||
}
|
||||
|
||||
if (abs(angle - average) > 0.0001)
|
||||
{
|
||||
Serial.print(angle);
|
||||
Serial.print("\t");
|
||||
Serial.print(average);
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
stop = millis();
|
||||
Serial.println();
|
||||
Serial.print("TIME: \t");
|
||||
Serial.println(stop - start);
|
||||
Serial.println("done...");
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,7 @@
|
||||
|
||||
IDE: 1.8.19
|
||||
Board: UNO:
|
||||
version: 0.1.5
|
||||
|
||||
Average angle: 61.56 deg
|
||||
Average time: 681.09 CPU cycles
|
@ -0,0 +1,10 @@
|
||||
|
||||
IDE: 1.8.19
|
||||
Board: UNO:
|
||||
version: 0.2.0
|
||||
|
||||
both mode 0 and mode 1
|
||||
|
||||
Average angle: 61.56 deg
|
||||
Average time: 681.09 CPU cycles
|
||||
|
@ -1,15 +1,15 @@
|
||||
/*
|
||||
* time-add.ino: Measure the average execution time of
|
||||
* runningAngle::add().
|
||||
*
|
||||
* This test sketch feeds pseudo-random angles to runningAngle::add()
|
||||
* in order to measure its average execution time in CPU cycles. The
|
||||
* input angles are within 0..90 deg, which ensures there will be no
|
||||
* wrapping. Wrapping would make the method slightly slower, but it is
|
||||
* expected to be infrequent in typical use cases.
|
||||
*
|
||||
* This test is meant to run on AVR-based Arduinos only.
|
||||
*/
|
||||
time-add.ino: Measure the average execution time of
|
||||
runningAngle::add().
|
||||
|
||||
This test sketch feeds pseudo-random angles to runningAngle::add()
|
||||
in order to measure its average execution time in CPU cycles. The
|
||||
input angles are within 0..90 deg, which ensures there will be no
|
||||
wrapping. Wrapping would make the method slightly slower, but it is
|
||||
expected to be infrequent in typical use cases.
|
||||
|
||||
This test is meant to run on AVR-based Arduinos only.
|
||||
*/
|
||||
|
||||
|
||||
#include <runningAngle.h>
|
||||
@ -57,6 +57,8 @@ runningAngle heading(runningAngle::ANGLE_UNIT);
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
heading.setMode1();
|
||||
|
||||
// Set Timer 1 to count in normal mode at the full CPU frequency.
|
||||
// The timer value, TCNT1, can then be used as a clock with
|
||||
// single-cycle resolution.
|
||||
@ -103,5 +105,4 @@ void setup() {
|
||||
asm("sleep");
|
||||
}
|
||||
|
||||
void loop(){}
|
||||
|
||||
void loop() {}
|
||||
|
@ -17,6 +17,11 @@ getWeight KEYWORD2
|
||||
type KEYWORD2
|
||||
wrap KEYWORD2
|
||||
|
||||
setMode0 KEYWORD2
|
||||
setMode1 KEYWORD2
|
||||
getMode1 KEYWORD2
|
||||
|
||||
|
||||
# Constants (LITERAL1)
|
||||
RUNNING_ANGLE_LIB_VERSION LITERAL1
|
||||
|
||||
@ -24,3 +29,7 @@ DEGREES LITERAL1
|
||||
RADIANS LITERAL1
|
||||
GRADIANS LITERAL1
|
||||
|
||||
RA_DEFAULT_WEIGHT LITERAL1
|
||||
RA_MIN_WEIGHT LITERAL1
|
||||
RA_MAX_WEIGHT LITERAL1
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/runningAngle.git"
|
||||
},
|
||||
"version": "0.1.5",
|
||||
"version": "0.2.0",
|
||||
"license": "MIT",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "*",
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=runningAngle
|
||||
version=0.1.5
|
||||
version=0.2.0
|
||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
sentence=Library to average angles by means of low pass filtering with wrapping.
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// FILE: runningAngle.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.5
|
||||
// VERSION: 0.2.0
|
||||
// PURPOSE: Library to average angles by means of low pass filtering with wrapping.
|
||||
// URL: https://github.com/RobTillaart/runningAngle
|
||||
// RELATED: https://github.com/RobTillaart/AverageAngle
|
||||
@ -20,7 +20,7 @@ runningAngle::runningAngle(const enum AngleType type)
|
||||
void runningAngle::reset()
|
||||
{
|
||||
_average = 0;
|
||||
_weight = 0.80;
|
||||
_weight = RA_DEFAULT_WEIGHT;
|
||||
_reset = true;
|
||||
}
|
||||
|
||||
@ -29,14 +29,56 @@ float runningAngle::add(float angle)
|
||||
{
|
||||
if (_reset)
|
||||
{
|
||||
_average = angle;
|
||||
_average = wrap(angle);
|
||||
_reset = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_average = wrap(_average + _weight * wrap(angle - _average));
|
||||
}
|
||||
return _average;
|
||||
if (_mode == 0) return _average;
|
||||
return getAverage();
|
||||
}
|
||||
|
||||
|
||||
|
||||
float runningAngle::getAverage()
|
||||
{
|
||||
if (_mode == 0) return _average;
|
||||
if (_average >= 0) return _average;
|
||||
if (_type == DEGREES) return _average + 360;
|
||||
if (_type == RADIANS) return _average + TWO_PI;
|
||||
// GRADIANS
|
||||
return _average + 200;
|
||||
}
|
||||
|
||||
|
||||
bool runningAngle::setWeight(float w)
|
||||
{
|
||||
if (w < RA_MIN_WEIGHT)
|
||||
{
|
||||
_weight = RA_MIN_WEIGHT;
|
||||
return false;
|
||||
}
|
||||
if (w > RA_MAX_WEIGHT)
|
||||
{
|
||||
_weight = RA_MAX_WEIGHT;
|
||||
return false;
|
||||
}
|
||||
_weight = w;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
float runningAngle::getWeight()
|
||||
{
|
||||
return _weight;
|
||||
}
|
||||
|
||||
|
||||
enum runningAngle::AngleType runningAngle::type()
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
|
||||
@ -45,21 +87,41 @@ float runningAngle::wrap(float angle)
|
||||
if (_type == DEGREES)
|
||||
{
|
||||
while (angle < -180) angle += 360;
|
||||
while (angle >= 180) angle -= 360;
|
||||
while (angle >= +180) angle -= 360;
|
||||
}
|
||||
else if (_type == RADIANS)
|
||||
{
|
||||
while (angle < -PI) angle += TWO_PI;
|
||||
while (angle >= PI) angle -= TWO_PI;
|
||||
while (angle >= +PI) angle -= TWO_PI;
|
||||
}
|
||||
else // GRADIANS
|
||||
{
|
||||
while (angle < -200) angle += 400;
|
||||
while (angle >= 200) angle -= 400;
|
||||
while (angle >= +200) angle -= 400;
|
||||
}
|
||||
return angle;
|
||||
}
|
||||
|
||||
|
||||
// -180..180
|
||||
void runningAngle::setMode0()
|
||||
{
|
||||
_mode = 0;
|
||||
}
|
||||
|
||||
|
||||
// 0..360
|
||||
void runningAngle::setMode1()
|
||||
{
|
||||
_mode = 1;
|
||||
}
|
||||
|
||||
|
||||
uint8_t runningAngle::getMode()
|
||||
{
|
||||
return _mode;
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
//
|
||||
// FILE: runningAngle.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.5
|
||||
// VERSION: 0.2.0
|
||||
// PURPOSE: Library to average angles by means of low pass filtering with wrapping.
|
||||
// URL: https://github.com/RobTillaart/runningAngle
|
||||
// RELATED: https://github.com/RobTillaart/AverageAngle
|
||||
@ -12,7 +12,12 @@
|
||||
#include "math.h"
|
||||
|
||||
|
||||
#define RUNNING_ANGLE_LIB_VERSION (F("0.1.5"))
|
||||
#define RUNNING_ANGLE_LIB_VERSION (F("0.2.0"))
|
||||
|
||||
|
||||
const float RA_DEFAULT_WEIGHT = 0.80;
|
||||
const float RA_MIN_WEIGHT = 0.001;
|
||||
const float RA_MAX_WEIGHT = 1.0;
|
||||
|
||||
|
||||
class runningAngle
|
||||
@ -20,26 +25,31 @@ class runningAngle
|
||||
public:
|
||||
enum AngleType { DEGREES = 0, RADIANS = 1, GRADIANS = 2 };
|
||||
|
||||
|
||||
runningAngle(const enum AngleType type = DEGREES);
|
||||
|
||||
// first value added will not use the weight to set the initial value.
|
||||
float add(float angle); // returns new average
|
||||
void reset();
|
||||
float getAverage() { return _average; };
|
||||
float getAverage();
|
||||
|
||||
void setWeight(float w) { _weight = constrain(w, 0.001, 1); };
|
||||
float getWeight() { return _weight; };
|
||||
enum AngleType type() { return _type; };
|
||||
bool setWeight(float w = RA_DEFAULT_WEIGHT);
|
||||
float getWeight();
|
||||
enum AngleType type();
|
||||
|
||||
// reformat angle to -180..+180 (degrees) or -PI..PI (radians)
|
||||
float wrap(float angle);
|
||||
|
||||
// select the output
|
||||
void setMode0(); // -180..180
|
||||
void setMode1(); // 0..360
|
||||
uint8_t getMode();
|
||||
|
||||
private:
|
||||
enum AngleType _type;
|
||||
float _average = 0;
|
||||
float _weight;
|
||||
bool _reset;
|
||||
uint16_t _mode = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -45,11 +45,19 @@ unittest_teardown()
|
||||
}
|
||||
|
||||
|
||||
unittest(test_constants)
|
||||
{
|
||||
assertEqualFloat(0.800, RA_DEFAULT_WEIGHT, 0.0001);
|
||||
assertEqualFloat(0.001, RA_MIN_WEIGHT, 0.0001);
|
||||
assertEqualFloat(1.000, RA_MAX_WEIGHT, 0.0001);
|
||||
}
|
||||
|
||||
|
||||
unittest(test_constructor_1)
|
||||
{
|
||||
runningAngle heading(runningAngle::DEGREES);
|
||||
assertEqualFloat(0.80, heading.getWeight(), 0.0001);
|
||||
assertEqualFloat(0, heading.getAverage(), 0.0001);
|
||||
assertEqualFloat(0.00, heading.getAverage(), 0.0001);
|
||||
}
|
||||
|
||||
|
||||
@ -57,7 +65,7 @@ unittest(test_constructor_2)
|
||||
{
|
||||
runningAngle heading(runningAngle::RADIANS);
|
||||
assertEqualFloat(0.80, heading.getWeight(), 0.0001);
|
||||
assertEqualFloat(0, heading.getAverage(), 0.0001);
|
||||
assertEqualFloat(0.00, heading.getAverage(), 0.0001);
|
||||
}
|
||||
|
||||
|
||||
@ -65,7 +73,7 @@ unittest(test_constructor_3)
|
||||
{
|
||||
runningAngle heading(runningAngle::GRADIANS);
|
||||
assertEqualFloat(0.80, heading.getWeight(), 0.0001);
|
||||
assertEqualFloat(0, heading.getAverage(), 0.0001);
|
||||
assertEqualFloat(0.00, heading.getAverage(), 0.0001);
|
||||
}
|
||||
|
||||
|
||||
@ -90,15 +98,18 @@ unittest(test_weight)
|
||||
runningAngle heading(runningAngle::DEGREES);
|
||||
assertEqualFloat(0.80, heading.getWeight(), 0.0001);
|
||||
|
||||
heading.setWeight(0.85);
|
||||
assertTrue(heading.setWeight(0.85));
|
||||
assertEqualFloat(0.85, heading.getWeight(), 0.0001);
|
||||
|
||||
heading.setWeight(2);
|
||||
assertFalse(heading.setWeight(2));
|
||||
assertEqualFloat(1, heading.getWeight(), 0.0001);
|
||||
|
||||
heading.setWeight(-5);
|
||||
assertFalse(heading.setWeight(-5));
|
||||
assertEqualFloat(0.001, heading.getWeight(), 0.0001);
|
||||
|
||||
assertTrue(heading.setWeight()); // use default
|
||||
assertEqualFloat(0.80, heading.getWeight(), 0.0001);
|
||||
|
||||
fprintf(stderr, "\treset()\n");
|
||||
heading.reset();
|
||||
assertEqualFloat(0.80, heading.getWeight(), 0.0001);
|
||||
@ -109,6 +120,8 @@ unittest(test_wrap)
|
||||
{
|
||||
runningAngle heading(runningAngle::DEGREES);
|
||||
|
||||
heading.setMode0();
|
||||
|
||||
assertEqualFloat(0, heading.wrap(0), 0.0001);
|
||||
assertEqualFloat(0, heading.wrap(360), 0.0001);
|
||||
assertEqualFloat(1, heading.wrap(361), 0.0001);
|
||||
@ -125,6 +138,35 @@ unittest(test_wrap)
|
||||
}
|
||||
|
||||
|
||||
unittest(test_mode_0)
|
||||
{
|
||||
runningAngle heading(runningAngle::DEGREES);
|
||||
|
||||
for (int i = 0; i < 360; i+= 20)
|
||||
{
|
||||
heading.reset();
|
||||
heading.setMode0();
|
||||
if (i < 180) assertEqualFloat(i, heading.add(i), 0.0001);
|
||||
else assertEqualFloat(i-360, heading.add(i), 0.0001);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unittest(test_mode_1)
|
||||
{
|
||||
runningAngle heading(runningAngle::DEGREES);
|
||||
|
||||
for (int i = 0; i < 360; i+= 20)
|
||||
{
|
||||
heading.reset();
|
||||
heading.setMode1();
|
||||
assertEqualFloat(i, heading.add(i), 0.0001);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unittest_main()
|
||||
|
||||
// --------
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user