Generated reference › API — ICoreBlocks/ICoreMath/Aerospace
kind: generated#api#icoreblocks-icoremath-aerospace

API — ICoreBlocks/ICoreMath/Aerospace

The public contract of 10 header(s) under src/ICoreBlocks/ICoreMath/Aerospace — 10 class/struct definition(s), 44 declaration(s). Each section shows the header's banner and its public (and protected-virtual) surface exactly as the file writes it.

ICoreAerospaceTime.h#

src/ICoreBlocks/ICoreMath/Aerospace/ICoreAerospaceTime.h

ICoreAerospaceTime#

ICoreAerospaceTime.h:56 · class · nested DateParts · 4 declaration(s)

The Aerospace Toolbox date and time conversions of toolbox row T7.15 -- juliandate, mjuliandate, decyear, leapyear and siderealTime.

class ICoreAerospaceTime {
public:
    // One calendar instant. Every field may be non-integer; `month` carries
    // the scaling rule above and the rest are linear.
    struct DateParts {
        double year = 0.0;
        double month = 1.0;
        double day = 1.0;
        double hour = 0.0;
        double minute = 0.0;
        double second = 0.0;
    };

    // `jd = juliandate(...)`.
    static double julianDate(const DateParts& parts);

    // `mjd = mjuliandate(...)` = julianDate - 2400000.5.
    static double modifiedJulianDate(const DateParts& parts);

    // `dyear = decyear(...)` -- the year plus the fraction of it elapsed.
    static double decimalYear(const DateParts& parts);

    // `ly = leapyear(y)`, one year at a time. MATLAB floors first, so 2004.9
    // is a leap year.
    static bool isLeapYear(double year);

    // `thGMST = siderealTime(utcJD[, dUT1, dAT])`, in degrees, folded into
    // 0, 360).
    static double greenwichMeanSiderealTime(double julianDateUtc, double deltaUT1Seconds = 0.0,
                                            double deltaATSeconds = 0.0);

    // Element-wise wrappers over the five above, for the console's matrices.
    // `rows` is a matrix whose ROWS are date vectors of three or six columns;
    // the scalar forms build one row.
    static bool julianDates(const ICoreMatrix& dateRows, bool modified, ICoreMatrix& out,
                            std::string* whyNot = nullptr);
    static bool decimalYears(const ICoreMatrix& dateRows, ICoreMatrix& out,
                             std::string* whyNot = nullptr);
    static bool leapYears(const ICoreMatrix& years, ICoreMatrix& out,
                          std::string* whyNot = nullptr);
    static bool siderealTimes(const ICoreMatrix& julianDatesUtc, const ICoreMatrix& deltaUT1,
                              const ICoreMatrix& deltaAT, ICoreMatrix& out,
                              std::string* whyNot = nullptr);
};
};

ICoreFlightParameters.h#

[src/ICoreBlocks/ICoreMath/Aerospace/ICoreFlightParameters.h

ICoreFlightParameters#

ICoreFlightParameters.h:38 · class · 0 declaration(s)

The Aerospace Toolbox flight relations of toolbox row T7.14 -- airspeed, machnumber, dpressure, alphabeta and correctairspeed.

class ICoreFlightParameters {
public:
    // `as = airspeed(vel)` -- N x 3 in, N x 1 out.
    static bool airspeed(const ICoreMatrix& velocity, ICoreMatrix& out,
                         std::string* whyNot = nullptr);

    // `mach = machnumber(vel, a)`; `a` is a scalar or a vector as long as vel
    // has rows.
    static bool machNumber(const ICoreMatrix& velocity, const ICoreMatrix& speedOfSound,
                           ICoreMatrix& out, std::string* whyNot = nullptr);

    // `q = dpressure(vel, rho)`.
    static bool dynamicPressure(const ICoreMatrix& velocity, const ICoreMatrix& density,
                                ICoreMatrix& out, std::string* whyNot = nullptr);

    // `[alpha, beta] = alphabeta(vel)`, both in RADIANS.
    static bool incidenceAngles(const ICoreMatrix& velocity, ICoreMatrix& alpha,
                                ICoreMatrix& beta, std::string* whyNot = nullptr);

    // `out = correctairspeed(v, a, P0, from, to[, method])`. `from` and `to`
    // are "TAS", "CAS" or "EAS", matched case-insensitively as MATLAB matches
    // them. `method` is "Equation"; anything else (including MATLAB's default,
    // "TableLookup") is refused for the two conversions that need it.
    static bool correctAirspeed(const ICoreMatrix& velocity, const ICoreMatrix& speedOfSound,
                                const ICoreMatrix& staticPressure, const std::string& fromUnit,
                                const std::string& toUnit, const std::string& method,
                                ICoreMatrix& out, std::string* whyNot = nullptr);
};
};

