This commit is contained in:
Timur A. Fatkhullin 2025-07-21 00:33:06 +03:00
parent 9cd52267d6
commit 6d65efd0af
6 changed files with 323 additions and 181 deletions

View File

@ -10,10 +10,39 @@
#include "mcc_astrom_iers.h" #include "mcc_astrom_iers.h"
#include "mcc_mount_concepts.h"
#include "mcc_mount_coord.h" #include "mcc_mount_coord.h"
// #include "mcc_mount_astrom.h"
#include "mcc_mount_concepts.h" namespace mcc::astrom::erfa
{
enum class MccMountAstromEngineERFAErrorCode : int {
ERROR_OK = 0,
ERROR_INVALID_INPUT_ARG,
ERROR_JULDATE_INVALID_YEAR,
ERROR_JULDATE_INVALID_MONTH,
ERROR_BULLETINA_OUT_OF_RANGE,
ERROR_LEAPSECONDS_OUT_OF_RANGE,
ERROR_DUBIOUS_YEAR,
ERROR_UNACCEPTABLE_DATE,
ERROR_UPDATE_LEAPSECONDS,
ERROR_UPDATE_BULLETINA,
};
}
namespace std
{
template <>
class is_error_code_enum<mcc::astrom::erfa::MccMountAstromEngineERFAErrorCode> : public true_type
{
};
} // namespace std
namespace mcc::astrom::erfa namespace mcc::astrom::erfa
{ {
@ -22,6 +51,62 @@ namespace mcc::astrom::erfa
#include <erfam.h> #include <erfam.h>
/* error category definition */
// error category
struct MccMountAstromEngineERFACategory : public std::error_category {
MccMountAstromEngineERFACategory() : std::error_category() {}
const char* name() const noexcept
{
return "ADC_GENERIC_DEVICE";
}
std::string message(int ec) const
{
MccMountAstromEngineERFAErrorCode err = static_cast<MccMountAstromEngineERFAErrorCode>(ec);
switch (err) {
case MccMountAstromEngineERFAErrorCode::ERROR_OK:
return "OK";
case MccMountAstromEngineERFAErrorCode::ERROR_INVALID_INPUT_ARG:
return "invalid argument";
case MccMountAstromEngineERFAErrorCode::ERROR_JULDATE_INVALID_YEAR:
return "invalid year number";
case MccMountAstromEngineERFAErrorCode::ERROR_JULDATE_INVALID_MONTH:
return "invalid month number";
case MccMountAstromEngineERFAErrorCode::ERROR_BULLETINA_OUT_OF_RANGE:
return "time point is out of range";
case MccMountAstromEngineERFAErrorCode::ERROR_LEAPSECONDS_OUT_OF_RANGE:
return "time point is out of range";
case MccMountAstromEngineERFAErrorCode::ERROR_DUBIOUS_YEAR:
return "dubious year";
case MccMountAstromEngineERFAErrorCode::ERROR_UNACCEPTABLE_DATE:
return "unacceptable date";
case MccMountAstromEngineERFAErrorCode::ERROR_UPDATE_LEAPSECONDS:
return "leap seconds update error";
case MccMountAstromEngineERFAErrorCode::ERROR_UPDATE_BULLETINA:
return "bulletin A update error";
default:
return "UNKNOWN";
}
}
static const MccMountAstromEngineERFACategory& get()
{
static const MccMountAstromEngineERFACategory constInst;
return constInst;
}
};
inline std::error_code make_error_code(MccMountAstromEngineERFAErrorCode ec)
{
return std::error_code(static_cast<int>(ec), MccMountAstromEngineERFACategory::get());
}
/* A concept for ERFA-library compatible type to represent anglular quantities */ /* A concept for ERFA-library compatible type to represent anglular quantities */
template <typename T> template <typename T>
concept mcc_erfa_angle_t = std::constructible_from<T, double> && std::convertible_to<T, double>; concept mcc_erfa_angle_t = std::constructible_from<T, double> && std::convertible_to<T, double>;
@ -29,32 +114,10 @@ concept mcc_erfa_angle_t = std::constructible_from<T, double> && std::convertibl
template <mcc_erfa_angle_t AngleT = MccAngle> template <mcc_erfa_angle_t AngleT = MccAngle>
class MccMountAstromEngineERFA class MccMountAstromEngineERFA
{ {
protected:
static constexpr std::array engineErrorString = {"OK",
"invalid argument",
"invalid year",
"invalid month",
"time point is out of range",
"time point is out of range",
"dubious year",
"unacceptable year",
"leap seconds update error",
"bulletin A update error"};
public: public:
static constexpr double DEFAULT_WAVELENGTH = 0.55; // default observed wavelength in mkm static constexpr double DEFAULT_WAVELENGTH = 0.55; // default observed wavelength in mkm
enum error_t : size_t {
ERROR_OK = 0, typedef std::error_code error_t;
ERROR_INVALID_INPUT_ARG,
ERROR_JULDATE_INVALID_YEAR,
ERROR_JULDATE_INVALID_MONTH,
ERROR_BULLETINA_OUT_OF_RANGE,
ERROR_LEAPSECONDS_OUT_OF_RANGE,
ERROR_DUBIOUS_YEAR,
ERROR_UNACCEPTABLE_DATE,
ERROR_UPDATE_LEAPSECONDS,
ERROR_UPDATE_BULLETINA,
};
// meteo parameters (to compute refraction) // meteo parameters (to compute refraction)
@ -140,10 +203,10 @@ public:
std::lock_guard lock{_stateMutex}; std::lock_guard lock{_stateMutex};
if (!_currentState._leapSeconds.load(stream, comment_sym)) { if (!_currentState._leapSeconds.load(stream, comment_sym)) {
return ERROR_UPDATE_LEAPSECONDS; return MccMountAstromEngineERFAErrorCode::ERROR_UPDATE_LEAPSECONDS;
} }
return ERROR_OK; return MccMountAstromEngineERFAErrorCode::ERROR_OK;
} }
@ -152,10 +215,10 @@ public:
std::lock_guard lock{_stateMutex}; std::lock_guard lock{_stateMutex};
if (!_currentState._leapSeconds.load(filename, comment_sym)) { if (!_currentState._leapSeconds.load(filename, comment_sym)) {
return ERROR_UPDATE_LEAPSECONDS; return MccMountAstromEngineERFAErrorCode::ERROR_UPDATE_LEAPSECONDS;
} }
return ERROR_OK; return MccMountAstromEngineERFAErrorCode::ERROR_OK;
} }
@ -164,10 +227,10 @@ public:
std::lock_guard lock{_stateMutex}; std::lock_guard lock{_stateMutex};
if (!_currentState._bulletinA.load(stream, comment_sym)) { if (!_currentState._bulletinA.load(stream, comment_sym)) {
return ERROR_UPDATE_BULLETINA; return MccMountAstromEngineERFAErrorCode::ERROR_UPDATE_BULLETINA;
} }
return ERROR_OK; return MccMountAstromEngineERFAErrorCode::ERROR_OK;
} }
@ -176,19 +239,13 @@ public:
std::lock_guard lock{_stateMutex}; std::lock_guard lock{_stateMutex};
if (!_currentState._bulletinA.load(filename, comment_sym)) { if (!_currentState._bulletinA.load(filename, comment_sym)) {
return ERROR_UPDATE_BULLETINA; return MccMountAstromEngineERFAErrorCode::ERROR_UPDATE_BULLETINA;
} }
return ERROR_OK; return MccMountAstromEngineERFAErrorCode::ERROR_OK;
} }
std::string errorString(error_t err) const
{
return engineErrorString[err];
}
/* time-related methods */ /* time-related methods */
// templated generic version // templated generic version
@ -203,10 +260,10 @@ public:
static constexpr std::chrono::year MIN_YEAR = -4799y; static constexpr std::chrono::year MIN_YEAR = -4799y;
if (ymd.year() < MIN_YEAR) { if (ymd.year() < MIN_YEAR) {
return ERROR_JULDATE_INVALID_YEAR; return MccMountAstromEngineERFAErrorCode::ERROR_JULDATE_INVALID_YEAR;
} }
if (!ymd.month().ok()) { if (!ymd.month().ok()) {
return ERROR_JULDATE_INVALID_MONTH; return MccMountAstromEngineERFAErrorCode::ERROR_JULDATE_INVALID_MONTH;
} }
int64_t im = (unsigned)ymd.month(); int64_t im = (unsigned)ymd.month();
@ -223,7 +280,7 @@ public:
using fd_t = std::chrono::duration<double, std::ratio<86400>>; // fraction of day using fd_t = std::chrono::duration<double, std::ratio<86400>>; // fraction of day
juldate.mjd = static_cast<double>(mjd_int) + std::chrono::duration_cast<fd_t>(time_point - dd).count(); juldate.mjd = static_cast<double>(mjd_int) + std::chrono::duration_cast<fd_t>(time_point - dd).count();
return ERROR_OK; return MccMountAstromEngineERFAErrorCode::ERROR_OK;
} }
error_t greg2jul(time_point_t time_point, juldate_t& juldate) error_t greg2jul(time_point_t time_point, juldate_t& juldate)
@ -242,14 +299,14 @@ public:
if (tai_utc.has_value()) { if (tai_utc.has_value()) {
tt.mjd += std::chrono::duration_cast<real_days_t>(tai_utc.value()).count(); tt.mjd += std::chrono::duration_cast<real_days_t>(tai_utc.value()).count();
} else { } else {
return ERROR_LEAPSECONDS_OUT_OF_RANGE; return MccMountAstromEngineERFAErrorCode::ERROR_LEAPSECONDS_OUT_OF_RANGE;
} }
auto tt_tai = _currentState._bulletinA.TT_TAI(); auto tt_tai = _currentState._bulletinA.TT_TAI();
tt.mjd = juldate.mjd + std::chrono::duration_cast<real_days_t>(tt_tai).count(); tt.mjd = juldate.mjd + std::chrono::duration_cast<real_days_t>(tt_tai).count();
return ERROR_OK; return MccMountAstromEngineERFAErrorCode::ERROR_OK;
} }
@ -270,7 +327,7 @@ public:
if (dut1.has_value()) { if (dut1.has_value()) {
ut1 += std::chrono::duration_cast<real_days_t>(dut1.value()).count(); ut1 += std::chrono::duration_cast<real_days_t>(dut1.value()).count();
} else { // out of range } else { // out of range
return ERROR_BULLETINA_OUT_OF_RANGE; return MccMountAstromEngineERFAErrorCode::ERROR_BULLETINA_OUT_OF_RANGE;
} }
} }
@ -288,7 +345,7 @@ public:
juldate_t tt; juldate_t tt;
auto err = terrestrialTime(juldate, tt); auto err = terrestrialTime(juldate, tt);
if (err != ERROR_OK) { if (err != MccMountAstromEngineERFAErrorCode::ERROR_OK) {
return err; return err;
} }
@ -297,7 +354,7 @@ public:
gst += _currentState.lon; gst += _currentState.lon;
} }
return ERROR_OK; return MccMountAstromEngineERFAErrorCode::ERROR_OK;
} }
@ -306,13 +363,13 @@ public:
juldate_t tt; juldate_t tt;
auto err = terrestrialTime(juldate, tt); auto err = terrestrialTime(juldate, tt);
if (err != ERROR_OK) { if (err != MccMountAstromEngineERFAErrorCode::ERROR_OK) {
return err; return err;
} }
eo = eraEo06a(tt.MJD0, tt.mjd); eo = eraEo06a(tt.MJD0, tt.mjd);
return ERROR_OK; return MccMountAstromEngineERFAErrorCode::ERROR_OK;
} }
/* atmospheric refraction-related methods */ /* atmospheric refraction-related methods */
@ -324,7 +381,7 @@ public:
eraRefco(_currentState.meteo.pressure, _currentState.meteo.temperature, _currentState.meteo.humidity, eraRefco(_currentState.meteo.pressure, _currentState.meteo.temperature, _currentState.meteo.humidity,
_currentState.wavelength, &refr.refa, &refr.refb); _currentState.wavelength, &refr.refa, &refr.refb);
return ERROR_OK; return MccMountAstromEngineERFAErrorCode::ERROR_OK;
} }
@ -337,7 +394,7 @@ public:
corr = ref_params.refa / tanALT + ref_params.refb / tanALT / tanALT / tanALT; corr = ref_params.refa / tanALT + ref_params.refb / tanALT / tanALT / tanALT;
} }
return ERROR_OK; return MccMountAstromEngineERFAErrorCode::ERROR_OK;
} }
/* coordinates conversional methods */ /* coordinates conversional methods */
@ -357,12 +414,12 @@ public:
auto dut1 = _currentState._bulletinA.DUT1(juldate.mjd); auto dut1 = _currentState._bulletinA.DUT1(juldate.mjd);
if (!dut1.has_value()) { if (!dut1.has_value()) {
return ERROR_BULLETINA_OUT_OF_RANGE; return MccMountAstromEngineERFAErrorCode::ERROR_BULLETINA_OUT_OF_RANGE;
} }
auto pol_pos = _currentState._bulletinA.polarCoords(juldate.mjd); auto pol_pos = _currentState._bulletinA.polarCoords(juldate.mjd);
if (!pol_pos.has_value()) { if (!pol_pos.has_value()) {
return ERROR_BULLETINA_OUT_OF_RANGE; return MccMountAstromEngineERFAErrorCode::ERROR_BULLETINA_OUT_OF_RANGE;
} }
const auto arcsec2rad = std::numbers::pi / 180 / 3600; const auto arcsec2rad = std::numbers::pi / 180 / 3600;
pol_pos->x *= arcsec2rad; pol_pos->x *= arcsec2rad;
@ -376,9 +433,9 @@ public:
&oaz, &ozd, &oha, &odec, &ora, &eo_); &oaz, &ozd, &oha, &odec, &ora, &eo_);
if (ret == 1) { if (ret == 1) {
return ERROR_DUBIOUS_YEAR; return MccMountAstromEngineERFAErrorCode::ERROR_DUBIOUS_YEAR;
} else if (ret == -1) { } else if (ret == -1) {
return ERROR_UNACCEPTABLE_DATE; return MccMountAstromEngineERFAErrorCode::ERROR_UNACCEPTABLE_DATE;
} }
ra_app = ora; ra_app = ora;
@ -388,7 +445,7 @@ public:
ha = oha; ha = oha;
eo = eo_; eo = eo_;
return ERROR_OK; return MccMountAstromEngineERFAErrorCode::ERROR_OK;
} }
@ -402,7 +459,7 @@ public:
az = r_az; az = r_az;
alt = r_alt; alt = r_alt;
return ERROR_OK; return MccMountAstromEngineERFAErrorCode::ERROR_OK;
} }
error_t azalt2hadec(coord_t az, coord_t alt, coord_t& ha, coord_t& dec) error_t azalt2hadec(coord_t az, coord_t alt, coord_t& ha, coord_t& dec)
@ -416,7 +473,7 @@ public:
ha = r_ha; ha = r_ha;
dec = r_dec; dec = r_dec;
return ERROR_OK; return MccMountAstromEngineERFAErrorCode::ERROR_OK;
} }
@ -426,7 +483,7 @@ public:
pa = eraHd2pa(ha, dec, _currentState.lat); pa = eraHd2pa(ha, dec, _currentState.lat);
return ERROR_OK; return MccMountAstromEngineERFAErrorCode::ERROR_OK;
} }

