This commit is contained in:
Timur A. Fatkhullin 2025-08-19 00:23:31 +03:00
parent 3640882874
commit da46ab3e3b
5 changed files with 326 additions and 33 deletions

View File

@ -64,12 +64,14 @@ set(ERFA_INCLUDE_DIR ${CMAKE_BINARY_DIR}/erfa_lib)
message(STATUS ${ERFA_INCLUDE_DIR})
set(MCC_LIBRARY_SRC1 mcc_generics.h mcc_defaults.h mcc_traits.h mcc_utils.h mcc_ccte_iers.h mcc_ccte_iers_default.h mcc_ccte_erfa.h)
set(MCC_LIBRARY_SRC1 mcc_generics.h mcc_defaults.h mcc_traits.h mcc_utils.h mcc_ccte_iers.h mcc_ccte_iers_default.h mcc_ccte_erfa.h mcc_pzone.h mcc_telemetry.h)
set(MCC_LIBRARY1 mcc1)
add_library(${MCC_LIBRARY1} INTERFACE ${MCC_LIBRARY_SRC1})
target_compile_features(${MCC_LIBRARY1} INTERFACE cxx_std_23)
target_include_directories(${MCC_LIBRARY1} INTERFACE ${ERFA_INCLUDE_DIR})
# add_subdirectory(fitpack)
# message(STATUS "FITPACK: " ${FITPACK_INCLUDE_DIR})
option(WITH_TESTS "Build tests" ON)

View File