ICoreFrameRotations.h#

src/ICoreBlocks/ICoreMath/Aerospace/ICoreFrameRotations.h

ICoreFrameRotations#

ICoreFrameRotations.h:38 · class · 3 declaration(s)

The frame direction cosine matrices of toolbox row T7.7 -- dcmbody2wind, dcmbody2stability, dcm2alphabeta, dcmecef2ned and dcm2latlon.

class ICoreFrameRotations {
public:
    // `dcmbody2wind(alpha, beta)` -- angles in RADIANS, the 3 x 3 that takes a
    // body-axes vector into wind axes.
    static ICoreMatrix bodyToWind(const double& alpha, const double& beta);

    // `dcmbody2stability(alpha)` -- dcmbody2wind(alpha, 0), which is what
    // MATLAB's own one-line implementation is.
    static ICoreMatrix bodyToStability(const double& alpha);

    // `dcmecef2ned(lat, lon)` -- angles in DEGREES, the 3 x 3 that takes an
    // ECEF vector into the local north-east-down frame.
    static ICoreMatrix ecefToNed(const double& latitudeDegrees,
                                 const double& longitudeDegrees);

    // `[alpha, beta] = dcm2alphabeta(dcm)` -- RADIANS, read straight off two
    // entries: beta is asin(dcm(1,2)) and alpha is asin(-dcm(3,1)).
    static bool alphaBetaOf(const ICoreMatrix& dcm, const bool& validate, const double& tolerance,
                            double& alpha, double& beta, std::string* whyNot = nullptr);

    // `[lat, lon] = dcm2latlon(dcm)` -- DEGREES; the longitude comes from an
    // atan2 and therefore carries its quadrant, where the latitude is an asin
    // and is confined to +/-90.
    static bool latitudeLongitudeOf(const ICoreMatrix& dcm, const bool& validate,
                                    const double& tolerance, double& latitudeDegrees,
                                    double& longitudeDegrees, std::string* whyNot = nullptr);

    // MATLAB's validateDCM: proper (det == 1) and orthogonal (D' * D == I),
    // each to `tolerance`, whose default is eps(2) on both sides. The proper
    // test is made FIRST and a matrix that fails it is not also reported as
    // non-orthogonal, which is validateDCM.m's own ordering.
    static bool isValidDcm(const ICoreMatrix& dcm, const double& tolerance,
                           std::string* whyNot = nullptr);

    // eps(2) -- the default tolerance both readers use.
    static double defaultTolerance();

};
};

ICoreGeodesy.h#

src/ICoreBlocks/ICoreMath/Aerospace/ICoreGeodesy.h

ICoreGeodesy#

ICoreGeodesy.h:48 · class · nested World · 1 declaration(s)

The Aerospace Toolbox geodetic conversions of toolbox row T7.10 -- geoc2geod, geod2geoc, lla2ecef, ecef2lla, lla2flat, flat2lla and geocradius.

class ICoreGeodesy {
public:
    // The reference ellipsoid. MATLAB's `worldparams` accepts the model name
    // "WGS84" or an explicit (flattening, equatorial radius) pair and nothing
    // else, and this is that pair.
    struct World {
        double flattening = 1.0 / 298.257223563;
        double equatorialRadius = 6378137.0;
    };
    static World wgs84();

    // `wraplatitude`: folds a latitude in DEGREES back into [-90, 90] and says
    // whether the longitude beside it must turn by 180. Public because three
    // of the seven names below apply it to their inputs and one applies it to
    // its output, and the fold is the same fold every time.
    // `halfTurn` is 180 for a pair in degrees and pi for a pair in radians;
    // `gravitywgs84` wraps in RADIANS, so the same fold has to work in both
    // units rather than being a degrees-only rule with a conversion around it.
    static void wrapLatitude(double& latitude, double& longitude, bool* wrapped = nullptr,
                             const double& halfTurn = 180.0);