View File

@ -97,12 +97,6 @@ concept mcc_astrom_engine_c = requires(T t, const T t_const) {
typename T::refract_result_t; typename T::refract_result_t;
// { t.setState(std::declval<typename T::engine_state_t>()) };
// { t_const.getState() } -> std::same_as<typename T::engine_state_t>;
{ t_const.errorString(std::declval<typename T::error_t>()) } -> mcc_formattable;
/* coordinates conversional methods */ /* coordinates conversional methods */
// ICRS RA and DEC to observed place: icrs2obs(ra, dec, jd, ra_app, dec_app, ha, az, alt, eo) // ICRS RA and DEC to observed place: icrs2obs(ra, dec, jd, ra_app, dec_app, ha, az, alt, eo)
@ -249,7 +243,7 @@ concept mcc_mount_telemetry_data_c = requires(T telemetry) {
template <typename T> template <typename T>
concept mcc_mount_telemetry_c = requires(T t, const T t_const) { concept mcc_mount_telemetry_c = requires(T t, const T t_const) {
typename T::error_t; requires mcc_error_c<typename T::error_t>;
// // a class that at least contains celestial (equatorial and horizontal) coordinates // // a class that at least contains celestial (equatorial and horizontal) coordinates
// requires requires(typename T::mount_telemetry_data_t telemetry) { // requires requires(typename T::mount_telemetry_data_t telemetry) {

View File

@ -12,6 +12,65 @@
#include "mcc_mount_concepts.h" #include "mcc_mount_concepts.h"
#include "mcc_mount_coord.h" #include "mcc_mount_coord.h"
namespace mcc
{
enum class MccMountDefaultPECErrorCode : int { ERROR_OK, ERROR_INVALID_INPUTS_BISPLEV, ERROR_EXCEED_MAX_ITERS };
/* error category definition */
// error category
struct MccMountDefaultPECCategory : public std::error_category {
MccMountDefaultPECCategory() : std::error_category() {}
const char* name() const noexcept
{
return "ADC_GENERIC_DEVICE";
}
std::string message(int ec) const
{
MccMountDefaultPECErrorCode err = static_cast<MccMountDefaultPECErrorCode>(ec);
switch (err) {
case MccMountDefaultPECErrorCode::ERROR_OK:
return "OK";
case MccMountDefaultPECErrorCode::ERROR_INVALID_INPUTS_BISPLEV:
return "invalid input arguments for bispev";
case MccMountDefaultPECErrorCode::ERROR_EXCEED_MAX_ITERS:
return "exceed maximum of iterations number";
default:
return "UNKNOWN";
}
}
static const MccMountDefaultPECCategory& get()
{
static const MccMountDefaultPECCategory constInst;
return constInst;
}
};
inline std::error_code make_error_code(MccMountDefaultPECErrorCode ec)
{
return std::error_code(static_cast<int>(ec), MccMountDefaultPECCategory::get());
}
} // namespace mcc
namespace std
{
template <>
class is_error_code_enum<mcc::MccMountDefaultPECErrorCode> : public true_type
{
};
} // namespace std
namespace mcc namespace mcc
{ {
@ -165,7 +224,7 @@ public:
if (ret) { if (ret) {
res.dx = std::numeric_limits<double>::quiet_NaN(); res.dx = std::numeric_limits<double>::quiet_NaN();
res.dy = std::numeric_limits<double>::quiet_NaN(); res.dy = std::numeric_limits<double>::quiet_NaN();
return std::error_code(); // !!!!!!!!!!!!!! return MccMountDefaultPECErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
} }
@ -175,7 +234,7 @@ public:
if (ret) { if (ret) {
res.dx = std::numeric_limits<double>::quiet_NaN(); res.dx = std::numeric_limits<double>::quiet_NaN();
res.dy = std::numeric_limits<double>::quiet_NaN(); res.dy = std::numeric_limits<double>::quiet_NaN();
return std::error_code(); // !!!!!!!!!!!!!! return MccMountDefaultPECErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
} }
@ -187,7 +246,7 @@ public:
static_assert(false, "UNSUPPORTED"); static_assert(false, "UNSUPPORTED");
} }
return std::error_code(); return MccMountDefaultPECErrorCode::ERROR_OK;
} }
// from celestial to encoder (use of iterative scheme) // from celestial to encoder (use of iterative scheme)
@ -196,35 +255,59 @@ public:
coord_t e2 = eps * eps; coord_t e2 = eps * eps;
coord_t xi = x, yi = y; coord_t xi = x, yi = y;
coord_t xp, yp; coord_t xe, ye;
size_t iter = 1; size_t iter = 1;
// the first iteration // the first iteration
auto err = compute(x, y, res); auto err = compute(x, y, res);
if (!err) { if (!err) {
xp = x - res.dx; // 'encoder' cocordinates
yp = y - res.dy; xe = x - res.dx;
ye = y - res.dy;
bool ok = ((xp - x) * (xp - x) + (yp - y) * (yp - y)) <= e2; err = compute(xe, ye, res); // to celestial
if (err) {
return MccMountDefaultPECErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
}
xi = xe + res.dx; // celestial
yi = ye + res.dy;
auto rx = (x - xi);
auto ry = (y - yi);
auto d = rx * rx + ry * ry;
bool ok = d <= e2;
if (ok) { if (ok) {
return std::error_code(); return MccMountDefaultPECErrorCode::ERROR_OK;
} }
while (iter < max_iter) { while (iter < max_iter) {
xi = xp; err = compute(xi, yi, res); // to encoder
yi = xp; if (err) {
err = compute(xi, yi, res); return MccMountDefaultPECErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
xp -= res.dx;
yp -= res.dy;
ok = ((xp - xi) * (xp - xi) + (yp - yi) * (yp - yi)) <= e2;
if (ok) {
return std::error_code();
} }
xe = x - res.dx;
ye = y - res.dy;
err = compute(xe, ye, res); // to celestial
if (err) {
return MccMountDefaultPECErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
}
xi = xe + res.dx; // celestial
yi = ye + res.dy;
ok = ((x - xi) * (x - xi) + (y - yi) * (y - yi)) <= e2;
if (ok) {
return MccMountDefaultPECErrorCode::ERROR_OK;
}
++iter;
} }
// err = "exceed max iterations";!!! err = MccMountDefaultPECErrorCode::ERROR_EXCEED_MAX_ITERS;
} }
return err; return err;

View File

@ -139,42 +139,6 @@ public:
typedef DATA_T mount_telemetry_data_t; typedef DATA_T mount_telemetry_data_t;
// mount current telemetry data: time, position and related quantities
// struct mount_telemetry_data_t {
// typedef typename astrom_engine_t::coord_t coord_t;
// // time-related
// typename astrom_engine_t::time_point_t utc; // time point of measurements, UTC
// typename astrom_engine_t::juldate_t jd; // Julian date
// typename astrom_engine_t::sideral_time_t siderTime; // local apperant sideral time
// // typename astrom_engine_t::time_point_t ut1; // Universal time
// // typename astrom_engine_t::time_point_t tt; // Terrestial time
// // apparent target (user-input) current coordinates (in radians)
// coord_t tagRA, tagDEC;
// coord_t tagHA;
// coord_t tagAZ, tagALT;
// coord_t tagPA; // paralactic angle
// // encoder-measured current mount coordinates (in radians)
// coord_t mntRA, mntDEC;
// coord_t mntHA;
// coord_t mntAZ, mntALT;
// typename astrom_engine_t::pa_t mntPA;
// // encoder-measured (non-corrected for PCS) current mount position and moving speed (in radians, radians/s)
// // X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ALT for horizontal-type one
// coord_t mntPosX, mntPosY;
// // current refraction coefficients
// typename pec_t::pec_result_t currRefrCoeffs;
// // current refraction correction (for mntALT)
// coord_t currRefr;
// // PEC (pointing error correction):
// // X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ALT for horizontal-type one
// coord_t pecX, pecY;
// };
MccMountTelemetry(astrom_engine_t& astrom_engine, pec_t& pec, hardware_t& hardware) MccMountTelemetry(astrom_engine_t& astrom_engine, pec_t& pec, hardware_t& hardware)
: _astromEngine(astrom_engine), _pec(pec), _hardware(hardware) : _astromEngine(astrom_engine), _pec(pec), _hardware(hardware)

View File

@ -19,7 +19,6 @@ namespace mcc
* [azimuth, zenithal distance] (see sources code below) * [azimuth, zenithal distance] (see sources code below)
*/ */
template <traits::mcc_mount_telemetry_c TELEMETRY_T>
class MccSimpleSlewModel class MccSimpleSlewModel
{ {
public: public:
@ -37,26 +36,47 @@ public:
}; };
template <traits::mcc_mount_hardware_c HARDWARE_T, template <traits::mcc_mount_controls_c MOUNT_CONTROLS_T>
traits::mcc_astrom_engine_c ASTROM_T, MccSimpleSlewModel(MOUNT_CONTROLS_T& mount_controls)
traits::mcc_mount_pec_c PEC_T>
MccSimpleSlewModel(HARDWARE_T& hardware, ASTROM_T& astrom_engine, PEC_T& pec)
{ {
const auto p_hardware = &hardware; // deduce controls types
const auto p_astrom_engine = &astrom_engine; using astrom_engine_t = decltype(mount_controls.astrometryEngine);
const auto p_pec = &pec; using hardware_t = decltype(mount_controls.hardware);
using pec_t = decltype(mount_controls.PEC);
using telemetry_t = decltype(mount_controls.telemetry);
using tpl_pz_t = decltype(mount_controls.prohibitedZones);
static constexpr size_t Nzones = std::tuple_size_v<tpl_pz_t>;
const auto p_mount_controls = &mount_controls;
// prohibited zones related lambdas
auto check_zones = [p_mount_controls]<size_t... Is>(std::array<bool, sizeof...(Is)>& result,
std::index_sequence<Is...>) {
((result[Is] = std::get<Is>(p_mount_controls->prohibitedZones).inZone(p_mount_controls->telemetry.data())),
...);
bool flag = false;
((flag |= result[Is]), ...);
return flag;
};
_slewFunc = [p_mount_controls](this auto&& self, const slew_params_t& slew_pars) {
auto& astrom_engine = p_mount_controls->astrometryEngine;
auto& hardware = p_mount_controls->hardware;
auto& pec = p_mount_controls->PEC;
auto& telemetry = p_mount_controls->telemetry;
_slewFunc = [p_hardware, p_astrom_engine, p_pec](this auto&& self, const slew_params_t& slew_pars, using coord_t = typename astrom_engine_t::coord_t;
TELEMETRY_T& telemetry) { using jd_t = typename astrom_engine_t::juldate_t;
using coord_t = typename ASTROM_T::coord_t;
using jd_t = typename ASTROM_T::juldate_t;
typename HARDWARE_T::axes_pos_t ax_pos; typename hardware_t::axes_pos_t ax_pos;
error_t res_err; error_t res_err;
typename ASTROM_T::error_t ast_err; typename astrom_engine_t::error_t ast_err;
typename pec_t::error_t pec_err;
if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_XY) { if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_XY) {
// trivial case (the pair is interpretated as raw encoder coordinates) // trivial case (the pair is interpretated as raw encoder coordinates)
@ -66,26 +86,24 @@ public:
mcc::MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // catalog coordinates mcc::MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // catalog coordinates
jd_t jd; jd_t jd;
coord_t ra_app, dec_app, ha, az, alt; coord_t ra_app, dec_app, ha, az, alt;
typename ASTROM_T::eo_t eo; typename astrom_engine_t::eo_t eo;
ast_err = p_astrom_engine->greg2jul(std::chrono::system_clock::now(), jd); ast_err = astrom_engine->greg2jul(std::chrono::system_clock::now(), jd);
if (!ast_err) { if (!ast_err) {
ast_err = p_astrom_engine->icrs2obs(slew_pars.x, slew_pars.y, jd, ra_app, dec_app, ha, az, alt, eo); ast_err = astrom_engine->icrs2obs(slew_pars.x, slew_pars.y, jd, ra_app, dec_app, ha, az, alt, eo);
if (!ast_err) { if (!ast_err) {
if constexpr (mccIsEquatorialMount(PEC_T::mountType)) { if constexpr (mccIsEquatorialMount(pec_t::mountType)) {
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP, res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP,
.x = ha, .x = ha,
.y = dec_app, .y = dec_app,
.stop = slew_pars.stop}, .stop = slew_pars.stop});
telemetry); } else if constexpr (mccIsAltAzMount(pec_t::mountType)) {
} else if constexpr (mccIsAltAzMount(PEC_T::mountType)) {
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_AZALT, res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_AZALT,
.x = az, .x = az,
.y = alt, .y = alt,
.stop = slew_pars.stop}, .stop = slew_pars.stop});
telemetry);
} else { } else {
static_assert(false, "UNKNOWN MOUNT TYPE!"); static_assert(false, "UNKNOWN MOUNT TYPE!");
} }
@ -94,78 +112,73 @@ public:
} else if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_RADEC_APP) { // apparent } else if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_RADEC_APP) { // apparent
jd_t jd; jd_t jd;
typename ASTROM_T::eo_t eo; typename astrom_engine_t::eo_t eo;
ast_err = p_astrom_engine->greg2jul(std::chrono::system_clock::now(), jd); ast_err = astrom_engine->greg2jul(std::chrono::system_clock::now(), jd);
if (!ast_err) { if (!ast_err) {
typename ASTROM_T::sideral_time_t lst; typename astrom_engine_t::sideral_time_t lst;
ast_err = p_astrom_engine->apparentSiderTime(jd, lst, true); ast_err = astrom_engine->apparentSiderTime(jd, lst, true);
if (!ast_err) { if (!ast_err) {
ast_err = p_astrom_engine->eqOrigins(jd, eo); ast_err = astrom_engine->eqOrigins(jd, eo);
if (!ast_err) { if (!ast_err) {
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP, res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP,
.x = lst - slew_pars.x + eo, // HA = LST - RA_APP + EO .x = lst - slew_pars.x + eo, // HA = LST - RA_APP + EO
.y = slew_pars.y, .y = slew_pars.y,
.stop = slew_pars.stop}, .stop = slew_pars.stop});
telemetry);
} }
} }
} }
} else if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP) { // apparent } else if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP) { // apparent
if constexpr (mccIsEquatorialMount(PEC_T::mountType)) { // compute encoder coordinates if constexpr (mccIsEquatorialMount(pec_t::mountType)) { // compute encoder coordinates
coord_t eps = 1.0 / 3600.0 * std::numbers::pi / 180.0; coord_t eps = 1.0 / 3600.0 * std::numbers::pi / 180.0;
typename PEC_T::pec_result_t pec_res; typename pec_t::pec_result_t pec_res;
auto err = p_pec->reverseCompute(slew_pars.x, slew_pars.y, pec_res, eps, 10); pec_err = pec->reverseCompute(slew_pars.x, slew_pars.y, pec_res, eps, 10);
if (!err) { if (!pec_err) {
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_XY, res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_XY,
.x = slew_pars.x - pec_res.dx, .x = slew_pars.x - pec_res.dx,
.y = slew_pars.y - pec_res.dy, .y = slew_pars.y - pec_res.dy,
.stop = slew_pars.stop}, .stop = slew_pars.stop});
telemetry);
} }
} else if constexpr (mccIsAltAzMount(PEC_T::mountType)) { } else if constexpr (mccIsAltAzMount(pec_t::mountType)) {
coord_t az, alt; coord_t az, alt;
ast_err = p_astrom_engine->hadec2azalt(slew_pars.x, slew_pars.y, az, alt); ast_err = astrom_engine->hadec2azalt(slew_pars.x, slew_pars.y, az, alt);
if (!ast_err) { if (!ast_err) {
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_AZALT, res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_AZALT,
.x = az, .x = az,
.y = alt, .y = alt,
.stop = slew_pars.stop}, .stop = slew_pars.stop});
telemetry);
} }
} else { } else {
static_assert(false, "UNKNOWN MOUNT TYPE!"); static_assert(false, "UNKNOWN MOUNT TYPE!");
} }
} else if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_AZALT) { } else if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_AZALT) {
if constexpr (mccIsEquatorialMount(PEC_T::mountType)) { if constexpr (mccIsEquatorialMount(pec_t::mountType)) {
coord_t ha, dec; coord_t ha, dec;
ast_err = p_astrom_engine->azalt2hadec(slew_pars.x, slew_pars.y, ha, dec); ast_err = astrom_engine->azalt2hadec(slew_pars.x, slew_pars.y, ha, dec);
if (!ast_err) { if (!ast_err) {
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP, res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP,
.x = ha, .x = ha,
.y = dec, .y = dec,
.stop = slew_pars.stop}, .stop = slew_pars.stop});
telemetry);
} }
} else if constexpr (mccIsAltAzMount(PEC_T::mountType)) { // compute encoder coordinates } else if constexpr (mccIsAltAzMount(pec_t::mountType)) { // compute encoder coordinates
coord_t eps = 1.0 / 3600.0 * std::numbers::pi / 180.0; coord_t eps = 1.0 / 3600.0 * std::numbers::pi / 180.0;
typename PEC_T::pec_result_t pec_res; typename pec_t::pec_result_t pec_res;
auto err = p_pec->reverseCompute(slew_pars.x, slew_pars.y, pec_res, eps, 10); pec_err = pec->reverseCompute(slew_pars.x, slew_pars.y, pec_res, eps, 10);
if (!err) { if (!pec_err) {
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_XY, res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_XY,
.x = slew_pars.x - pec_res.dx, .x = slew_pars.x - pec_res.dx,
.y = slew_pars.y - pec_res.dy, .y = slew_pars.y - pec_res.dy,
.stop = slew_pars.stop}, .stop = slew_pars.stop});
telemetry);
} }
} else { } else {
@ -178,32 +191,57 @@ public:
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_AZALT, res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_AZALT,
.x = slew_pars.x, .x = slew_pars.x,
.y = std::numbers::pi / 2.0 - slew_pars.y, .y = std::numbers::pi / 2.0 - slew_pars.y,
.stop = slew_pars.stop}, .stop = slew_pars.stop});
telemetry);
} }
if (res_err) { if (res_err) {
return res_err; return res_err;
} }
if (!ast_err) { if (pec_err) {
auto err = p_hardware->setPos(std::move(ax_pos)); // ???????????
return std::error_code(); // !!!!!!!!!!!!!!!
}
while (true) { if (!ast_err) {
typename telemetry_t::error_t t_err;
typename telemetry_t::mount_telemetry_data_t t_data;
// move mount (it is assumed this is asynchronous operation!!!)
typename hardware_t::error_t err = hardware->setPos(std::move(ax_pos));
std::array<bool, Nzones> pz_result;
if (!err) {
//
// what is the condition for mount reaches given position?!!
//
while (true) {
t_err = telemetry.data(t_data);
if (t_err) {
// ?????????!!!!!!!!!!
}
// check prohibited zones
if (check_zones(pz_result, std::make_index_sequence<Nzones>{})) {
// stop mount ?!!!!!!!!!!!!!!!!!!!!!
// return in-zone-error-code
}
}
} }
} }
}; };
} }
error_t slew(const slew_params_t& pars, TELEMETRY_T& telemetry) error_t slew(const slew_params_t& pars)
{ {
error_t res_err = _slewFunc(pars, telemetry); error_t res_err = _slewFunc(pars);
return res_err; return res_err;
} }
protected: protected:
std::function<error_t(const slew_params_t&, TELEMETRY_T&)> _slewFunc{}; std::function<error_t(const slew_params_t&)> _slewFunc{};
}; };