@ -272,9 +272,9 @@ public:
auto days = std::chrono::floor<std::chrono::days>(tp);
std::chrono::year_month_day ymd{days};
double mjd0;
double mjd0, mjd;
int err = eraCal2jd((int)ymd.year(), (unsigned)ymd.month(), (unsigned)ymd.day(), &mjd0, &julday->mjd);
int err = eraCal2jd((int)ymd.year(), (unsigned)ymd.month(), (unsigned)ymd.day(), &mjd0, &mjd);
if (err != 0) {
ret = err == -1 ? MccCCTE_ERFAErrorCode::ERROR_julday_INVALID_YEAR
@ -282,15 +282,14 @@ public:
: err == -3 ? MccCCTE_ERFAErrorCode::ERROR_julday_INVALID_DAY
: MccCCTE_ERFAErrorCode::ERROR_UNEXPECTED;
} else { // partial part of day
julday->mjd +=
std::chrono::duration_cast<std::chrono::duration<double, std::ratio<86400>>>(tp - days).count();
mjd += std::chrono::duration_cast<std::chrono::duration<double, std::ratio<86400>>>(tp - days).count();
*julday = mjd + mjd0;
}
return ret;
}
error_t timepointToAppSideral(mcc_time_point_c auto tp, mcc_angle_c auto* st, bool islocal = false)
error_t juldayToAppSideral(mcc_julday_c auto jd, mcc_angle_c auto* st, bool islocal = false)
{
error_t ret = MccCCTE_ERFAErrorCode::ERROR_OK;
@ -300,19 +299,12 @@ public:
using real_days_t = std::chrono::duration<double, std::ratio<86400>>;
MccJulianDay julday;
ret = timepointToJulday(tp, &julday);
if (ret != MccCCTE_ERFAErrorCode::ERROR_OK) {
return ret;
}
double ut1 = julday.mjd;
double tt = julday.mjd;
double ut1 = jd.MJD();
double tt = jd.MJD();
std::lock_guard lock{*_stateMutex};
auto dut1 = _currentState._bulletinA.DUT1(julday.mjd);
auto dut1 = _currentState._bulletinA.DUT1(jd.MJD());
if (dut1.has_value()) {
ut1 += std::chrono::duration_cast<real_days_t>(dut1.value()).count();
@ -320,7 +312,7 @@ public:
return MccCCTE_ERFAErrorCode::ERROR_BULLETINA_OUT_OF_RANGE;
}
auto tai_utc = _currentState._leapSeconds[julday.mjd];
auto tai_utc = _currentState._leapSeconds[jd.MJD()];
if (tai_utc.has_value()) {
tt += std::chrono::duration_cast<real_days_t>(tai_utc.value()).count();
} else {
@ -331,7 +323,7 @@ public:
auto tt_tai = _currentState._bulletinA.TT_TAI();
tt += std::chrono::duration_cast<real_days_t>(tt_tai).count();
*st = eraGst06a(julday.MJD0, ut1, julday.MJD0, tt);
*st = eraGst06a(ERFA_DJM0, ut1, ERFA_DJM0, tt);
if (islocal) {
*st += _currentState.lon;
@ -341,6 +333,57 @@ public:
return ret;
}
error_t timepointToAppSideral(mcc_time_point_c auto tp, mcc_angle_c auto* st, bool islocal = false)
{
error_t ret = MccCCTE_ERFAErrorCode::ERROR_OK;
if (st == nullptr) {
return ret;
}
MccJulianDay julday;
ret = timepointToJulday(tp, &julday);
if (ret != MccCCTE_ERFAErrorCode::ERROR_OK) {
return ret;
}
return juldayToAppSideral(julday, st, islocal);
// double ut1 = julday.MJD();
// double tt = julday.MJD();
// std::lock_guard lock{*_stateMutex};
// auto dut1 = _currentState._bulletinA.DUT1(julday.MJD());
// if (dut1.has_value()) {
// ut1 += std::chrono::duration_cast<real_days_t>(dut1.value()).count();
// } else { // out of range
// return MccCCTE_ERFAErrorCode::ERROR_BULLETINA_OUT_OF_RANGE;
// }
// auto tai_utc = _currentState._leapSeconds[julday.MJD()];
// if (tai_utc.has_value()) {
// tt += std::chrono::duration_cast<real_days_t>(tai_utc.value()).count();
// } else {
// return MccCCTE_ERFAErrorCode::ERROR_LEAPSECONDS_OUT_OF_RANGE;
// }
// auto tt_tai = _currentState._bulletinA.TT_TAI();
// tt += std::chrono::duration_cast<real_days_t>(tt_tai).count();
// *st = eraGst06a(ERFA_DJM0, ut1, ERFA_DJM0, tt);
// if (islocal) {
// *st += _currentState.lon;
// }
// return ret;
}
// coordinates transformations
@ -691,13 +734,13 @@ protected:
std::lock_guard lock{*_stateMutex};
auto dut1 = _currentState._bulletinA.DUT1(jd.mjd);
auto dut1 = _currentState._bulletinA.DUT1(jd.MJD());
if (!dut1.has_value()) {
return MccCCTE_ERFAErrorCode::ERROR_BULLETINA_OUT_OF_RANGE;
}
auto pol_pos = _currentState._bulletinA.polarCoords(jd.mjd);
auto pol_pos = _currentState._bulletinA.polarCoords(jd.MJD());
if (!pol_pos.has_value()) {
return MccCCTE_ERFAErrorCode::ERROR_BULLETINA_OUT_OF_RANGE;
}
@ -709,7 +752,7 @@ protected:
double az, zd, ha, ra, dec, eo;
int err = eraAtco13(pt.X, pt.Y, 0.0, 0.0, 0.0, 0.0, jd.MJD0, jd.mjd, dut1->count(), _currentState.lon,
int err = eraAtco13(pt.X, pt.Y, 0.0, 0.0, 0.0, 0.0, jd.MJD0, jd.MJD(), dut1->count(), _currentState.lon,
_currentState.lat, _currentState.elev, pol_pos->x, pol_pos->y, _currentState.meteo.pressure,
_currentState.meteo.temperature, _currentState.meteo.humidity, _currentState.wavelength,
&az, &zd, &ha, &dec, &ra, &eo);
@ -750,13 +793,13 @@ protected:
std::lock_guard lock{*_stateMutex};
auto dut1 = _currentState._bulletinA.DUT1(jd.mjd);
auto dut1 = _currentState._bulletinA.DUT1(jd.MJD());
if (!dut1.has_value()) {
return MccCCTE_ERFAErrorCode::ERROR_BULLETINA_OUT_OF_RANGE;
}
auto pol_pos = _currentState._bulletinA.polarCoords(jd.mjd);
auto pol_pos = _currentState._bulletinA.polarCoords(jd.MJD());
if (!pol_pos.has_value()) {
return MccCCTE_ERFAErrorCode::ERROR_BULLETINA_OUT_OF_RANGE;
}
@ -793,7 +836,7 @@ protected:
return MccCCTE_ERFAErrorCode::ERROR_UNSUPPORTED_COORD_PAIR;
}
int err = eraAtoc13(type.c_str(), from_pt.X, from_pt.Y, jd.MJD0, jd.mjd, dut1->count(), _currentState.lon,
int err = eraAtoc13(type.c_str(), from_pt.X, from_pt.Y, jd.MJD0, jd.MJD(), dut1->count(), _currentState.lon,
_currentState.lat, _currentState.elev, pol_pos->x, pol_pos->y, _currentState.meteo.pressure,
_currentState.meteo.temperature, _currentState.meteo.humidity, _currentState.wavelength,
&to_pt->X, &to_pt->Y);
@ -842,7 +885,8 @@ protected:
return MccCCTE_ERFAErrorCode::ERROR_OK;
}
MccJulianDay jd, tt;
MccJulianDay jd;
double tt;
auto ret = timepointToJulday(tp, &jd);
if (ret) {
return ret;
@ -852,14 +896,14 @@ protected:
using real_days_t = std::chrono::duration<double, std::ratio<86400>>;
auto tai_utc = _currentState._leapSeconds[jd.mjd];
auto tai_utc = _currentState._leapSeconds[jd.MJD()];
if (tai_utc.has_value()) {
tt.mjd = jd.mjd + std::chrono::duration_cast<real_days_t>(tai_utc.value()).count();
tt = jd.MJD() + std::chrono::duration_cast<real_days_t>(tai_utc.value()).count();
auto tt_tai = _currentState._bulletinA.TT_TAI();
tt.mjd = jd.mjd + std::chrono::duration_cast<real_days_t>(tt_tai).count();
tt += +std::chrono::duration_cast<real_days_t>(tt_tai).count();
*eo = eraEo06a(tt.MJD0, tt.mjd);
*eo = eraEo06a(jd.MJD0, tt);
} else {
ret = MccCCTE_ERFAErrorCode::ERROR_LEAPSECONDS_OUT_OF_RANGE;
}

View File

@ -22,19 +22,37 @@ typedef std::chrono::system_clock::time_point MccTimePoint;
struct MccJulianDay {
static constexpr double MJD0 = 2400000.5;
double mjd{51544.5}; // J2000.0
MccJulianDay() = default;
MccJulianDay(double jd) : mjd(jd - MJD0) {}
constexpr operator double() const
{
return MccJulianDay::MJD0 + mjd;
}
MccJulianDay& operator=(double jd)
{
mjd = jd - MJD0;
return *this;
}
double MJD() const
{
return mjd;
}
constexpr auto operator<=>(const MccJulianDay&) const = default;
constexpr auto operator<=>(double v) const
{
return v <=> (MccJulianDay::MJD0 + mjd);
};
protected:
double mjd{51544.5}; // J2000.0
};

View File

@ -21,6 +21,46 @@ namespace mcc
// mount construction type (only the most common ones)
enum class MccMountType : uint8_t { GERMAN_TYPE, FORK_TYPE, CROSSAXIS_TYPE, ALTAZ_TYPE };
template <MccMountType TYPE>
static constexpr std::string_view MccMountTypeStr = TYPE == MccMountType::GERMAN_TYPE ? "GERMAN"
: TYPE == MccMountType::FORK_TYPE ? "FORK"
: TYPE == MccMountType::CROSSAXIS_TYPE ? "CROSSAXIS"
: TYPE == MccMountType::ALTAZ_TYPE ? "ALTAZ"
: "UNKNOWN";
template <MccMountType TYPE>
static constexpr bool mcc_is_equatorial_mount = TYPE == MccMountType::GERMAN_TYPE ? true
: TYPE == MccMountType::FORK_TYPE ? true
: TYPE == MccMountType::CROSSAXIS_TYPE ? true
: TYPE == MccMountType::ALTAZ_TYPE ? false
: false;
template <MccMountType TYPE>
static constexpr bool mcc_is_altaz_mount = TYPE == MccMountType::GERMAN_TYPE ? false
: TYPE == MccMountType::FORK_TYPE ? false
: TYPE == MccMountType::CROSSAXIS_TYPE ? false
: TYPE == MccMountType::ALTAZ_TYPE ? true
: false;
static consteval bool mccIsEquatorialMount(const MccMountType type)
{
return type == MccMountType::GERMAN_TYPE ? true
: type == MccMountType::FORK_TYPE ? true
: type == MccMountType::CROSSAXIS_TYPE ? true
: type == MccMountType::ALTAZ_TYPE ? false
: false;
};
static consteval bool mccIsAltAzMount(const MccMountType type)
{
return type == MccMountType::GERMAN_TYPE ? false
: type == MccMountType::FORK_TYPE ? false
: type == MccMountType::CROSSAXIS_TYPE ? false
: type == MccMountType::ALTAZ_TYPE ? true
: false;
};
// enum MccCoordPairKind : size_t {
// COORDS_KIND_GENERIC,
// COORDS_KIND_RADEC_ICRS,
@ -68,6 +108,8 @@ concept mcc_time_point_c = requires(T t) { []<typename CT, typename DT>(std::chr
template <typename T>
concept mcc_julday_c = mcc_fp_type_like_c<T> && requires(const T v) {
// modified Julian Day
{ v.MJD() } -> std::convertible_to<double>;
// comparison operators
v <=> v;
};
@ -145,7 +187,7 @@ struct mcc_CCTE_interface_t {
return std::forward<SelfT>(self).transformCoordinates(std::move(from_pt), to_pt);
}
// NOTE: ASSUMING THE AZINUTH IS COUNTED FROM THE SOUTH THROUGH THE WEST!!!
// NOTE: ASSUMING THE AZIMUTH IS COUNTED FROM THE SOUTH THROUGH THE WEST!!!
template <std::derived_from<mcc_CCTE_interface_t> SelfT>
RetT transformCoordinates(this SelfT&& self, mcc_celestial_point_c auto from_pt, mcc_eqt_hrz_coord_c auto* to_pt)
{
@ -275,7 +317,7 @@ concept mcc_hardware_c = requires(T t, const T t_const) {
// a class that contains at least time point of measurement, coordinates for x,y axes and its moving rates
requires requires(typename T::axes_pos_t pos) {
requires mcc_time_point_c<typename T::time_point_t>; // time point
requires mcc_time_point_c<decltype(pos.time_point)>; // time point
requires mcc_angle_c<decltype(pos.X)>; // target or current co-longitude coordinate
requires mcc_angle_c<decltype(pos.Y)>; // target or current co-latitude coordinate

187
mcc/mcc_telemetry.h Normal file
View File

@ -0,0 +1,187 @@
#pragma once
/* MOUNT CONTROL COMPONENTS LIBRARY */
/* IMPLEMENTATION OF TELEMETRY CLASS */
#include "mcc_defaults.h"
namespace mcc
{
static constexpr double mcc_sideral_to_UT1_ratio = 1.002737909350795; // sideral/UT1
enum MccTelemetryErrorCode : int { ERROR_OK, ERROR_COORD_TRANSFROM, ERROR_PCM_COMP };
} // namespace mcc
namespace std
{
template <>
class is_error_code_enum<mcc::MccTelemetryErrorCode> : public true_type
{
};
} // namespace std
namespace mcc
{
/* error category definition */
// error category
struct MccTelemetryCategory : public std::error_category {
MccTelemetryCategory() : std::error_category() {}
const char* name() const noexcept
{
return "ALTITUDE-LIMIT-PZ";
}
std::string message(int ec) const
{
MccTelemetryErrorCode err = static_cast<MccTelemetryErrorCode>(ec);
switch (err) {
case MccTelemetryErrorCode::ERROR_OK:
return "OK";
case MccTelemetryErrorCode::ERROR_COORD_TRANSFROM:
return "coordinate transformation error";
case MccTelemetryErrorCode::ERROR_PCM_COMP:
return "PCM computation error";
default:
return "UNKNOWN";
}
}
static const MccTelemetryCategory& get()
{
static const MccTelemetryCategory constInst;
return constInst;
}
};
inline std::error_code make_error_code(MccTelemetryErrorCode ec)
{
return std::error_code(static_cast<int>(ec), MccTelemetryCategory::get());
}
/* TELEMETRY UPDATE POLICY */
enum class MccTelemetryUpdatePolicy : int { TEMETRY_UPDATE_INNER, TEMETRY_UPDATE_EXTERNAL };
template <MccTelemetryUpdatePolicy UPDATE_POLICY = MccTelemetryUpdatePolicy::TEMETRY_UPDATE_INNER>
class MccTelemetry : public mcc_telemetry_interface_t<std::error_code>
{
public:
static constexpr MccTelemetryUpdatePolicy updatePolicy = UPDATE_POLICY;
typedef std::error_code error_t;
MccTelemetry(mcc_ccte_c auto* ccte, mcc_PCM_c auto* pcm, mcc_hardware_c auto* hardware)
{
using ccte_t = std::remove_cvref_t<decltype(*ccte)>;
using pcm_t = std::remove_cvref_t<decltype(*pcm)>;
using hardware_t = std::remove_cvref_t<decltype(*hardware)>;
_updateFunc = [ccte, pcm, hardware, this](MccTelemetryData* data) {
typename hardware_t::axes_pos_t hw_pos;
auto hw_err = hardware->getPos(&hw_pos);
if (!hw_err) {
data->time_point =
std::chrono::time_point_cast<typename decltype(data->time_point)::duration>(hw_pos.time_point);
auto ccte_err = ccte->timepointToJulday(data->time_point, &data->JD);
if (!ccte_err) {
ccte_err = ccte->timepointToAppSideral(data->time_point, &data->LST, true);
if (!ccte_err) {
data->speedX = (double)hw_pos.speedX;
data->speedY = (double)hw_pos.speedY;
struct {
double dx, dy;
} pcm_res;
auto pcm_err = pcm->computePCM(data, &pcm_res);
if (pcm_err) {
if constexpr (std::same_as<decltype(pcm_err), error_t>) {
return pcm_err;
} else {
return MccTelemetryErrorCode::ERROR_PCM_COMP;
}
}
MccCelestialPoint pt{.pair_kind = MccCoordPairKind::COORDS_KIND_AZALT,
.time_point = data->time_point};
if constexpr (mccIsEquatorialMount(pcm_t::mountType)) {
data->HA = (double)hw_pos.X + pcm_res.dx;
data->DEC_APP = (double)hw_pos.Y + pcm_res.dy;
data->X = data->HA;
data->Y = data->DEC_APP;
data->pair_kind = MccCoordPairKind::COORDS_KIND_HADEC_APP;
ccte_err = ccte->transformCoordinates(*data, &pt);
if (!ccte_err) {
data->AZ = pt.X;
data->ALT = pt.Y;
data->ZD = std::numbers::pi / 2.0 - data->ALT;
}
} else if constexpr (mccIsAltAzMount(pcm_t::mountType)) {
data->AZ = (double)hw_pos.X + pcm_res.dx;
data->ALT = (double)hw_pos.Y + pcm_res.dy;
data->ZD = std::numbers::pi / 2.0 - data->ALT;
data->X = data->AZ;
data->Y = data->ALT;
data->pair_kind = MccCoordPairKind::COORDS_KIND_AZALT;
pt.pair_kind = MccCoordPairKind::COORDS_KIND_HADEC_APP;
ccte_err = ccte->transformCoordinates(*data, &pt);
if (!ccte) {
data->HA = pt.X;
data->DEC_APP = pt.Y;
}
} else {
static_assert(false, "UNKNOWN MOUNT TYPE!");
}
}
}
}
};
}
error_t telemetryData(mcc_telemetry_data_c auto* data)
{
error_t ret = MccTelemetryErrorCode::ERROR_OK;
// first, update mount coordinates
return ret;
}
error_t setPointingTarget(mcc_celestial_point_c auto pt) {}
protected:
std::function<error_t(MccTelemetryData*)> _updateFunc;
};
} // namespace mcc