    // `wraplongitude`: folds a longitude in DEGREES into (-180, 180]. The
    // interval is MATLAB's and is not symmetric: -180 stays -180 and 180 stays
    // 180, while 540 becomes -180.
    static void wrapLongitude(double& longitude, bool* wrapped = nullptr,
                              const double& halfTurn = 180.0);

    // `[gd, h] = geoc2geod(gc, r[, f, Re])` -- geocentric latitude and radius
    // to geodetic latitude and height. Degrees in, degrees and metres out.
    static bool geocentricToGeodetic(const ICoreMatrix& geocentricLatitudeDeg,
                                     const ICoreMatrix& radius, const World& world,
                                     ICoreMatrix& geodeticLatitudeDeg, ICoreMatrix& height,
                                     std::string* whyNot = nullptr);

    // `[gc, r] = geod2geoc(gd, h[, f, Re])` -- the other direction.
    static bool geodeticToGeocentric(const ICoreMatrix& geodeticLatitudeDeg,
                                     const ICoreMatrix& height, const World& world,
                                     ICoreMatrix& geocentricLatitudeDeg, ICoreMatrix& radius,
                                     std::string* whyNot = nullptr);

    // `p = lla2ecef(lla[, f, Re])` -- an N x 3 [lat lon alt] to an N x 3
    // [x y z] in metres.
    static bool llaToEcef(const ICoreMatrix& lla, const World& world, ICoreMatrix& ecef,
                          std::string* whyNot = nullptr);

    // `lla = ecef2lla(p[, f, Re])`.
    static bool ecefToLla(const ICoreMatrix& ecef, const World& world, ICoreMatrix& lla,
                          std::string* whyNot = nullptr);

    // `p = lla2flat(lla, ll0, psi0, href[, f, Re])` -- N x 3 to N x 3 flat-Earth
    // [north east down] about the reference point `ll0` (two elements, degrees)
    // rotated by the heading `psi0` (degrees).
    static bool llaToFlat(const ICoreMatrix& lla, double referenceLatitudeDeg,
                          double referenceLongitudeDeg, double headingDeg, double referenceHeight,
                          const World& world, ICoreMatrix& flat, std::string* whyNot = nullptr);

    // `lla = flat2lla(p, ll0, psi0, href[, f, Re])`.
    static bool flatToLla(const ICoreMatrix& flat, double referenceLatitudeDeg,
                          double referenceLongitudeDeg, double headingDeg, double referenceHeight,
                          const World& world, ICoreMatrix& lla, std::string* whyNot = nullptr);

    // `radius = geocradius(lambda[, model])` -- the ellipsoid's radius at a
    // GEOCENTRIC latitude, in metres. This one takes RADIANS internally by
    // going through convang, which is why it is the one name on the row whose
    // sind is a plain sin.
    static bool geocentricRadius(const ICoreMatrix& geocentricLatitudeDeg, const World& world,
                                 ICoreMatrix& radius, std::string* whyNot = nullptr);
};
};

ICoreGravityModels.h#

src/ICoreBlocks/ICoreMath/Aerospace/ICoreGravityModels.h

ICoreGravityModels#

ICoreGravityModels.h:47 · class · nested Wgs84Options · 1 declaration(s)

The Aerospace Toolbox gravity models of toolbox row T7.11 -- gravitywgs84, gravitycentrifugal and gravityzonal.

class ICoreGravityModels {
public:
    enum class Wgs84Method { TaylorSeries, CloseApprox, Exact };

    // [noatmos centrifugal precessing JD], MATLAB's own order and sense.
    struct Wgs84Options {
        bool noAtmosphere = false;   // use GM without the atmosphere's mass
        bool noCentrifugal = false;  // 1 SUPPRESSES the centrifugal term
        bool precessing = false;     // use the IAU rate corrected to `julianDate`
        double julianDate = 0.0;
    };

    // `gravitywgs84(h, lat[, lon, method[, options]])`. `latitudeDeg` and
    // `longitudeDeg` are degrees; `height` metres. `gravity` is the magnitude;
    // `gravityDown` and `gravityNorth` are filled only by Exact and may be
    // null. All three take h's shape.
    static bool wgs84(const ICoreMatrix& height, const ICoreMatrix& latitudeDeg,
                      const ICoreMatrix& longitudeDeg, const Wgs84Method& method,
                      const Wgs84Options& options, ICoreMatrix& gravity,
                      ICoreMatrix* gravityDown, ICoreMatrix* gravityNorth,
                      std::string* whyNot = nullptr);

