LocalMagneticFieldFrame.java

  1. /* Copyright 2002-2025 CS GROUP
  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.frames;

  18. import org.hipparchus.CalculusFieldElement;
  19. import org.hipparchus.Field;
  20. import org.hipparchus.geometry.euclidean.threed.FieldRotation;
  21. import org.hipparchus.geometry.euclidean.threed.Rotation;
  22. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  23. import org.orekit.bodies.OneAxisEllipsoid;
  24. import org.orekit.models.earth.GeoMagneticField;
  25. import org.orekit.models.earth.ReferenceEllipsoid;
  26. import org.orekit.time.AbsoluteDate;
  27. import org.orekit.time.FieldAbsoluteDate;
  28. import org.orekit.utils.FieldPVCoordinates;
  29. import org.orekit.utils.PVCoordinates;

  30. /**
  31.  * This class handles a magnetic field variation attitude provider.
  32.  * <p>
  33.  * It was designed to be used as a Bdot attitude pointing law which align a specific body axis with Earth magnetic field
  34.  * vector.
  35.  * <p>
  36.  * Attitude control thought the magnetic field is called Bdot as it follows the sinusoidal variation of the Earth magnetic
  37.  * field vector, along the orbit. Magnetorquers are used on board to align the instrument, as so the satellite, with the
  38.  * planet magnetic field, producing a sinusoidal torque along the orbit.
  39.  *
  40.  * @author Alberto Ferrero
  41.  * @author Vincent Cucchietti
  42.  */
  43. public class LocalMagneticFieldFrame implements LOF {

  44.     /** Inertial frame in which position-velocity coordinates will be given when computing transform and rotation. */
  45.     private final Frame inertialFrame;

  46.     /** Vector used to define the local orbital frame. */
  47.     private final LOFBuilderVector lofBuilderVector;

  48.     /** Body shape. */
  49.     private final OneAxisEllipsoid wgs84BodyShape;

  50.     /** Earth's magnetic field. */
  51.     private final GeoMagneticField magneticField;

  52.     /**
  53.      * Constructor with default definition of the local orbital frame:
  54.      * <ul>
  55.      *     <li> x: Magnetic field</li>
  56.      *     <li> y: Completes orthonormal frame</li>
  57.      *     <li> z: Cross product of the magnetic field with the orbital momentum</li>
  58.      * </ul>.
  59.      * <b>BEWARE : Do not use this constructor if it is planned to be used with an equatorial orbit as the magnetic field and
  60.      * orbital momentum vectors will be parallel and cause an error to be thrown</b>
  61.      *
  62.      * @param inertialFrame inertial frame in which position-velocity coordinates will be given when computing transform and
  63.      * rotation
  64.      * @param magneticField Earth magnetic field model
  65.      * @param bodyFrame body frame related to body shape
  66.      */
  67.     public LocalMagneticFieldFrame(final Frame inertialFrame,
  68.                                    final GeoMagneticField magneticField,
  69.                                    final Frame bodyFrame) {
  70.         this(inertialFrame, magneticField, LOFBuilderVector.PLUS_MOMENTUM, bodyFrame);
  71.     }

  72.     /**
  73.      * Constructor with custom definition of the local orbital frame:
  74.      * <ul>
  75.      *     <li> x: Magnetic field</li>
  76.      *     <li> y: Completes orthonormal frame</li>
  77.      *     <li> z: Cross product of the magnetic field with chosen {@link LOFBuilderVector vector}</li>
  78.      * </ul>
  79.      * For near-polar orbits, it is suggested to use the {@link LOFBuilderVector orbital momentum} to define the local
  80.      * orbital frame. However, for near-equatorial orbits, it is advised to use either the
  81.      * {@link LOFBuilderVector position or the velocity}.
  82.      *
  83.      * @param inertialFrame inertial frame in which position-velocity coordinates will be given when computing transform and
  84.      * rotation
  85.      * @param magneticField Earth magnetic field model
  86.      * @param lofBuilderVector vector used to define the local orbital frame
  87.      * @param bodyFrame body frame related to body shape
  88.      */
  89.     public LocalMagneticFieldFrame(final Frame inertialFrame, final GeoMagneticField magneticField,
  90.                                    final LOFBuilderVector lofBuilderVector,
  91.                                    final Frame bodyFrame) {
  92.         this.inertialFrame    = inertialFrame;
  93.         this.magneticField    = magneticField;
  94.         this.lofBuilderVector = lofBuilderVector;
  95.         // Default WGS84 body shape as this is the one used by default in GeoMagneticField
  96.         this.wgs84BodyShape = ReferenceEllipsoid.getWgs84(bodyFrame);
  97.     }

  98.     /**
  99.      * {@inheritDoc} Direction as X axis aligned with magnetic field vector, Y axis aligned with the cross product of the
  100.      * magnetic field vector with chosen {@link LOFBuilderVector vector type}.
  101.      * <p>
  102.      * <b>BEWARE: In this implementation, the method simply fieldify the normal rotation with given field.
  103.      * Hence all derivatives are lost.</b>
  104.      */
  105.     @Override
  106.     public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  107.                                                                                      final FieldAbsoluteDate<T> date,
  108.                                                                                      final FieldPVCoordinates<T> pv) {
  109.         // TODO Implement field equivalent of "calculateField" method in GeoMagneticField
  110.         final Rotation rotation = rotationFromInertial(date.toAbsoluteDate(), pv.toPVCoordinates());
  111.         return new FieldRotation<>(field, rotation);
  112.     }

  113.     /**
  114.      * {@inheritDoc} Direction as X axis aligned with magnetic field vector, Z axis aligned with the cross product of the
  115.      * magnetic field vector with chosen {@link LOFBuilderVector vector type}.
  116.      */
  117.     @Override
  118.     public Rotation rotationFromInertial(final AbsoluteDate date, final PVCoordinates pv) {
  119.         // Express satellite coordinates in body frame
  120.         final StaticTransform inertialToBodyFrame = inertialFrame.getStaticTransformTo(wgs84BodyShape.getBodyFrame(), date);
  121.         final Vector3D        posBody             = inertialToBodyFrame.transformPosition(pv.getPosition());

  122.         // Compute satellite coordinates LLA and magnetic field vector in body frame
  123.         final double   lat            = posBody.getDelta();
  124.         final double   lng            = posBody.getAlpha();
  125.         final double   alt            = posBody.getNorm() - wgs84BodyShape.getEquatorialRadius();
  126.         final Vector3D magnVectorBody = magneticField.calculateField(lat, lng, alt).getFieldVector();

  127.         // Compute magnetic field in inertial frame
  128.         final StaticTransform bodyToInertialFrame = inertialToBodyFrame.getInverse();
  129.         final Vector3D        magnVector          = bodyToInertialFrame.transformVector(magnVectorBody);

  130.         return new Rotation(magnVector, magnVector.crossProduct(lofBuilderVector.getVector(pv)),
  131.                             Vector3D.PLUS_I, Vector3D.PLUS_K);
  132.     }

  133.     /** {@inheritDoc} */
  134.     @Override
  135.     public String getName() {
  136.         return "LOCAL_MAGNETIC_FIELD_FRAME";
  137.     }

  138.     /** Get interlai frame.
  139.      * @return inertial frame
  140.      */
  141.     public Frame getInertialFrame() {
  142.         return inertialFrame;
  143.     }

  144.     /** Get geomagnetid field.
  145.      * @return geo magnetic field
  146.      */
  147.     public GeoMagneticField getMagneticField() {
  148.         return magneticField;
  149.     }

  150.     /**
  151.      * Enum defining how the +j axis of the local orbital frame will be defined.
  152.      * <p>
  153.      * For example, if {@code MINUS_MOMENTUM} is chosen, +j aligned as the cross product of the momentum vector  and the
  154.      * magnetic field vector. The resulting body frame will be +x aligned with magnetic field, +z aligned with negative
  155.      * momentum, +y orthonormal.
  156.      */
  157.     public enum LOFBuilderVector {

  158.         /** Positive position vector. */
  159.         PLUS_POSITION {
  160.             /** {@inheritDoc} */
  161.             @Override
  162.             Vector3D getVector(final PVCoordinates pv) {
  163.                 return pv.getPosition();
  164.             }
  165.         },

  166.         /** Positive velocity vector. */
  167.         PLUS_VELOCITY {
  168.             /** {@inheritDoc} */
  169.             @Override
  170.             Vector3D getVector(final PVCoordinates pv) {
  171.                 return pv.getVelocity();
  172.             }
  173.         },

  174.         /** Positive orbital momentum vector. */
  175.         PLUS_MOMENTUM {
  176.             /** {@inheritDoc} */
  177.             @Override
  178.             Vector3D getVector(final PVCoordinates pv) {
  179.                 return pv.getMomentum();
  180.             }
  181.         },

  182.         /** Negative position vector. */
  183.         MINUS_POSITION {
  184.             /** {@inheritDoc} */
  185.             @Override
  186.             Vector3D getVector(final PVCoordinates pv) {
  187.                 return pv.getPosition().negate();
  188.             }
  189.         },

  190.         /** Negative velocity vector. */
  191.         MINUS_VELOCITY {
  192.             /** {@inheritDoc} */
  193.             @Override
  194.             Vector3D getVector(final PVCoordinates pv) {
  195.                 return pv.getVelocity().negate();
  196.             }
  197.         },

  198.         /** Negative orbital momentum vector. */
  199.         MINUS_MOMENTUM {
  200.             /** {@inheritDoc} */
  201.             @Override
  202.             Vector3D getVector(final PVCoordinates pv) {
  203.                 return pv.getMomentum().negate();
  204.             }
  205.         };

  206.         /**
  207.          * @param pv position-velocity coordinates expressed in the instance inertial frame
  208.          *
  209.          * @return Vector used to define the local orbital frame by computing the cross product of the magnetic field with
  210.          * this
  211.          */
  212.         abstract Vector3D getVector(PVCoordinates pv);
  213.     }

  214. }