View File

@ -10,6 +10,7 @@
struct tel_data_t { struct tel_data_t {
typedef mcc::MccAngle coord_t; typedef mcc::MccAngle coord_t;
typedef std::chrono::system_clock::time_point time_point_t;
coord_t mntRA, mntDEC, mntHA; coord_t mntRA, mntDEC, mntHA;
coord_t mntAZ, mntALT; coord_t mntAZ, mntALT;
@ -187,7 +188,7 @@ int main(int argc, char* argv[])
auto res = erfa.icrs2obs(ra1, dec1, jd, ra_o, dec_o, ha1, az1, alt1, eor); auto res = erfa.icrs2obs(ra1, dec1, jd, ra_o, dec_o, ha1, az1, alt1, eor);
std::cout << "eq of origins (from icrs2obs) = " << eor.sexagesimal(true) << "\n"; std::cout << "eq of origins (from icrs2obs) = " << eor.sexagesimal(true) << "\n";
std::cout << "ret code (icrs2obs) = " << erfa.errorString(res) << "\n"; std::cout << "ret code (icrs2obs) = " << res.message() << "\n";
std::cout << "alt = " << alt1.sexagesimal() << "\n"; std::cout << "alt = " << alt1.sexagesimal() << "\n";
std::cout << "az = " << az1.sexagesimal() << "\n"; std::cout << "az = " << az1.sexagesimal() << "\n";
@ -232,7 +233,7 @@ int main(int argc, char* argv[])
ra1 = "17:00:00"_hms; ra1 = "17:00:00"_hms;
dec1 = "40:25:10.43"_dms; dec1 = "40:25:10.43"_dms;
res = erfa.icrs2obs(ra1, dec1, jd, ra_o, dec_o, ha1, az1, alt1, eor); res = erfa.icrs2obs(ra1, dec1, jd, ra_o, dec_o, ha1, az1, alt1, eor);
std::cout << "ret code (icrs2obs) = " << erfa.errorString(res) << "\n"; std::cout << "ret code (icrs2obs) = " << res.message() << "\n";
std::cout << "alt = " << alt1.sexagesimal() << "\n"; std::cout << "alt = " << alt1.sexagesimal() << "\n";
std::cout << "az = " << az1.sexagesimal() << "\n"; std::cout << "az = " << az1.sexagesimal() << "\n";
@ -265,5 +266,10 @@ int main(int argc, char* argv[])
std::cout << "(MAXALT) time from zone: " << std::chrono::hh_mm_ss(tm) << " (" << now1 << ")\n"; std::cout << "(MAXALT) time from zone: " << std::chrono::hh_mm_ss(tm) << " (" << now1 << ")\n";
} }
ra_o = 1.0;
dec_o = 2.0;
ha1 = ra_o * dec_o;
std::cout << "mult: " << ha1.degrees() << "\n";
return ecode; return ecode;
} }