    // `[gx, gy, gz] = gravitycentrifugal(p[, model])`, p an N x 3 position in
    // the planet-fixed frame. `gz` is all zeros, by construction.
    static bool centrifugal(const ICoreMatrix& position, const std::string& model,
                            ICoreMatrix& gx, ICoreMatrix& gy, ICoreMatrix& gz,
                            std::string* whyNot = nullptr);

    // `[gx, gy, gz] = gravityzonal(p[, model][, degree])`. `degree` 2..4; a
    // degree above the model's own J list is clamped to it, as MATLAB clamps
    // it (with a warning this console does not have a place for).
    static bool zonal(const ICoreMatrix& position, const std::string& model, int degree,
                      ICoreMatrix& gx, ICoreMatrix& gy, ICoreMatrix& gz,
                      std::string* whyNot = nullptr);

    // The nine planet names `gravityzonal` and `gravitycentrifugal` accept,
    // for the refusal message and for `help`.
    static std::string planetList();
};
};

ICoreJplEphemeris.h#

src/ICoreBlocks/ICoreMath/Aerospace/ICoreJplEphemeris.h

ICoreJplEphemeris#

ICoreJplEphemeris.h:27 · class · pImpl · nested Slice · 20 declaration(s)

A JPL planetary and lunar ephemeris (DE405, DE421, DE430, ...), read from JPL's published ASCII form -- the header.4xx file and one or more ascp*.4xx data files -- and evaluated by JPL's own al...

class ICoreJplEphemeris {
public:
    enum Body {
        Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto,
        Moon, Sun, SolarSystemBarycenter, EarthMoonBarycenter
    };

    ICoreJplEphemeris();
    ~ICoreJplEphemeris();
    ICoreJplEphemeris(ICoreJplEphemeris&& other) noexcept;
    ICoreJplEphemeris& operator=(ICoreJplEphemeris&& other) noexcept;
    ICoreJplEphemeris(const ICoreJplEphemeris&) = delete;
    ICoreJplEphemeris& operator=(const ICoreJplEphemeris&) = delete;

    // Reads `headerPath` (GROUP 1010/1030/1040/1041/1050) and every record of
    // every file in `dataPaths`. False, with the reason and nothing loaded, for a
    // file that does not read, a record whose coefficient count or span is not
    // the header's, two records that overlap, or a coefficient table that would
    // read past a record.
    bool loadAscii(const std::string& headerPath, const std::vector<std::string>& dataPaths,
                   std::string* whyNot = nullptr);

    [[nodiscard]] bool isLoaded() const;
    // The DE number (DENUM), e.g. 421.
    [[nodiscard]] int deNumber() const;
    // The span the header announces, and the record length in days.
    [[nodiscard]] double headerStartJd() const;
    [[nodiscard]] double headerEndJd() const;
    [[nodiscard]] double recordDays() const;
    // How many records are loaded, and the span from the first to the last.
    [[nodiscard]] std::size_t recordCount() const;
    [[nodiscard]] double firstLoadedJd() const;
    [[nodiscard]] double lastLoadedJd() const;
    // THE DATA AS THE USER SUPPLIES IT (decision D6): the ephemeris DE `de` read from
    // `folder`, once, and shared. The folder holds JPL's published ASCII files as they
    // download: `header.<de>` and the `asc*.<de>` data files (ascp1900.421,
    // ascp2050.421, ...), all of which are read, in name order. A second call with the
    // same folder and DE answers the same object without reading again; nullptr, with
    // the reason naming the folder and the files it expected, when they are absent or
    // do not load. Sizes, for a user deciding what to download: a record is 1018
    // numbers for DE421 (about 27 kB of ASCII, 8 kB binary); DE421's ascp1900.421,
    // 1900 to 2050, is 46 MB.
    static std::shared_ptr<const ICoreJplEphemeris> shared(const std::filesystem::path& folder, int de,
                                                           std::string* whyNot = nullptr);
    // Forgets every shared ephemeris, so the next shared() reads the files again: a
    // user who replaced them, or a test.
    static void clearShared();

    // A header constant by name (AU in km, EMRAT, CLIGHT, ...); false when absent.
    bool constant(const std::string& name, double& value) const;

