mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-21 01:01:43 +00:00
[wpimath] Add LinearFilter::BackwardFiniteDifference() (#3528)
This is an alternative to #2344 that handles arbitrary order derivatives of arbitrary precision. The downside is that since it's part of LinearFilter, it can't utilize the units type system in the same way to make Calculate()'s input type different from its output type.
This commit is contained in:
@@ -108,4 +108,113 @@ class LinearFilterTest {
|
||||
(DoubleFunction<Double>) LinearFilterTest::getPulseData,
|
||||
0.0));
|
||||
}
|
||||
|
||||
/** Test backward finite difference. */
|
||||
@Test
|
||||
void backwardFiniteDifferenceTest() {
|
||||
double h = 0.005;
|
||||
|
||||
assertResults(
|
||||
1,
|
||||
2,
|
||||
// f(x) = x²
|
||||
(double x) -> x * x,
|
||||
// df/dx = 2x
|
||||
(double x) -> 2.0 * x,
|
||||
h,
|
||||
-20.0,
|
||||
20.0);
|
||||
|
||||
assertResults(
|
||||
1,
|
||||
2,
|
||||
// f(x) = sin(x)
|
||||
(double x) -> Math.sin(x),
|
||||
// df/dx = cos(x)
|
||||
(double x) -> Math.cos(x),
|
||||
h,
|
||||
-20.0,
|
||||
20.0);
|
||||
|
||||
assertResults(
|
||||
1,
|
||||
2,
|
||||
// f(x) = ln(x)
|
||||
(double x) -> Math.log(x),
|
||||
// df/dx = 1 / x
|
||||
(double x) -> 1.0 / x,
|
||||
h,
|
||||
1.0,
|
||||
20.0);
|
||||
|
||||
assertResults(
|
||||
2,
|
||||
4,
|
||||
// f(x) = x²
|
||||
(double x) -> x * x,
|
||||
// d²f/dx² = 2
|
||||
(double x) -> 2.0,
|
||||
h,
|
||||
-20.0,
|
||||
20.0);
|
||||
|
||||
assertResults(
|
||||
2,
|
||||
4,
|
||||
// f(x) = sin(x)
|
||||
(double x) -> Math.sin(x),
|
||||
// d²f/dx² = -sin(x)
|
||||
(double x) -> -Math.sin(x),
|
||||
h,
|
||||
-20.0,
|
||||
20.0);
|
||||
|
||||
assertResults(
|
||||
2,
|
||||
4,
|
||||
// f(x) = ln(x)
|
||||
(double x) -> Math.log(x),
|
||||
// d²f/dx² = -1 / x²
|
||||
(double x) -> -1.0 / (x * x),
|
||||
h,
|
||||
1.0,
|
||||
20.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for checking results of backward finite difference.
|
||||
*
|
||||
* @param derivative The order of the derivative.
|
||||
* @param samples The number of sample points.
|
||||
* @param f Function of which to take derivative.
|
||||
* @param dfdx Derivative of f.
|
||||
* @param h Sample period in seconds.
|
||||
* @param min Minimum of f's domain to test.
|
||||
* @param max Maximum of f's domain to test.
|
||||
*/
|
||||
void assertResults(
|
||||
int derivative,
|
||||
int samples,
|
||||
DoubleFunction<Double> f,
|
||||
DoubleFunction<Double> dfdx,
|
||||
double h,
|
||||
double min,
|
||||
double max) {
|
||||
var filter = LinearFilter.backwardFiniteDifference(derivative, samples, h);
|
||||
|
||||
for (int i = (int) (min / h); i < (int) (max / h); ++i) {
|
||||
// Let filter initialize
|
||||
if (i < (int) (min / h) + samples) {
|
||||
filter.calculate(f.apply(i * h));
|
||||
continue;
|
||||
}
|
||||
|
||||
// The order of accuracy is O(h^(N - d)) where N is number of stencil
|
||||
// points and d is order of derivative
|
||||
assertEquals(
|
||||
dfdx.apply(i * h),
|
||||
filter.calculate(f.apply(i * h)),
|
||||
10.0 * Math.pow(h, samples - derivative));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user