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);
};
};