    // WHAT AN EXPORT CARRIES (decision D6 (b)): the records a configured run needs and
    // nothing else -- the records [jdFrom, jdTo] (TDB) falls in, and in each only the
    // coefficient columns the asked-for answers read, packed. A DE421 record is 1018
    // numbers; Earth to Sun reads three columns of it (456). `pointer`, `count` and
    // `subintervals` are JPL's IPT rows over the packed record (pointer 1-based, count
    // 0 for a column not carried); `coefficients` holds the records one after another,
    // each `recordSize` numbers starting with its start and end JD.
    struct Slice {
        int de = 0;
        double recordDays = 0.0;
        double emrat = 0.0;
        double au = 0.0;
        int columns = 0;
        int pointer[15] = {};
        int count[15] = {};
        int subintervals[15] = {};
        int recordSize = 0;
        std::vector<double> coefficients;
        [[nodiscard]] std::size_t recordCount() const;
        [[nodiscard]] double firstJd() const;   // the first record's start
        [[nodiscard]] double lastJd() const;    // the last record's end
    };
    // The slice for states of `bodies` (Body values; Earth, Moon and the Earth-Moon
    // barycenter all read the barycenter and the geocentric Moon) and, if asked, the
    // nutations and librations, over [jdFrom, jdTo]. False, with the reason, when a
    // date in the span is in no loaded record (a gap counts), a body is not a Body, or
    // a column asked for is one this ephemeris does not carry.
    bool slice(double jdFrom, double jdTo, const std::vector<int>& bodies, bool nutations, bool librations,
               Slice& out, std::string* whyNot = nullptr) const;
    // An ephemeris that answers from a slice, exactly as the one it was cut from does
    // inside it, and refuses everything else by name: what an exported model computes,
    // run here.
    bool loadSlice(const Slice& slice, std::string* whyNot = nullptr);

    // JPL's PLEPH: the state of `target` relative to `center` (both Body values)
    // at TDB Julian date `jdTdb` -- x, y, z in km and their rates in km/day, in
    // the ephemeris' ICRF frame. Earth and Moon relative to each other are read
    // from the geocentric Moon directly, as JPL does.
    bool state(double jdTdb, int target, int center, double out[6], std::string* whyNot = nullptr) const;
    // The 1980 IAU nutations: dpsi and deps in radians, then their rates in
    // radians per day. False when the ephemeris carries none.
    bool nutations(double jdTdb, double out[4], std::string* whyNot = nullptr) const;
    // The lunar mantle librations: phi, theta and psi in radians, then their
    // rates in radians per day. False when the ephemeris carries none.
    bool librations(double jdTdb, double out[6], std::string* whyNot = nullptr) const;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreQuaternionAlgebra.h#

src/ICoreBlocks/ICoreMath/Aerospace/ICoreQuaternionAlgebra.h

ICoreQuaternionAlgebra#

ICoreQuaternionAlgebra.h:55 · class · 6 declaration(s)

The Aerospace Toolbox's quaternion ARITHMETIC -- toolbox rows T7.1 (the product, the conjugate, the inverse, the two norms, the normaliser and the quotient) and T7.2 (quatrotate).

class ICoreQuaternionAlgebra {
public:
    // ---- T7.1 ---------------------------------------------------------
    //
    // `quatmultiply(q, r)`: the Hamilton product, row by row. The order is
    // MATLAB's and it is not symmetric -- q*r composes r's rotation first.
    static bool multiply(const ICoreMatrix& q, const ICoreMatrix& r, ICoreMatrix& out,
                         std::string* whyNot = nullptr);

    // `quatmultiply(q)` with ONE argument is q * q -- measured:
    // quatmultiply([1 2 3 4]) answers [-28 4 6 8]. A third argument is
    // "Too many input arguments.", so the name takes one or two and no more.
    static bool square(const ICoreMatrix& q, ICoreMatrix& out, std::string* whyNot = nullptr);

    // `quatdivide(q, r)` is inv(r) * q -- a LEFT division, row by row,
    // broadcasting like multiply. ⚠ NOT q * inv(r), which is what the name
    // invites and what the documentation's "divides q by r" does not rule
    // out; the two differ by more than rounding (12.5 over 500 random pairs)
    // and on [1 2 3 4] / [5 6 7 8] they are the same four numbers in a
    // different order. Measured; it agrees with quatmultiply(quatinv(r), q)
    // to the BIT.
    static bool divide(const ICoreMatrix& q, const ICoreMatrix& r, ICoreMatrix& out,
                       std::string* whyNot = nullptr);

