WalkerConstellation.java

  1. /* Copyright 2002-2024 Luc Maisonobe
  2.  * Licensed to CS GROUP (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS 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.orekit.orbits;

  18. import org.hipparchus.geometry.euclidean.threed.Rotation;
  19. import org.hipparchus.geometry.euclidean.threed.RotationConvention;
  20. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  21. import org.hipparchus.util.MathUtils;
  22. import org.orekit.errors.OrekitException;
  23. import org.orekit.errors.OrekitMessages;
  24. import org.orekit.utils.PVCoordinates;

  25. import java.util.ArrayList;
  26. import java.util.List;

  27. /** Builder for orbits of satellites forming a Walker constellation.
  28.  * @author Luc Maisonobe
  29.  * @since 12.1
  30.  */
  31. public class WalkerConstellation {

  32.     /** Total number of satellites. */
  33.     private final int t;

  34.     /** Number of orbital planes. */
  35.     private final int p;

  36.     /** Phasing parameter. */
  37.     private final int f;

  38.     /** Simple constructor.
  39.      * @param t total number of satellites
  40.      * @param p number of orbital planes
  41.      * @param f phasing parameter
  42.      */
  43.     public WalkerConstellation(final int t, final int p, final int f) {
  44.         this.t = t;
  45.         this.p = p;
  46.         this.f = f;
  47.         if (t % p != 0) {
  48.             throw new OrekitException(OrekitMessages.WALKER_INCONSISTENT_PLANES, p, t);
  49.         }
  50.     }

  51.     /** Get the total number of satellites.
  52.      * @return total number of satellites
  53.      */
  54.     public int getT() {
  55.         return t;
  56.     }

  57.     /** Get the number of orbital planes.
  58.      * @return number of orbital planes
  59.      */
  60.     public int getP() {
  61.         return p;
  62.     }

  63.     /** Get the phasing parameter.
  64.      * @return phasing parameter
  65.      */
  66.     public int getF() {
  67.         return f;
  68.     }

  69.     /** Create the regular slots.
  70.      * <p>
  71.      * This method builds the {@link #getT() T} regular satellite, with
  72.      * integer {@link WalkerConstellationSlot#getSatellite() satellite indices}. If
  73.      * additional in-orbit spare satellites must be created, the {@link
  74.      * #buildSlot(WalkerConstellationSlot, int, double) buildSlot} method must be called
  75.      * explicitly.
  76.      * </p>
  77.      * <p>
  78.      * The various orbits are built from the {@code referenceOrbit} using plane
  79.      * rotations and {@link Orbit#shiftedBy(double) shifts}. This implies that
  80.      * if orbit does not include {@link Orbit#hasDerivatives() derivatives}, a
  81.      * simple Keplerian motion is assumed, which is the intended use case.
  82.      * </p>
  83.      * @param <O> type of the orbits
  84.      * @param referenceOrbit orbit of the reference satellite, in
  85.      * {@link WalkerConstellationSlot#getPlane() plane} 0 and
  86.      * at {@link WalkerConstellationSlot#getSatellite()} satellite index} 0
  87.      * @return built orbits as a list of list, organized by planes
  88.      * @see #buildReferenceSlot(Orbit)
  89.      * @see #buildSlot(WalkerConstellationSlot, int, double)
  90.      */
  91.     public <O extends Orbit> List<List<WalkerConstellationSlot<O>>> buildRegularSlots(final O referenceOrbit) {

  92.         // build the reference slot
  93.         final WalkerConstellationSlot<O> referenceSlot = buildReferenceSlot(referenceOrbit);

  94.         final List<List<WalkerConstellationSlot<O>>> all = new ArrayList<>(p);
  95.         for (int plane = 0; plane < p; ++plane) {

  96.             // prepare list for one plane
  97.             final List<WalkerConstellationSlot<O>> planeSlots = new ArrayList<>(t / p);

  98.             // build all slots belonging to this plane
  99.             for (int satellite = 0; satellite < t / p; ++satellite) {
  100.                 planeSlots.add(plane == 0 && satellite == 0 ?
  101.                                referenceSlot :
  102.                                buildSlot(referenceSlot, plane, satellite));
  103.             }

  104.             // finished plane
  105.             all.add(planeSlots);

  106.         }

  107.         // return the complete constellation
  108.         return all;

  109.     }

  110.     /** Create the reference slot, which is satellite 0 in plane 0.
  111.      * @param <O> type of the orbits
  112.      * @param referenceOrbit orbit of the reference satellite, in
  113.      * {@link WalkerConstellationSlot#getPlane() plane} 0 and
  114.      * at {@link WalkerConstellationSlot#getSatellite()} satellite index} 0
  115.      * @return build reference slot
  116.      * @see #buildRegularSlots(Orbit)
  117.      * @see #buildSlot(WalkerConstellationSlot, int, double)
  118.      */
  119.     public <O extends Orbit> WalkerConstellationSlot<O>buildReferenceSlot(final O referenceOrbit) {
  120.         return new WalkerConstellationSlot<>(this, 0, 0, referenceOrbit);
  121.     }

  122.     /** Create one offset slot from an already existing slot.
  123.      * @param <O> type of the orbits
  124.      * @param existingSlot existing slot (may be the {@link #buildReferenceSlot(Orbit) reference slot} or not)
  125.      * @param plane plane index of the new slot (may be non-integer for in-orbit spare satellites)
  126.      * @param satellite new slot satellite index in plane (may be non-integer if needed)
  127.      * @return built slot
  128.      * @see #buildRegularSlots(Orbit)
  129.      * @see #buildReferenceSlot(Orbit)
  130.      */
  131.     public <O extends Orbit> WalkerConstellationSlot<O> buildSlot(final WalkerConstellationSlot<O> existingSlot,
  132.                                                                   final int plane, final double satellite) {

  133.         // offsets from existing slot
  134.         final O      refOrbit = existingSlot.getOrbit();
  135.         final int    dp       = plane - existingSlot.getPlane();
  136.         final double ds       = satellite - existingSlot.getSatellite();

  137.         // in plane shift
  138.         final double deltaT = (dp * f + ds * p) * refOrbit.getKeplerianPeriod() / t;
  139.         final Orbit shifted = refOrbit.shiftedBy(deltaT);

  140.         // plane rotation
  141.         final Rotation      r       = new Rotation(Vector3D.PLUS_K,
  142.                                                    MathUtils.TWO_PI * dp / p,
  143.                                                    RotationConvention.VECTOR_OPERATOR);
  144.         final PVCoordinates pv      = shifted.getPVCoordinates();
  145.         final PVCoordinates rotated = new PVCoordinates(r.applyTo(pv.getPosition()),
  146.                                                         r.applyTo(pv.getVelocity()));

  147.         // build orbit
  148.         final CartesianOrbit c = new CartesianOrbit(rotated, refOrbit.getFrame(),
  149.                                                     refOrbit.getDate(), refOrbit.getMu());
  150.         @SuppressWarnings("unchecked")
  151.         final O orbit = (O) refOrbit.getType().convertType(c);

  152.         // build slot
  153.         return new WalkerConstellationSlot<>(this, plane, satellite, orbit);

  154.     }

  155. }