View Javadoc
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 }