You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by er...@apache.org on 2020/04/05 12:16:27 UTC
[commons-math] 02/03: MATH-1529: Modified Akima interpolator.
This is an automated email from the ASF dual-hosted git repository.
erans pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-math.git
commit 13a084b3d9cda815f6b5b4d5044851b1227f4e90
Author: Gilles Sadowski <gi...@gmail.com>
AuthorDate: Fri Apr 3 22:11:13 2020 +0200
MATH-1529: Modified Akima interpolator.
---
.../interpolation/AkimaSplineInterpolator.java | 38 ++++++++++++++++++++--
.../interpolation/AkimaSplineInterpolatorTest.java | 35 ++++++++++++++++++++
2 files changed, 70 insertions(+), 3 deletions(-)
diff --git a/src/main/java/org/apache/commons/math4/analysis/interpolation/AkimaSplineInterpolator.java b/src/main/java/org/apache/commons/math4/analysis/interpolation/AkimaSplineInterpolator.java
index 089a7ac..0ab0b13 100644
--- a/src/main/java/org/apache/commons/math4/analysis/interpolation/AkimaSplineInterpolator.java
+++ b/src/main/java/org/apache/commons/math4/analysis/interpolation/AkimaSplineInterpolator.java
@@ -36,7 +36,13 @@ import org.apache.commons.numbers.core.Precision;
* <p>
* This implementation is based on the Akima implementation in the CubicSpline
* class in the Math.NET Numerics library. The method referenced is
- * CubicSpline.InterpolateAkimaSorted
+ * "CubicSpline.InterpolateAkimaSorted".
+ * </p>
+ * <p>
+ * When the {@link #AkimaSplineInterpolator(boolean) argument to the constructor}
+ * is {@code true}, the weights are modified in order to
+ * <a href="https://nl.mathworks.com/help/matlab/ref/makima.html">smooth out
+ * spurious oscillations</a>.
* </p>
* <p>
* The {@link #interpolate(double[], double[]) interpolate} method returns a
@@ -49,6 +55,24 @@ public class AkimaSplineInterpolator
implements UnivariateInterpolator {
/** The minimum number of points that are needed to compute the function. */
private static final int MINIMUM_NUMBER_POINTS = 5;
+ /** Whether to use the "modified Akima" interpolation. */
+ private final boolean useModified;
+
+ /**
+ * Uses the original Akima algorithm.
+ */
+ public AkimaSplineInterpolator() {
+ this(false);
+ }
+
+ /**
+ * @param useModified Whether to use the
+ * <a href="https://nl.mathworks.com/help/matlab/ref/makima.html">modified Akima</a>
+ * interpolation.
+ */
+ public AkimaSplineInterpolator(boolean useModified) {
+ this.useModified = useModified;
+ }
/**
* Computes an interpolating function for the data set.
@@ -95,8 +119,16 @@ public class AkimaSplineInterpolator
differences[i] = (yvals[i + 1] - yvals[i]) / (xvals[i + 1] - xvals[i]);
}
- for (int i = 1; i < weights.length; i++) {
- weights[i] = FastMath.abs(differences[i] - differences[i - 1]);
+ if (useModified) {
+ for (int i = 1; i < weights.length; i++) {
+ final double a = differences[i];
+ final double b = differences[i - 1];
+ weights[i] = FastMath.abs(a - b) + 0.5 * FastMath.abs(a + b);
+ }
+ } else {
+ for (int i = 1; i < weights.length; i++) {
+ weights[i] = FastMath.abs(differences[i] - differences[i - 1]);
+ }
}
// Prepare Hermite interpolation scheme.
diff --git a/src/test/java/org/apache/commons/math4/analysis/interpolation/AkimaSplineInterpolatorTest.java b/src/test/java/org/apache/commons/math4/analysis/interpolation/AkimaSplineInterpolatorTest.java
index d559c4e..28a6e30 100644
--- a/src/test/java/org/apache/commons/math4/analysis/interpolation/AkimaSplineInterpolatorTest.java
+++ b/src/test/java/org/apache/commons/math4/analysis/interpolation/AkimaSplineInterpolatorTest.java
@@ -187,6 +187,41 @@ public class AkimaSplineInterpolatorTest
maxTolerance );
}
+ @Test
+ public void testOriginalVsModified() {
+ final UnivariateFunction f = new UnivariateFunction() {
+ @Override
+ public double value(double x) {
+ return x < -1 ? -1 :
+ x < 1 ? x : 1;
+ }
+ };
+
+ final double[] xS = new double[] {-1, 0, 1, 2, 3 };
+ final double[] yS = new double[xS.length];
+
+ for (int i = 0; i < xS.length; i++) {
+ yS[i] = f.value(xS[i]);
+ }
+
+ final UnivariateFunction iOriginal = new AkimaSplineInterpolator(false).interpolate(xS, yS);
+ final UnivariateFunction iModified = new AkimaSplineInterpolator(true).interpolate(xS, yS);
+
+ final int n = 100;
+ final double delta = 1d / n;
+ for (int i = 1; i < n - 1; i++) {
+ final double x = 2 - i * delta;
+
+ final double value = f.value(x);
+ final double diffOriginal = Math.abs(iOriginal.value(x) - value);
+ final double diffModified = Math.abs(iModified.value(x) - value);
+
+ // In interval (1, 2), the modified algorithm eliminates interpolation artefacts.
+ Assert.assertTrue(diffOriginal > 0);
+ Assert.assertEquals(0d, diffModified, 0d);
+ }
+ }
+
private void testInterpolation( double minimumX, double maximumX, int numberOfElements, int numberOfSamples,
UnivariateFunction f, double tolerance, double maxTolerance )
{