1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.math3.fitting; 18 19 import java.util.Random; 20 21 import org.apache.commons.math3.optim.nonlinear.vector.jacobian.LevenbergMarquardtOptimizer; 22 import org.apache.commons.math3.analysis.function.HarmonicOscillator; 23 import org.apache.commons.math3.exception.NumberIsTooSmallException; 24 import org.apache.commons.math3.exception.MathIllegalStateException; 25 import org.apache.commons.math3.util.FastMath; 26 import org.apache.commons.math3.util.MathUtils; 27 import org.junit.Test; 28 import org.junit.Assert; 29 30 @Deprecated 31 public class HarmonicFitterTest { 32 @Test(expected=NumberIsTooSmallException.class) testPreconditions1()33 public void testPreconditions1() { 34 HarmonicFitter fitter = 35 new HarmonicFitter(new LevenbergMarquardtOptimizer()); 36 37 fitter.fit(); 38 } 39 40 @Test testNoError()41 public void testNoError() { 42 final double a = 0.2; 43 final double w = 3.4; 44 final double p = 4.1; 45 HarmonicOscillator f = new HarmonicOscillator(a, w, p); 46 47 HarmonicFitter fitter = 48 new HarmonicFitter(new LevenbergMarquardtOptimizer()); 49 for (double x = 0.0; x < 1.3; x += 0.01) { 50 fitter.addObservedPoint(1, x, f.value(x)); 51 } 52 53 final double[] fitted = fitter.fit(); 54 Assert.assertEquals(a, fitted[0], 1.0e-13); 55 Assert.assertEquals(w, fitted[1], 1.0e-13); 56 Assert.assertEquals(p, MathUtils.normalizeAngle(fitted[2], p), 1e-13); 57 58 HarmonicOscillator ff = new HarmonicOscillator(fitted[0], fitted[1], fitted[2]); 59 60 for (double x = -1.0; x < 1.0; x += 0.01) { 61 Assert.assertTrue(FastMath.abs(f.value(x) - ff.value(x)) < 1e-13); 62 } 63 } 64 65 @Test 66 public void test1PercentError() { 67 Random randomizer = new Random(64925784252l); 68 final double a = 0.2; 69 final double w = 3.4; 70 final double p = 4.1; 71 HarmonicOscillator f = new HarmonicOscillator(a, w, p); 72 73 HarmonicFitter fitter = 74 new HarmonicFitter(new LevenbergMarquardtOptimizer()); 75 for (double x = 0.0; x < 10.0; x += 0.1) { 76 fitter.addObservedPoint(1, x, 77 f.value(x) + 0.01 * randomizer.nextGaussian()); 78 } 79 80 final double[] fitted = fitter.fit(); 81 Assert.assertEquals(a, fitted[0], 7.6e-4); 82 Assert.assertEquals(w, fitted[1], 2.7e-3); 83 Assert.assertEquals(p, MathUtils.normalizeAngle(fitted[2], p), 1.3e-2); 84 } 85 86 @Test 87 public void testTinyVariationsData() { 88 Random randomizer = new Random(64925784252l); 89 90 HarmonicFitter fitter = 91 new HarmonicFitter(new LevenbergMarquardtOptimizer()); 92 for (double x = 0.0; x < 10.0; x += 0.1) { 93 fitter.addObservedPoint(1, x, 1e-7 * randomizer.nextGaussian()); 94 } 95 96 fitter.fit(); 97 // This test serves to cover the part of the code of "guessAOmega" 98 // when the algorithm using integrals fails. 99 } 100 101 @Test 102 public void testInitialGuess() { 103 Random randomizer = new Random(45314242l); 104 final double a = 0.2; 105 final double w = 3.4; 106 final double p = 4.1; 107 HarmonicOscillator f = new HarmonicOscillator(a, w, p); 108 109 HarmonicFitter fitter = 110 new HarmonicFitter(new LevenbergMarquardtOptimizer()); 111 for (double x = 0.0; x < 10.0; x += 0.1) { 112 fitter.addObservedPoint(1, x, 113 f.value(x) + 0.01 * randomizer.nextGaussian()); 114 } 115 116 final double[] fitted = fitter.fit(new double[] { 0.15, 3.6, 4.5 }); 117 Assert.assertEquals(a, fitted[0], 1.2e-3); 118 Assert.assertEquals(w, fitted[1], 3.3e-3); 119 Assert.assertEquals(p, MathUtils.normalizeAngle(fitted[2], p), 1.7e-2); 120 } 121 122 @Test 123 public void testUnsorted() { 124 Random randomizer = new Random(64925784252l); 125 final double a = 0.2; 126 final double w = 3.4; 127 final double p = 4.1; 128 HarmonicOscillator f = new HarmonicOscillator(a, w, p); 129 130 HarmonicFitter fitter = 131 new HarmonicFitter(new LevenbergMarquardtOptimizer()); 132 133 // build a regularly spaced array of measurements 134 int size = 100; 135 double[] xTab = new double[size]; 136 double[] yTab = new double[size]; 137 for (int i = 0; i < size; ++i) { 138 xTab[i] = 0.1 * i; 139 yTab[i] = f.value(xTab[i]) + 0.01 * randomizer.nextGaussian(); 140 } 141 142 // shake it 143 for (int i = 0; i < size; ++i) { 144 int i1 = randomizer.nextInt(size); 145 int i2 = randomizer.nextInt(size); 146 double xTmp = xTab[i1]; 147 double yTmp = yTab[i1]; 148 xTab[i1] = xTab[i2]; 149 yTab[i1] = yTab[i2]; 150 xTab[i2] = xTmp; 151 yTab[i2] = yTmp; 152 } 153 154 // pass it to the fitter 155 for (int i = 0; i < size; ++i) { 156 fitter.addObservedPoint(1, xTab[i], yTab[i]); 157 } 158 159 final double[] fitted = fitter.fit(); 160 Assert.assertEquals(a, fitted[0], 7.6e-4); 161 Assert.assertEquals(w, fitted[1], 3.5e-3); 162 Assert.assertEquals(p, MathUtils.normalizeAngle(fitted[2], p), 1.5e-2); 163 } 164 165 @Test(expected=MathIllegalStateException.class) 166 public void testMath844() { 167 final double[] y = { 0, 1, 2, 3, 2, 1, 168 0, -1, -2, -3, -2, -1, 169 0, 1, 2, 3, 2, 1, 170 0, -1, -2, -3, -2, -1, 171 0, 1, 2, 3, 2, 1, 0 }; 172 final int len = y.length; 173 final WeightedObservedPoint[] points = new WeightedObservedPoint[len]; 174 for (int i = 0; i < len; i++) { 175 points[i] = new WeightedObservedPoint(1, i, y[i]); 176 } 177 178 // The guesser fails because the function is far from an harmonic 179 // function: It is a triangular periodic function with amplitude 3 180 // and period 12, and all sample points are taken at integer abscissae 181 // so function values all belong to the integer subset {-3, -2, -1, 0, 182 // 1, 2, 3}. 183 new HarmonicFitter.ParameterGuesser(points); 184 } 185 } 186