    // `quatconj(q)`: [w -x -y -z].
    static bool conjugate(const ICoreMatrix& q, ICoreMatrix& out, std::string* whyNot = nullptr);

    // `quatinv(q)` = conj(q) / quatnorm(q) -- the SQUARED modulus, not the
    // modulus.
    static bool inverse(const ICoreMatrix& q, ICoreMatrix& out, std::string* whyNot = nullptr);

    // `quatnorm(q)`: the N x 1 of w^2 + x^2 + y^2 + z^2.
    static bool normSquared(const ICoreMatrix& q, ICoreMatrix& out, std::string* whyNot = nullptr);

    // `quatmod(q)`: the N x 1 of sqrt(quatnorm(q)).
    static bool modulus(const ICoreMatrix& q, ICoreMatrix& out, std::string* whyNot = nullptr);

    // `quatnormalize(q)` = q / quatmod(q).
    static bool normalize(const ICoreMatrix& q, ICoreMatrix& out, std::string* whyNot = nullptr);

    // ---- T7.2 ---------------------------------------------------------
    //
    // `quatrotate(q, v)` rotates the FRAME, not the vector: it is `q* v q`,
    // the INVERSE of what the console's own `rotatevector(q, v)` does, and
    // both are "rotate v by q" in prose (T0.7's trap). The identity that keeps
    // the two apart is asserted in aero.itest rather than described:
    // quatrotate(q, v) == rotatevector(quatconj(q), v).
    //
    // The transcription is `quat2dcm(q) * v`, which is what the documentation
    // says and what measurement bears out to 7.1e-15 over 3000 random
    // (non-unit) quaternion/vector pairs -- not bit for bit, because the
    // P-coded body sums the products in an order no arrangement of the
    // published formula reproduced. 7.1e-15 on values of order ten is three
    // orders inside the 1e-12 this row's parity cases compare at.
    static bool rotate(const ICoreMatrix& q, const ICoreMatrix& v, ICoreMatrix& out,
                       std::string* whyNot = nullptr);

};
};

ICoreRotationConversions.h#

src/ICoreBlocks/ICoreMath/Aerospace/ICoreRotationConversions.h

ICoreRotationConversions#

ICoreRotationConversions.h:61 · class · 5 declaration(s)

The Aerospace Toolbox's attitude conversions -- toolbox rows T7.3 (the DCM pair), T7.4 (the Euler pair and the twelve rotation orders), T7.5 (the Rodrigues family) and T7.6 (the quaternion log, exp...

class ICoreRotationConversions {
public:
    // The twelve rotation sequences angle2dcm/angle2quat/dcm2angle accept.
    enum class Order { ZYX, ZYZ, ZXY, ZXZ, YXZ, YXY, YZX, YZY, XYZ, XYX, XZY, XZX };

    // dcm2angle's third argument. Default and Robust take the same branch in
    // dcm2angle.m, and they take the same branch here.
    enum class Limit { Default, ZeroR3, Robust };

    // quatinterp's method word. Slerp is the default; Lerp is NOT normalised
    // (MATLAB's is not either) and Nlerp is Lerp normalised.
    enum class Interpolation { Slerp, Lerp, Nlerp };

    // "ZYX", "zyx", "ZyX" -- MATLAB's validatestring is case-insensitive.
    static bool orderOf(const std::string& text, Order& into);

    // The order's own name, for a message.
    static std::string nameOf(const Order& order);

    // A quaternion argument: a 1 x 4 row or a 4 x 1 column, into `into` as
    // [w, x, y, z]. An N x 4 with N > 1 is refused naming Z10.
    static bool readQuaternion(const ICoreMatrix& q, const std::string& who,
                               double into[4], std::string* whyNot = nullptr);

    // ---- T7.3: the DCM pair -------------------------------------------
    //
    // `quat2dcm(q)`: the 3 x 3 that takes a vector in the parent frame into
    // the child -- the TRANSPOSE of the rotation matrix `quat2rotm` answers.
    // A non-unit quaternion is normalised, as MATLAB's is.
    static bool quaternionToDcm(const ICoreMatrix& q, ICoreMatrix& dcm,
                                std::string* whyNot = nullptr);

    // `dcm2quat(dcm[, action[, tol]])`: the trace-branch reader of dcm2quat.m,
    // whose branch choice is what makes the sign deterministic.
    static bool dcmToQuaternion(const ICoreMatrix& dcm, const bool& validate,
                                const double& tolerance, ICoreMatrix& q,
                                std::string* whyNot = nullptr);

