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.  *      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.math4.legacy.analysis.function;

  18. import org.apache.commons.math4.legacy.analysis.ParametricUnivariateFunction;
  19. import org.apache.commons.math4.legacy.analysis.differentiation.DerivativeStructure;
  20. import org.apache.commons.math4.legacy.analysis.differentiation.UnivariateDifferentiableFunction;
  21. import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
  22. import org.apache.commons.math4.legacy.exception.NullArgumentException;
  23. import org.apache.commons.math4.core.jdkmath.JdkMath;

  24. /**
  25.  * <a href="http://en.wikipedia.org/wiki/Harmonic_oscillator">
  26.  *  simple harmonic oscillator</a> function.
  27.  *
  28.  * @since 3.0
  29.  */
  30. public class HarmonicOscillator implements UnivariateDifferentiableFunction {
  31.     /** Amplitude. */
  32.     private final double amplitude;
  33.     /** Angular frequency. */
  34.     private final double omega;
  35.     /** Phase. */
  36.     private final double phase;

  37.     /**
  38.      * Harmonic oscillator function.
  39.      *
  40.      * @param amplitude Amplitude.
  41.      * @param omega Angular frequency.
  42.      * @param phase Phase.
  43.      */
  44.     public HarmonicOscillator(double amplitude,
  45.                               double omega,
  46.                               double phase) {
  47.         this.amplitude = amplitude;
  48.         this.omega = omega;
  49.         this.phase = phase;
  50.     }

  51.     /** {@inheritDoc} */
  52.     @Override
  53.     public double value(double x) {
  54.         return value(omega * x + phase, amplitude);
  55.     }

  56.     /**
  57.      * Parametric function where the input array contains the parameters of
  58.      * the harmonic oscillator function. Ordered as follows:
  59.      * <ul>
  60.      *  <li>Amplitude</li>
  61.      *  <li>Angular frequency</li>
  62.      *  <li>Phase</li>
  63.      * </ul>
  64.      */
  65.     public static class Parametric implements ParametricUnivariateFunction {
  66.         /**
  67.          * Computes the value of the harmonic oscillator at {@code x}.
  68.          *
  69.          * @param x Value for which the function must be computed.
  70.          * @param param Values of norm, mean and standard deviation.
  71.          * @return the value of the function.
  72.          * @throws NullArgumentException if {@code param} is {@code null}.
  73.          * @throws DimensionMismatchException if the size of {@code param} is
  74.          * not 3.
  75.          */
  76.         @Override
  77.         public double value(double x, double ... param)
  78.             throws NullArgumentException,
  79.                    DimensionMismatchException {
  80.             validateParameters(param);
  81.             return HarmonicOscillator.value(x * param[1] + param[2], param[0]);
  82.         }

  83.         /**
  84.          * Computes the value of the gradient at {@code x}.
  85.          * The components of the gradient vector are the partial
  86.          * derivatives of the function with respect to each of the
  87.          * <em>parameters</em> (amplitude, angular frequency and phase).
  88.          *
  89.          * @param x Value at which the gradient must be computed.
  90.          * @param param Values of amplitude, angular frequency and phase.
  91.          * @return the gradient vector at {@code x}.
  92.          * @throws NullArgumentException if {@code param} is {@code null}.
  93.          * @throws DimensionMismatchException if the size of {@code param} is
  94.          * not 3.
  95.          */
  96.         @Override
  97.         public double[] gradient(double x, double ... param)
  98.             throws NullArgumentException,
  99.                    DimensionMismatchException {
  100.             validateParameters(param);

  101.             final double amplitude = param[0];
  102.             final double omega = param[1];
  103.             final double phase = param[2];

  104.             final double xTimesOmegaPlusPhase = omega * x + phase;
  105.             final double a = HarmonicOscillator.value(xTimesOmegaPlusPhase, 1);
  106.             final double p = -amplitude * JdkMath.sin(xTimesOmegaPlusPhase);
  107.             final double w = p * x;

  108.             return new double[] { a, w, p };
  109.         }

  110.         /**
  111.          * Validates parameters to ensure they are appropriate for the evaluation of
  112.          * the {@link #value(double,double[])} and {@link #gradient(double,double[])}
  113.          * methods.
  114.          *
  115.          * @param param Values of norm, mean and standard deviation.
  116.          * @throws NullArgumentException if {@code param} is {@code null}.
  117.          * @throws DimensionMismatchException if the size of {@code param} is
  118.          * not 3.
  119.          */
  120.         private void validateParameters(double[] param)
  121.             throws NullArgumentException,
  122.                    DimensionMismatchException {
  123.             if (param == null) {
  124.                 throw new NullArgumentException();
  125.             }
  126.             if (param.length != 3) {
  127.                 throw new DimensionMismatchException(param.length, 3);
  128.             }
  129.         }
  130.     }

  131.     /**
  132.      * @param xTimesOmegaPlusPhase {@code omega * x + phase}.
  133.      * @param amplitude Amplitude.
  134.      * @return the value of the harmonic oscillator function at {@code x}.
  135.      */
  136.     private static double value(double xTimesOmegaPlusPhase,
  137.                                 double amplitude) {
  138.         return amplitude * JdkMath.cos(xTimesOmegaPlusPhase);
  139.     }

  140.     /** {@inheritDoc}
  141.      * @since 3.1
  142.      */
  143.     @Override
  144.     public DerivativeStructure value(final DerivativeStructure t)
  145.         throws DimensionMismatchException {
  146.         final double x = t.getValue();
  147.         double[] f = new double[t.getOrder() + 1];

  148.         final double alpha = omega * x + phase;
  149.         f[0] = amplitude * JdkMath.cos(alpha);
  150.         if (f.length > 1) {
  151.             f[1] = -amplitude * omega * JdkMath.sin(alpha);
  152.             final double mo2 = - omega * omega;
  153.             for (int i = 2; i < f.length; ++i) {
  154.                 f[i] = mo2 * f[i - 2];
  155.             }
  156.         }

  157.         return t.compose(f);
  158.     }
  159. }