HarmonicOscillator.java

  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.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */

  21. package org.hipparchus.analysis.function;

  22. import org.hipparchus.analysis.ParametricUnivariateFunction;
  23. import org.hipparchus.analysis.differentiation.Derivative;
  24. import org.hipparchus.analysis.differentiation.UnivariateDifferentiableFunction;
  25. import org.hipparchus.exception.MathIllegalArgumentException;
  26. import org.hipparchus.exception.NullArgumentException;
  27. import org.hipparchus.util.FastMath;
  28. import org.hipparchus.util.MathUtils;
  29. import org.hipparchus.util.SinCos;

  30. /**
  31.  * <a href="http://en.wikipedia.org/wiki/Harmonic_oscillator">
  32.  *  simple harmonic oscillator</a> function.
  33.  *
  34.  */
  35. public class HarmonicOscillator implements UnivariateDifferentiableFunction {
  36.     /** Amplitude. */
  37.     private final double amplitude;
  38.     /** Angular frequency. */
  39.     private final double omega;
  40.     /** Phase. */
  41.     private final double phase;

  42.     /**
  43.      * Harmonic oscillator function.
  44.      *
  45.      * @param amplitude Amplitude.
  46.      * @param omega Angular frequency.
  47.      * @param phase Phase.
  48.      */
  49.     public HarmonicOscillator(double amplitude,
  50.                               double omega,
  51.                               double phase) {
  52.         this.amplitude = amplitude;
  53.         this.omega = omega;
  54.         this.phase = phase;
  55.     }

  56.     /** {@inheritDoc} */
  57.     @Override
  58.     public double value(double x) {
  59.         return value(omega * x + phase, amplitude);
  60.     }

  61.     /**
  62.      * Parametric function where the input array contains the parameters of
  63.      * the harmonic oscillator function, ordered as follows:
  64.      * <ul>
  65.      *  <li>Amplitude</li>
  66.      *  <li>Angular frequency</li>
  67.      *  <li>Phase</li>
  68.      * </ul>
  69.      */
  70.     public static class Parametric implements ParametricUnivariateFunction {

  71.         /** Empty constructor.
  72.          * <p>
  73.          * This constructor is not strictly necessary, but it prevents spurious
  74.          * javadoc warnings with JDK 18 and later.
  75.          * </p>
  76.          * @since 3.0
  77.          */
  78.         public Parametric() { // NOPMD - unnecessary constructor added intentionally to make javadoc happy
  79.             // nothing to do
  80.         }

  81.         /**
  82.          * Computes the value of the harmonic oscillator at {@code x}.
  83.          *
  84.          * @param x Value for which the function must be computed.
  85.          * @param param Values of norm, mean and standard deviation.
  86.          * @return the value of the function.
  87.          * @throws NullArgumentException if {@code param} is {@code null}.
  88.          * @throws MathIllegalArgumentException if the size of {@code param} is
  89.          * not 3.
  90.          */
  91.         @Override
  92.         public double value(double x, double ... param)
  93.             throws MathIllegalArgumentException, NullArgumentException {
  94.             validateParameters(param);
  95.             return HarmonicOscillator.value(x * param[1] + param[2], param[0]);
  96.         }

  97.         /**
  98.          * Computes the value of the gradient at {@code x}.
  99.          * The components of the gradient vector are the partial
  100.          * derivatives of the function with respect to each of the
  101.          * <em>parameters</em> (amplitude, angular frequency and phase).
  102.          *
  103.          * @param x Value at which the gradient must be computed.
  104.          * @param param Values of amplitude, angular frequency and phase.
  105.          * @return the gradient vector at {@code x}.
  106.          * @throws NullArgumentException if {@code param} is {@code null}.
  107.          * @throws MathIllegalArgumentException if the size of {@code param} is
  108.          * not 3.
  109.          */
  110.         @Override
  111.         public double[] gradient(double x, double ... param)
  112.             throws MathIllegalArgumentException, NullArgumentException {
  113.             validateParameters(param);

  114.             final double amplitude = param[0];
  115.             final double omega = param[1];
  116.             final double phase = param[2];

  117.             final double xTimesOmegaPlusPhase = omega * x + phase;
  118.             final double a = HarmonicOscillator.value(xTimesOmegaPlusPhase, 1);
  119.             final double p = -amplitude * FastMath.sin(xTimesOmegaPlusPhase);
  120.             final double w = p * x;

  121.             return new double[] { a, w, p };
  122.         }

  123.         /**
  124.          * Validates parameters to ensure they are appropriate for the evaluation of
  125.          * the {@link #value(double,double[])} and {@link #gradient(double,double[])}
  126.          * methods.
  127.          *
  128.          * @param param Values of norm, mean and standard deviation.
  129.          * @throws NullArgumentException if {@code param} is {@code null}.
  130.          * @throws MathIllegalArgumentException if the size of {@code param} is
  131.          * not 3.
  132.          */
  133.         private void validateParameters(double[] param)
  134.             throws MathIllegalArgumentException, NullArgumentException {
  135.             MathUtils.checkNotNull(param);
  136.             MathUtils.checkDimension(param.length, 3);
  137.         }
  138.     }

  139.     /**
  140.      * @param xTimesOmegaPlusPhase {@code omega * x + phase}.
  141.      * @param amplitude Amplitude.
  142.      * @return the value of the harmonic oscillator function at {@code x}.
  143.      */
  144.     private static double value(double xTimesOmegaPlusPhase,
  145.                                 double amplitude) {
  146.         return amplitude * FastMath.cos(xTimesOmegaPlusPhase);
  147.     }

  148.     /** {@inheritDoc}
  149.      */
  150.     @Override
  151.     public <T extends Derivative<T>> T value(T t)
  152.         throws MathIllegalArgumentException {
  153.         final double x = t.getValue();
  154.         double[] f = new double[t.getOrder() + 1];

  155.         final double alpha   = omega * x + phase;
  156.         final SinCos scAlpha = FastMath.sinCos(alpha);
  157.         f[0] = amplitude * scAlpha.cos();
  158.         if (f.length > 1) {
  159.             f[1] = -amplitude * omega * scAlpha.sin();
  160.             final double mo2 = - omega * omega;
  161.             for (int i = 2; i < f.length; ++i) {
  162.                 f[i] = mo2 * f[i - 2];
  163.             }
  164.         }

  165.         return t.compose(f);

  166.     }

  167. }