FourierTimeSeries.java
/* Copyright 2022-2025 Thales Alenia Space
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.models.earth.ionosphere.nequick;
import org.hipparchus.util.FastMath;
import org.hipparchus.util.SinCos;
import org.orekit.time.DateTimeComponents;
/**
* Fourier time series for the NeQuick model.
* @see NeQuickModel#computeFourierTimeSeries(DateTimeComponents, double)
* @author Luc Maisonobe
* @since 13.0.1
*/
public class FourierTimeSeries {
/** Date. */
private final DateTimeComponents dateTime;
/** Effective ionisation level. */
private final double az;
/** Effective sunspot number (Eq. 19). */
private final double azr;
/** Fourier time series for foF2. */
private final double[] cf2;
/** Fourier time series for M(3000)F2. */
private final double[] cm3;
/**
* Simple constructor.
* @param dateTime current date time components
* @param az effective ionisation level
* @param flattenF2 F2 coefficients used by the F2 layer (flatten array)
* @param flattenFm3 Fm3 coefficients used by the M(3000)F2 layer (flatten array)
*/
FourierTimeSeries(final DateTimeComponents dateTime, final double az,
final double[] flattenF2, final double[] flattenFm3) {
this.dateTime = dateTime;
this.az = az;
// Effective sunspot number (Eq. 19)
this.azr = FastMath.sqrt(167273.0 + (az - 63.7) * 1123.6) - 408.99;
// Hours
final double hours = dateTime.getTime().getSecondsInUTCDay() / 3600.0;
// Time argument (Eq. 49)
final double t = FastMath.toRadians(15 * hours) - FastMath.PI;
// Compute Fourier time series for foF2 and M(3000)F2
final double[] scT = sinCos(t, 6);
this.cf2 = computeCF2(flattenF2, scT);
this.cm3 = computeCm3(flattenFm3, scT);
}
/** Get date time components.
* @return date time components
*/
public DateTimeComponents getDateTime() {
return dateTime;
}
/** Get effective ionisation level.
* @return effective ionisation level
*/
public double getAz() {
return az;
}
/** Get effective sunspot number.
* @return effective sunspot number
*/
public double getAzr() {
return azr;
}
/** Get Fourier time series for foF2.
* <p>
* Beware that for efficiency purposes, this method returns
* a reference to an internal array; this is the reason why
* this method visibility is limited to package level.
* </p>
* @return Fourier time series for foF2 (reference to an internal array)
*/
double[] getCf2Reference() {
return cf2;
}
/** Get Fourier time series for M(3000)F2.
* <p>
* Beware that for efficiency purposes, this method returns
* a reference to an internal array; this is the reason why
* this method visibility is limited to package level.
* </p>
* @return Fourier time series for M(3000)F2 (reference to an internal array)
*/
double[] getCm3Reference() {
return cm3;
}
/** Computes cf2 coefficients.
* @param flattenF2 F2 coefficients used by the F2 layer (flatten array)
* @param scT sines/cosines array of time argument
* @return the cf2 coefficients array
*/
private double[] computeCF2(final double[] flattenF2, final double[] scT) {
// interpolation coefficients for effective spot number
final double azr01 = azr * 0.01;
final double omazr01 = 1 - azr01;
// Eq. 44 and Eq. 50 merged into one loop
final double[] array = new double[76];
int index = 0;
for (int i = 0; i < array.length; i++) {
array[i] =
omazr01 * flattenF2[index] + azr01 * flattenF2[index + 1] +
(omazr01 * flattenF2[index + 2] + azr01 * flattenF2[index + 3]) * scT[0] +
(omazr01 * flattenF2[index + 4] + azr01 * flattenF2[index + 5]) * scT[1] +
(omazr01 * flattenF2[index + 6] + azr01 * flattenF2[index + 7]) * scT[2] +
(omazr01 * flattenF2[index + 8] + azr01 * flattenF2[index + 9]) * scT[3] +
(omazr01 * flattenF2[index + 10] + azr01 * flattenF2[index + 11]) * scT[4] +
(omazr01 * flattenF2[index + 12] + azr01 * flattenF2[index + 13]) * scT[5] +
(omazr01 * flattenF2[index + 14] + azr01 * flattenF2[index + 15]) * scT[6] +
(omazr01 * flattenF2[index + 16] + azr01 * flattenF2[index + 17]) * scT[7] +
(omazr01 * flattenF2[index + 18] + azr01 * flattenF2[index + 19]) * scT[8] +
(omazr01 * flattenF2[index + 20] + azr01 * flattenF2[index + 21]) * scT[9] +
(omazr01 * flattenF2[index + 22] + azr01 * flattenF2[index + 23]) * scT[10] +
(omazr01 * flattenF2[index + 24] + azr01 * flattenF2[index + 25]) * scT[11];
index += 26;
}
return array;
}
/** Computes Cm3 coefficients.
* @param flattenFm3 Fm3 coefficients used by the M(3000)F2 layer (flatten array)
* @param scT sines/cosines array of time argument
* @return the Cm3 coefficients array
*/
private double[] computeCm3(final double[] flattenFm3, final double[] scT) {
// interpolation coefficients for effective spot number
final double azr01 = azr * 0.01;
final double omazr01 = 1 - azr01;
// Eq. 44 and Eq. 51 merged into one loop
final double[] array = new double[49];
int index = 0;
for (int i = 0; i < array.length; i++) {
array[i] =
omazr01 * flattenFm3[index] + azr01 * flattenFm3[index + 1] +
(omazr01 * flattenFm3[index + 2] + azr01 * flattenFm3[index + 3]) * scT[0] +
(omazr01 * flattenFm3[index + 4] + azr01 * flattenFm3[index + 5]) * scT[1] +
(omazr01 * flattenFm3[index + 6] + azr01 * flattenFm3[index + 7]) * scT[2] +
(omazr01 * flattenFm3[index + 8] + azr01 * flattenFm3[index + 9]) * scT[3] +
(omazr01 * flattenFm3[index + 10] + azr01 * flattenFm3[index + 11]) * scT[4] +
(omazr01 * flattenFm3[index + 12] + azr01 * flattenFm3[index + 13]) * scT[5] +
(omazr01 * flattenFm3[index + 14] + azr01 * flattenFm3[index + 15]) * scT[6] +
(omazr01 * flattenFm3[index + 16] + azr01 * flattenFm3[index + 17]) * scT[7];
index += 18;
}
return array;
}
/** Compute sines and cosines.
* @param a argument
* @param n number of terms
* @return sin(a), cos(a), sin(2a), cos(2a) … sin(n a), cos(n a) array
*/
static double[] sinCos(final double a, final int n) {
final SinCos sc0 = FastMath.sinCos(a);
SinCos sci = sc0;
final double[] sc = new double[2 * n];
int isc = 0;
sc[isc++] = sci.sin();
sc[isc++] = sci.cos();
for (int i = 1; i < n; i++) {
sci = SinCos.sum(sc0, sci);
sc[isc++] = sci.sin();
sc[isc++] = sci.cos();
}
return sc;
}
}