    // ---- T7.4: the Euler pair, over the twelve orders ------------------
    static ICoreMatrix anglesToDcm(const double& r1, const double& r2, const double& r3,
                                   const Order& order);

    static bool dcmToAngles(const ICoreMatrix& dcm, const Order& order, const Limit& limit,
                            const bool& validate, const double& tolerance,
                            double& r1, double& r2, double& r3, std::string* whyNot = nullptr);

    // `angle2quat`: the closed forms of angle2quat.m, one per order -- not
    // dcm2quat(angle2dcm(...)), which differs in the last bit or two.
    static ICoreMatrix anglesToQuaternion(const double& r1, const double& r2, const double& r3,
                                          const Order& order);

    // `quat2angle` IS dcm2angle(quat2dcm(quatnormalize(q)), order, "robust")
    // in MATLAB's source, and it is that here.
    static bool quaternionToAngles(const ICoreMatrix& q, const Order& order,
                                   double& r1, double& r2, double& r3,
                                   std::string* whyNot = nullptr);

    // ---- T7.5: the Rodrigues (Gibbs) family ---------------------------
    static ICoreMatrix rodriguesToQuaternion(const ICoreMatrix& rodrigues, std::string* whyNot = nullptr);

    // `quat2rod` is `q(2:4) / cos(acos(w))` -- and the acos/cos round trip is
    // not the identity: at w = 0 it answers 1.633e16 where the algebra says
    // infinity. That is MATLAB's number and it is reproduced, not corrected.
    static bool quaternionToRodrigues(const ICoreMatrix& q, ICoreMatrix& rodrigues,
                                      std::string* whyNot = nullptr);

    static bool rodriguesToDcm(const ICoreMatrix& rodrigues, ICoreMatrix& dcm,
                               std::string* whyNot = nullptr);

    static bool dcmToRodrigues(const ICoreMatrix& dcm, const bool& validate,
                               const double& tolerance, ICoreMatrix& rodrigues,
                               std::string* whyNot = nullptr);

    static bool rodriguesToAngles(const ICoreMatrix& rodrigues, const Order& order,
                                  double& r1, double& r2, double& r3,
                                  std::string* whyNot = nullptr);

    static ICoreMatrix anglesToRodrigues(const double& r1, const double& r2, const double& r3,
                                         const Order& order);

    // ---- T7.6: log, exponential, power, interpolation ------------------
    //
    // `quatlog(q)` on a UNIT quaternion: [0, theta * vhat] with theta the half
    // angle. A non-unit input is normalised (MATLAB warns and normalises; this
    // console has no warning channel, so it normalises silently and the
    // catalog note says so).
    static bool quaternionLog(const ICoreMatrix& q, ICoreMatrix& out, std::string* whyNot = nullptr);

    // `quatexp(q)` on ANY quaternion -- exp(w) * [cos|v|, vhat sin|v|]. This
    // one does NOT normalise: the scalar part is the exponential's scale, and
    // quatexp([1 0.3 0.4 0.5]) answers a quaternion of modulus e.
    static bool quaternionExp(const ICoreMatrix& q, ICoreMatrix& out, std::string* whyNot = nullptr);

    // `quatpower(q, t)` = quatexp(t * quatlog(q)) on the unit quaternion.
    static bool quaternionPower(const ICoreMatrix& q, const double& power, ICoreMatrix& out,
                                std::string* whyNot = nullptr);

    // `quatinterp(p, q, f[, method])`. f is in [0, 1] -- MATLAB errors outside
    // it, and so does this. All three methods take the SHORTEST path: q is
    // negated when dot(p, q) < 0, which is why interpolating toward -q answers
    // the same as interpolating toward q (measured, all three methods).
    static bool quaternionInterp(const ICoreMatrix& p, const ICoreMatrix& q, const double& fraction,
                                 const Interpolation& how, ICoreMatrix& out,
                                 std::string* whyNot = nullptr);

};
};

ICoreStandardAtmosphere.h#

src/ICoreBlocks/ICoreMath/Aerospace/ICoreStandardAtmosphere.h

ICoreStandardAtmosphere#

ICoreStandardAtmosphere.h:65 · class · nested Result, LapseParameters · 2 declaration(s)

