001 // Licensed to the Apache Software Foundation (ASF) under one
002 // or more contributor license agreements. See the NOTICE file
003 // distributed with this work for additional information
004 // regarding copyright ownership. The ASF licenses this file
005 // to you under the Apache License, Version 2.0 (the
006 // "License"); you may not use this file except in compliance
007 // with the License. You may obtain a copy of the License at
008 //
009 // http://www.apache.org/licenses/LICENSE-2.0
010 //
011 // Unless required by applicable law or agreed to in writing,
012 // software distributed under the License is distributed on an
013 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
014 // KIND, either express or implied. See the License for the
015 // specific language governing permissions and limitations
016 // under the License.
017
018 package org.apache.commons.math.optimization.fitting;
019
020 import static org.junit.Assert.assertEquals;
021 import static org.junit.Assert.assertTrue;
022
023 import java.util.Random;
024
025 import org.apache.commons.math.optimization.OptimizationException;
026 import org.apache.commons.math.optimization.general.LevenbergMarquardtOptimizer;
027 import org.apache.commons.math.util.MathUtils;
028 import org.junit.Test;
029
030 public class HarmonicFitterTest {
031
032 @Test
033 public void testNoError() throws OptimizationException {
034 HarmonicFunction f = new HarmonicFunction(0.2, 3.4, 4.1);
035
036 HarmonicFitter fitter =
037 new HarmonicFitter(new LevenbergMarquardtOptimizer());
038 for (double x = 0.0; x < 1.3; x += 0.01) {
039 fitter.addObservedPoint(1.0, x, f.value(x));
040 }
041
042 HarmonicFunction fitted = fitter.fit();
043 assertEquals(f.getAmplitude(), fitted.getAmplitude(), 1.0e-13);
044 assertEquals(f.getPulsation(), fitted.getPulsation(), 1.0e-13);
045 assertEquals(f.getPhase(), MathUtils.normalizeAngle(fitted.getPhase(), f.getPhase()), 1.0e-13);
046
047 for (double x = -1.0; x < 1.0; x += 0.01) {
048 assertTrue(Math.abs(f.value(x) - fitted.value(x)) < 1.0e-13);
049 }
050
051 }
052
053 @Test
054 public void test1PercentError() throws OptimizationException {
055 Random randomizer = new Random(64925784252l);
056 HarmonicFunction f = new HarmonicFunction(0.2, 3.4, 4.1);
057
058 HarmonicFitter fitter =
059 new HarmonicFitter(new LevenbergMarquardtOptimizer());
060 for (double x = 0.0; x < 10.0; x += 0.1) {
061 fitter.addObservedPoint(1.0, x,
062 f.value(x) + 0.01 * randomizer.nextGaussian());
063 }
064
065 HarmonicFunction fitted = fitter.fit();
066 assertEquals(f.getAmplitude(), fitted.getAmplitude(), 7.6e-4);
067 assertEquals(f.getPulsation(), fitted.getPulsation(), 2.7e-3);
068 assertEquals(f.getPhase(), MathUtils.normalizeAngle(fitted.getPhase(), f.getPhase()), 1.3e-2);
069
070 }
071
072 @Test
073 public void testInitialGuess() throws OptimizationException {
074 Random randomizer = new Random(45314242l);
075 HarmonicFunction f = new HarmonicFunction(0.2, 3.4, 4.1);
076
077 HarmonicFitter fitter =
078 new HarmonicFitter(new LevenbergMarquardtOptimizer(), new double[] { 0.15, 3.6, 4.5 });
079 for (double x = 0.0; x < 10.0; x += 0.1) {
080 fitter.addObservedPoint(1.0, x,
081 f.value(x) + 0.01 * randomizer.nextGaussian());
082 }
083
084 HarmonicFunction fitted = fitter.fit();
085 assertEquals(f.getAmplitude(), fitted.getAmplitude(), 1.2e-3);
086 assertEquals(f.getPulsation(), fitted.getPulsation(), 3.3e-3);
087 assertEquals(f.getPhase(), MathUtils.normalizeAngle(fitted.getPhase(), f.getPhase()), 1.7e-2);
088
089 }
090
091 @Test
092 public void testUnsorted() throws OptimizationException {
093 Random randomizer = new Random(64925784252l);
094 HarmonicFunction f = new HarmonicFunction(0.2, 3.4, 4.1);
095
096 HarmonicFitter fitter =
097 new HarmonicFitter(new LevenbergMarquardtOptimizer());
098
099 // build a regularly spaced array of measurements
100 int size = 100;
101 double[] xTab = new double[size];
102 double[] yTab = new double[size];
103 for (int i = 0; i < size; ++i) {
104 xTab[i] = 0.1 * i;
105 yTab[i] = f.value(xTab[i]) + 0.01 * randomizer.nextGaussian();
106 }
107
108 // shake it
109 for (int i = 0; i < size; ++i) {
110 int i1 = randomizer.nextInt(size);
111 int i2 = randomizer.nextInt(size);
112 double xTmp = xTab[i1];
113 double yTmp = yTab[i1];
114 xTab[i1] = xTab[i2];
115 yTab[i1] = yTab[i2];
116 xTab[i2] = xTmp;
117 yTab[i2] = yTmp;
118 }
119
120 // pass it to the fitter
121 for (int i = 0; i < size; ++i) {
122 fitter.addObservedPoint(1.0, xTab[i], yTab[i]);
123 }
124
125 HarmonicFunction fitted = fitter.fit();
126 assertEquals(f.getAmplitude(), fitted.getAmplitude(), 7.6e-4);
127 assertEquals(f.getPulsation(), fitted.getPulsation(), 3.5e-3);
128 assertEquals(f.getPhase(), MathUtils.normalizeAngle(fitted.getPhase(), f.getPhase()), 1.5e-2);
129
130 }
131
132 }