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 * https://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 18 /* 19 * This is not the original file distributed by the Apache Software Foundation 20 * It has been modified by the Hipparchus project 21 */ 22 23 package org.hipparchus.analysis.function; 24 25 import org.hipparchus.analysis.ParametricUnivariateFunction; 26 import org.hipparchus.analysis.differentiation.Derivative; 27 import org.hipparchus.analysis.differentiation.UnivariateDifferentiableFunction; 28 import org.hipparchus.exception.MathIllegalArgumentException; 29 import org.hipparchus.exception.NullArgumentException; 30 import org.hipparchus.util.FastMath; 31 import org.hipparchus.util.MathUtils; 32 import org.hipparchus.util.SinCos; 33 34 /** 35 * <a href="http://en.wikipedia.org/wiki/Harmonic_oscillator"> 36 * simple harmonic oscillator</a> function. 37 * 38 */ 39 public class HarmonicOscillator implements UnivariateDifferentiableFunction { 40 /** Amplitude. */ 41 private final double amplitude; 42 /** Angular frequency. */ 43 private final double omega; 44 /** Phase. */ 45 private final double phase; 46 47 /** 48 * Harmonic oscillator function. 49 * 50 * @param amplitude Amplitude. 51 * @param omega Angular frequency. 52 * @param phase Phase. 53 */ 54 public HarmonicOscillator(double amplitude, 55 double omega, 56 double phase) { 57 this.amplitude = amplitude; 58 this.omega = omega; 59 this.phase = phase; 60 } 61 62 /** {@inheritDoc} */ 63 @Override 64 public double value(double x) { 65 return value(omega * x + phase, amplitude); 66 } 67 68 /** 69 * Parametric function where the input array contains the parameters of 70 * the harmonic oscillator function, ordered as follows: 71 * <ul> 72 * <li>Amplitude</li> 73 * <li>Angular frequency</li> 74 * <li>Phase</li> 75 * </ul> 76 */ 77 public static class Parametric implements ParametricUnivariateFunction { 78 79 /** Empty constructor. 80 * <p> 81 * This constructor is not strictly necessary, but it prevents spurious 82 * javadoc warnings with JDK 18 and later. 83 * </p> 84 * @since 3.0 85 */ 86 public Parametric() { // NOPMD - unnecessary constructor added intentionally to make javadoc happy 87 // nothing to do 88 } 89 90 /** 91 * Computes the value of the harmonic oscillator at {@code x}. 92 * 93 * @param x Value for which the function must be computed. 94 * @param param Values of norm, mean and standard deviation. 95 * @return the value of the function. 96 * @throws NullArgumentException if {@code param} is {@code null}. 97 * @throws MathIllegalArgumentException if the size of {@code param} is 98 * not 3. 99 */ 100 @Override 101 public double value(double x, double ... param) 102 throws MathIllegalArgumentException, NullArgumentException { 103 validateParameters(param); 104 return HarmonicOscillator.value(x * param[1] + param[2], param[0]); 105 } 106 107 /** 108 * Computes the value of the gradient at {@code x}. 109 * The components of the gradient vector are the partial 110 * derivatives of the function with respect to each of the 111 * <em>parameters</em> (amplitude, angular frequency and phase). 112 * 113 * @param x Value at which the gradient must be computed. 114 * @param param Values of amplitude, angular frequency and phase. 115 * @return the gradient vector at {@code x}. 116 * @throws NullArgumentException if {@code param} is {@code null}. 117 * @throws MathIllegalArgumentException if the size of {@code param} is 118 * not 3. 119 */ 120 @Override 121 public double[] gradient(double x, double ... param) 122 throws MathIllegalArgumentException, NullArgumentException { 123 validateParameters(param); 124 125 final double amplitude = param[0]; 126 final double omega = param[1]; 127 final double phase = param[2]; 128 129 final double xTimesOmegaPlusPhase = omega * x + phase; 130 final double a = HarmonicOscillator.value(xTimesOmegaPlusPhase, 1); 131 final double p = -amplitude * FastMath.sin(xTimesOmegaPlusPhase); 132 final double w = p * x; 133 134 return new double[] { a, w, p }; 135 } 136 137 /** 138 * Validates parameters to ensure they are appropriate for the evaluation of 139 * the {@link #value(double,double[])} and {@link #gradient(double,double[])} 140 * methods. 141 * 142 * @param param Values of norm, mean and standard deviation. 143 * @throws NullArgumentException if {@code param} is {@code null}. 144 * @throws MathIllegalArgumentException if the size of {@code param} is 145 * not 3. 146 */ 147 private void validateParameters(double[] param) 148 throws MathIllegalArgumentException, NullArgumentException { 149 MathUtils.checkNotNull(param); 150 MathUtils.checkDimension(param.length, 3); 151 } 152 } 153 154 /** 155 * @param xTimesOmegaPlusPhase {@code omega * x + phase}. 156 * @param amplitude Amplitude. 157 * @return the value of the harmonic oscillator function at {@code x}. 158 */ 159 private static double value(double xTimesOmegaPlusPhase, 160 double amplitude) { 161 return amplitude * FastMath.cos(xTimesOmegaPlusPhase); 162 } 163 164 /** {@inheritDoc} 165 */ 166 @Override 167 public <T extends Derivative<T>> T value(T t) 168 throws MathIllegalArgumentException { 169 final double x = t.getValue(); 170 double[] f = new double[t.getOrder() + 1]; 171 172 final double alpha = omega * x + phase; 173 final SinCos scAlpha = FastMath.sinCos(alpha); 174 f[0] = amplitude * scAlpha.cos(); 175 if (f.length > 1) { 176 f[1] = -amplitude * omega * scAlpha.sin(); 177 final double mo2 = - omega * omega; 178 for (int i = 2; i < f.length; ++i) { 179 f[i] = mo2 * f[i - 2]; 180 } 181 } 182 183 return t.compose(f); 184 185 } 186 187 }