The Aerospace Toolbox standard atmospheres of toolbox row T7.8 -- atmosisa, atmoscoesa, atmoslapse and atmospalt.

class ICoreStandardAtmosphere {
public:
    // What every model answers. `nu` and `mu` are computed only by the two
    // models that publish them (`atmosisa` and `atmoslapse`); `atmoscoesa`
    // leaves them at 0 and its caller never asks for them, because MATLAB's
    // `atmoscoesa` has four outputs and no more.
    struct Result {
        ICoreMatrix* temperature;   // T, kelvin
        ICoreMatrix* speedOfSound;  // a, m/s
        ICoreMatrix* pressure;      // P, pascal
        ICoreMatrix* density;       // rho, kg/m^3
        ICoreMatrix* kinematicViscosity;  // nu, m^2/s   (may be null)
        ICoreMatrix* dynamicViscosity;    // mu, N.s/m^2 (may be null)
    };

    // `[T, a, P, rho, nu, mu] = atmosisa(h)`. h in geopotential metres, any
    // shape; every output takes h's shape.
    static bool isa1976(const ICoreMatrix& h, const Result& out, std::string* whyNot = nullptr);

    // `[T, a, P, rho] = atmoscoesa(h)`.
    static bool coesa1976(const ICoreMatrix& h, const Result& out, std::string* whyNot = nullptr);

    // `h = atmospalt(P)` -- the COESA table read backwards, pressure to the
    // altitude that has it. Not the inverse of `atmosisa`: it inverts the
    // DERIVED COESA pressures, so `atmospalt(atmosisa(h)'s P)` is h only to
    // about a millimetre.
    static bool pressureAltitude(const ICoreMatrix& pressure, ICoreMatrix& altitude,
                                 std::string* whyNot = nullptr);

    // `[T, a, P, rho, nu, mu] = atmoslapse(h, g, gamma, R, L, hts, htp, rho0, P0, T0[, H0])`
    // -- the parametric two-layer lapse model, every constant a caller's.
    // MATLAB's name-value viscosity parameters (S, Tref, muref) are not
    // spellable in this grammar; the defaults MATLAB uses when they are
    // omitted (110.4, 273.15, 1.716e-5) are used here, which is the same
    // answer MATLAB gives -- MATLAB only adds a warning saying it did so.
    struct LapseParameters {
        double g = 9.80665;
        double gamma = 1.4;
        double R = 287.0531;
        double L = 0.0065;
        double hts = 11000.0;
        double htp = 20000.0;
        double rho0 = 1.225;
        double P0 = 101325.0;
        double T0 = 288.15;
        double H0 = 0.0;
    };
    static bool lapse(const ICoreMatrix& h, const LapseParameters& parameters,
                      const Result& out, std::string* whyNot = nullptr);
};
};

ICoreUnitConversion.h#

src/ICoreBlocks/ICoreMath/Aerospace/ICoreUnitConversion.h

ICoreUnitConversion#

ICoreUnitConversion.h:59 · class · 2 declaration(s)

The eleven Aerospace Toolbox unit conversions of toolbox row T7.13 -- convvel, convlength, convang, convangvel, convangacc, convmass, convforce, convpres, convtemp, convdensity ...

class ICoreUnitConversion {
public:
    // The eleven tables, named as MATLAB names them in its error text
    // ("Unknown velocity conversion input unit, ...").
    enum class Quantity {
        Velocity, Length, Angle, AngularVelocity, AngularAcceleration,
        Mass, Force, Pressure, Temperature, Density, Acceleration
    };

    // `out = in * slope + offset`, element for element, with `in`'s shape.
    // Refuses an unknown unit on either side with MATLAB's own sentence plus
    // the units this quantity does accept -- MATLAB names the one it did not
    // recognise and stops, which tells a console user what is wrong but not
    // what to write instead.
    static bool convert(const Quantity& quantity, const ICoreMatrix& values,
                        const std::string& fromUnit, const std::string& toUnit,
                        ICoreMatrix& out, std::string* whyNot = nullptr);

    // The console command name for a quantity (`convvel`, `convtemp`, ...),
    // and the quantity for a name -- the pair the evaluator dispatches on, so
    // the eleven names exist in exactly one place.
    static bool quantityOf(const std::string& commandName, Quantity& out);

    // Every unit this quantity accepts, in MATLAB's own table order. Used by
    // the refusal message and by `help`.
    static std::vector<std::string> unitsOf(const Quantity& quantity);

};
};