504 lines
18 KiB
C++
504 lines
18 KiB
C++
#pragma once
|
|
|
|
/* MOUNT CONTROL COMPONENTS LIBRARY */
|
|
|
|
|
|
|
|
/* VARIUOS ASTROMETRIC TRANSFORMATIONS FOR TELEMETRY */
|
|
|
|
|
|
#include "mcc_mount_concepts.h"
|
|
|
|
namespace mcc
|
|
{
|
|
|
|
enum class MccMountTelemetryAstromTransformErrorCode : int {
|
|
ERROR_OK = 0,
|
|
ERROR_COORD_PAIR_KIND,
|
|
ERROR_ASTROMETRY_COMP,
|
|
ERROR_PEC
|
|
};
|
|
|
|
|
|
/* error category definition */
|
|
|
|
// error category
|
|
struct MccMountTelemetryAstromTransformCategory : public std::error_category {
|
|
MccMountTelemetryAstromTransformCategory() : std::error_category() {}
|
|
|
|
const char* name() const noexcept { return "ADC_GENERIC_DEVICE"; }
|
|
|
|
std::string message(int ec) const
|
|
{
|
|
MccMountTelemetryAstromTransformErrorCode err = static_cast<MccMountTelemetryAstromTransformErrorCode>(ec);
|
|
|
|
switch (err) {
|
|
case MccMountTelemetryAstromTransformErrorCode::ERROR_OK:
|
|
return "OK";
|
|
case MccMountTelemetryAstromTransformErrorCode::ERROR_COORD_PAIR_KIND:
|
|
return "unsupported coordinate pair kind";
|
|
case MccMountTelemetryAstromTransformErrorCode::ERROR_ASTROMETRY_COMP:
|
|
return "astrometry engine error";
|
|
case MccMountTelemetryAstromTransformErrorCode::ERROR_PEC:
|
|
return "PEC computation error";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
static const MccMountTelemetryAstromTransformCategory& get()
|
|
{
|
|
static const MccMountTelemetryAstromTransformCategory constInst;
|
|
return constInst;
|
|
}
|
|
};
|
|
|
|
|
|
inline std::error_code make_error_code(MccMountTelemetryAstromTransformErrorCode ec)
|
|
{
|
|
return std::error_code(static_cast<int>(ec), MccMountTelemetryAstromTransformCategory::get());
|
|
}
|
|
|
|
|
|
} // namespace mcc
|
|
|
|
namespace std
|
|
{
|
|
|
|
template <>
|
|
class is_error_code_enum<mcc::MccMountTelemetryAstromTransformErrorCode> : public true_type
|
|
{
|
|
};
|
|
|
|
} // namespace std
|
|
|
|
|
|
|
|
namespace mcc
|
|
{
|
|
|
|
template <traits::mcc_astrom_engine_c ASTROM_ENGINE_T, traits::mcc_mount_pec_c PEC_T>
|
|
class MccMountTelemetryAstromTransform
|
|
{
|
|
inline static typename ASTROM_ENGINE_T::coord_t dummyCoord{};
|
|
|
|
public:
|
|
typedef ASTROM_ENGINE_T astrom_engine_t;
|
|
typedef PEC_T pec_t;
|
|
|
|
// check for coordinate types consistency
|
|
static_assert(
|
|
requires(typename astrom_engine_t::coord_t ac, typename pec_t::coord_t pc) {
|
|
// to compute PEC-corrected values
|
|
{ ac += pc };
|
|
{ ac = ac + pc };
|
|
{ ac = ac - pc };
|
|
},
|
|
"ASTROMETRY ENGINE AND PEC COORDINATES TYPE MUST BE CONSISTENT!");
|
|
|
|
// deduce mount type
|
|
static constexpr bool equatorialMount = mccIsEquatorialMount(PEC_T::mountType);
|
|
static constexpr bool altAzMount = mccIsAltAzMount(PEC_T::mountType);
|
|
|
|
typedef typename astrom_engine_t::coord_t coord_t;
|
|
|
|
typedef std::error_code error_t;
|
|
|
|
MccMountTelemetryAstromTransform(astrom_engine_t* astrom_engine, pec_t* pec)
|
|
: _astromEngine(astrom_engine), _pec(pec)
|
|
{
|
|
}
|
|
|
|
|
|
MccMountTelemetryAstromTransform(MccMountTelemetryAstromTransform&& other)
|
|
: _pec(other._pec), _astromEngine(other._astromEngine)
|
|
{
|
|
}
|
|
|
|
MccMountTelemetryAstromTransform& operator=(MccMountTelemetryAstromTransform&& other)
|
|
{
|
|
if (this != &other) {
|
|
_pec = other._pec;
|
|
_astromEngine = other._astromEngine;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
MccMountTelemetryAstromTransform(const MccMountTelemetryAstromTransform& other)
|
|
: _pec(other._pec), _astromEngine(other._astromEngine)
|
|
{
|
|
}
|
|
|
|
MccMountTelemetryAstromTransform& operator=(const MccMountTelemetryAstromTransform& other)
|
|
{
|
|
if (this != &other) {
|
|
_pec = other._pec;
|
|
_astromEngine = other._astromEngine;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
virtual ~MccMountTelemetryAstromTransform() = default;
|
|
|
|
template <traits::mcc_celestial_point_c CT>
|
|
error_t toApparent(CT coord,
|
|
astrom_engine_t::time_point_t time_point,
|
|
coord_t& X_app,
|
|
coord_t& Y_app,
|
|
coord_t& XX_app = dummyCoord)
|
|
{
|
|
typedef typename astrom_engine_t::jd_t jd_t;
|
|
jd_t jd;
|
|
|
|
typedef typename astrom_engine_t::eo_t eo_t;
|
|
eo_t eo;
|
|
|
|
typedef typename astrom_engine_t::sideral_time_t sideral_time_t;
|
|
sideral_time_t lst;
|
|
|
|
typename astrom_engine_t::error_t ast_err;
|
|
typename pec_t::error_t pec_err;
|
|
|
|
auto get_jd_lst_eo = [&time_point, this](jd_t& jd, sideral_time_t& lst, eo_t& eo) {
|
|
auto ast_err = _astromEngine->greg2jul(time_point, jd);
|
|
if (!ast_err) {
|
|
ast_err = _astromEngine->apparentSiderTime(jd, lst, true);
|
|
|
|
if (!ast_err) {
|
|
ast_err = _astromEngine->eqOrigins(jd, eo);
|
|
}
|
|
}
|
|
|
|
return ast_err;
|
|
};
|
|
|
|
if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_XY) { // from encoder's
|
|
typename pec_t::pec_result_t pec_res;
|
|
pec_err = _pec->compute(coord.x, coord.y, pec_res);
|
|
if (!pec_err) {
|
|
X_app = coord.x + pec_res.dx;
|
|
Y_app = coord.y + pec_res.dy;
|
|
}
|
|
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_RADEC_APP) { // from app RA-DEC
|
|
|
|
coord_t HA;
|
|
|
|
// logDebug("Input slew coordinates are apparent RA-DEC: convert it to apparent HA-DEC ...");
|
|
|
|
ast_err = get_jd_lst_eo(jd, lst, eo);
|
|
|
|
if (!ast_err) {
|
|
HA = lst - coord.x + eo; // HA = LST - RA_APP + EO
|
|
|
|
if constexpr (equatorialMount) { // compute HA (as XX_app)
|
|
X_app = coord.x;
|
|
Y_app = coord.y;
|
|
XX_app = HA;
|
|
} else if constexpr (altAzMount) {
|
|
ast_err = _astromEngine->hadec2azalt(HA, coord.y, X_app, Y_app);
|
|
} else {
|
|
static_assert(false, "UNSUPPORTED MOUNT TYPE!");
|
|
}
|
|
}
|
|
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP) { // from app HA-DEC
|
|
ast_err = get_jd_lst_eo(jd, lst, eo);
|
|
|
|
if (!ast_err) {
|
|
if constexpr (equatorialMount) { // compute CIO RA (as XX_app)
|
|
X_app = coord.x;
|
|
Y_app = coord.y;
|
|
XX_app = lst - coord.x + eo;
|
|
} else if constexpr (altAzMount) {
|
|
ast_err = _astromEngine->hadec2azalt(coord.x, coord.y, X_app, Y_app);
|
|
} else {
|
|
static_assert(false, "UNSUPPORTED MOUNT TYPE!");
|
|
}
|
|
}
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT) { // from app AZ-ALT
|
|
if constexpr (equatorialMount) {
|
|
ast_err = _astromEngine->azalt2hadec(coord.x, coord.y, X_app, Y_app); // compute HA-DEC
|
|
if (!ast_err) { // compute CIO RA (as XX_app)
|
|
coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP;
|
|
coord.x = X_app;
|
|
coord.y = Y_app;
|
|
ast_err = toApparent(std::move(coord), std::move(time_point), X_app, Y_app, XX_app);
|
|
}
|
|
} else if (altAzMount) {
|
|
X_app = coord.x;
|
|
Y_app = coord.y;
|
|
} else {
|
|
static_assert(false, "UNSUPPORTED MOUNT TYPE!");
|
|
}
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZZD) { // from app AZ-ZD
|
|
coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT;
|
|
coord.y = std::numbers::pi / 2.0 - coord.y;
|
|
ast_err = toApparent(std::move(coord), std::move(time_point), X_app, Y_app, XX_app);
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // from ICRS RA-DEC
|
|
coord_t az, alt;
|
|
eo_t eo;
|
|
|
|
// for equatorial mount:
|
|
// X_app = RA_app, Y_app = DEC_app, XX_app = HA_app
|
|
// for alt-azimuthal mount:
|
|
// X_app = AZ, Y_app = ALT
|
|
|
|
ast_err = _astromEngine->greg2jul(time_point, jd);
|
|
if (!ast_err) {
|
|
ast_err = _astromEngine->icrs2obs(coord.x, coord.y, jd, X_app, Y_app, XX_app, az, alt, eo);
|
|
|
|
if (!ast_err) {
|
|
if constexpr (equatorialMount) {
|
|
// nothing to do
|
|
} else if (altAzMount) {
|
|
X_app = az;
|
|
Y_app = alt;
|
|
} else {
|
|
static_assert(false, "UNSUPPORTED MOUNT TYPE!");
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
return MccMountTelemetryAstromTransformErrorCode::ERROR_COORD_PAIR_KIND;
|
|
}
|
|
|
|
if (pec_err) {
|
|
if constexpr (std::same_as<decltype(pec_err), error_t>) {
|
|
return pec_err;
|
|
} else {
|
|
return MccMountTelemetryAstromTransformErrorCode::ERROR_PEC;
|
|
}
|
|
}
|
|
|
|
if (ast_err) {
|
|
if constexpr (std::same_as<decltype(ast_err), error_t>) {
|
|
return ast_err;
|
|
} else {
|
|
return MccMountTelemetryAstromTransformErrorCode::ERROR_ASTROMETRY_COMP;
|
|
}
|
|
}
|
|
|
|
return MccMountTelemetryAstromTransformErrorCode::ERROR_OK;
|
|
}
|
|
|
|
|
|
template <traits::mcc_celestial_point_c CT>
|
|
error_t toICRS(CT coord, astrom_engine_t::time_point_t time_point, coord_t& RA, coord_t& DEC)
|
|
{
|
|
typename astrom_engine_t::error_t ast_err;
|
|
typename pec_t::error_t pec_err;
|
|
|
|
if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_XY) { // from encoder's
|
|
typename pec_t::pec_result_t pec_res;
|
|
pec_err = _pec->compute(coord.x, coord.y, pec_res);
|
|
if (!pec_err) {
|
|
coord.x += pec_res.dx;
|
|
coord.y += pec_res.dy;
|
|
|
|
if constexpr (equatorialMount) {
|
|
coord.coordPairKind = MccCoordPairKind::COORDS_KIND_HADEC_APP;
|
|
} else if constexpr (altAzMount) {
|
|
coord.coordPairKind = MccCoordPairKind::COORDS_KIND_AZALT;
|
|
} else {
|
|
static_assert(false, "UNSUPPORTED MOUNT TYPE!");
|
|
}
|
|
|
|
ast_err = toICRS(std::move(coord), std::move(time_point), RA, DEC);
|
|
}
|
|
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_RADEC_APP) { // from app RA-DEC
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP) { // from app HA-DEC
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT) { // from app AZ-ALT
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZZD) { // from app AZ-ZD
|
|
coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT;
|
|
coord.y = std::numbers::pi / 2.0 - coord.y;
|
|
ast_err = toICRS(std::move(coord), std::move(time_point), RA, DEC);
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // from ICRS RA-DEC
|
|
RA = coord.x;
|
|
DEC = coord.y;
|
|
|
|
return MccMountTelemetryAstromTransformErrorCode::ERROR_OK;
|
|
} else {
|
|
return MccMountTelemetryAstromTransformErrorCode::ERROR_COORD_PAIR_KIND;
|
|
}
|
|
|
|
if (coord.coordPairKind != MccCoordPairKind::COORDS_KIND_RADEC_ICRS) {
|
|
typename astrom_engine_t::jd_t jd;
|
|
|
|
ast_err = _astromEngine->greg2jul(astrom_engine_t::timePointNow(), jd);
|
|
if (!ast_err) {
|
|
ast_err = _astromEngine->obs2icrs(coord.coordPairKind, coord.x, coord.y, jd, RA, DEC);
|
|
}
|
|
}
|
|
|
|
if (pec_err) {
|
|
if constexpr (std::same_as<decltype(pec_err), error_t>) {
|
|
return pec_err;
|
|
} else {
|
|
return MccMountTelemetryAstromTransformErrorCode::ERROR_PEC;
|
|
}
|
|
}
|
|
|
|
if (ast_err) {
|
|
if constexpr (std::same_as<decltype(ast_err), error_t>) {
|
|
return ast_err;
|
|
} else {
|
|
return MccMountTelemetryAstromTransformErrorCode::ERROR_ASTROMETRY_COMP;
|
|
}
|
|
}
|
|
|
|
return MccMountTelemetryAstromTransformErrorCode::ERROR_OK;
|
|
}
|
|
|
|
|
|
template <traits::mcc_celestial_point_c CT>
|
|
error_t toHardware(CT coord, astrom_engine_t::time_point_t time_point, coord_t& X, coord_t& Y)
|
|
{
|
|
typedef typename astrom_engine_t::jd_t jd_t;
|
|
jd_t jd;
|
|
|
|
typedef typename astrom_engine_t::eo_t eo_t;
|
|
eo_t eo;
|
|
|
|
typedef typename astrom_engine_t::sideral_time_t sideral_time_t;
|
|
sideral_time_t lst;
|
|
|
|
auto get_jd_lst_eo = [&time_point, this](jd_t& jd, sideral_time_t& lst, eo_t& eo) {
|
|
auto ast_err = _astromEngine->greg2jul(time_point, jd);
|
|
if (!ast_err) {
|
|
ast_err = _astromEngine->apparentSiderTime(jd, lst, true);
|
|
|
|
if (!ast_err) {
|
|
ast_err = _astromEngine->eqOrigins(jd, eo);
|
|
}
|
|
}
|
|
|
|
return ast_err;
|
|
};
|
|
|
|
typename astrom_engine_t::error_t ast_err;
|
|
typename pec_t::error_t pec_err;
|
|
|
|
if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_XY) { // from encoder's
|
|
X = coord.x;
|
|
Y = coord.y;
|
|
|
|
return MccMountTelemetryAstromTransformErrorCode::ERROR_OK;
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_RADEC_APP) { // from app RA-DEC
|
|
ast_err = get_jd_lst_eo(jd, lst, eo);
|
|
|
|
if (!ast_err) {
|
|
coord.x = lst - coord.x + eo; // HA
|
|
coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP;
|
|
|
|
ast_err = toHardware(std::move(coord), std::move(time_point), X, Y);
|
|
}
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP) { // from app HA-DEC
|
|
if constexpr (equatorialMount) {
|
|
typename pec_t::pec_result_t pec_res;
|
|
|
|
pec_err = _pec->compute(coord.x, coord.y, pec_res);
|
|
if (!pec_err) {
|
|
X = coord.x - pec_res.dx;
|
|
Y = coord.y - pec_res.dy;
|
|
|
|
return MccMountTelemetryAstromTransformErrorCode::ERROR_OK;
|
|
}
|
|
} else if constexpr (altAzMount) {
|
|
coord_t az, alt;
|
|
ast_err = _astromEngine->hadec2azalt(coord.x, coord.y, az, alt);
|
|
if (!ast_err) {
|
|
coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT;
|
|
coord.x = az;
|
|
coord.y = alt;
|
|
|
|
ast_err = toHardware(std::move(coord), std::move(time_point), X, Y);
|
|
}
|
|
} else {
|
|
static_assert(false, "UNSUPPORTED MOUNT TYPE!");
|
|
}
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT) { // from app AZ-ALT
|
|
if constexpr (equatorialMount) {
|
|
coord_t ha, dec;
|
|
ast_err = _astromEngine->azalt2hadec(coord.x, coord.y, ha, dec);
|
|
if (!ast_err) {
|
|
coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP;
|
|
coord.x = ha;
|
|
coord.y = dec;
|
|
|
|
ast_err = toHardware(std::move(coord), std::move(time_point), X, Y);
|
|
}
|
|
} else if constexpr (altAzMount) {
|
|
typename pec_t::pec_result_t pec_res;
|
|
|
|
pec_err = _pec->compute(coord.x, coord.y, pec_res);
|
|
if (!pec_err) {
|
|
X = coord.x - pec_res.dx;
|
|
Y = coord.y - pec_res.dy;
|
|
|
|
return {};
|
|
}
|
|
} else {
|
|
static_assert(false, "UNSUPPORTED MOUNT TYPE!");
|
|
}
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZZD) { // from app AZ-ZD
|
|
coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT;
|
|
coord.y = std::numbers::pi / 2.0 - coord.y;
|
|
ast_err = toICRS(std::move(coord), std::move(time_point), X, Y);
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // from ICRS RA-DEC
|
|
coord_t ra, dec, ha, az, alt;
|
|
eo_t eo;
|
|
|
|
ast_err = _astromEngine->greg2jul(time_point, jd);
|
|
if (!ast_err) {
|
|
ast_err = icrs2obs(coord.x, coord.y, jd, ra, dec, ha, az, alt, eo);
|
|
if (!ast_err) {
|
|
if constexpr (equatorialMount) {
|
|
coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP;
|
|
coord.x = ha;
|
|
coord.y = dec;
|
|
} else if constexpr (altAzMount) {
|
|
coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT;
|
|
coord.x = az;
|
|
coord.y = alt;
|
|
} else {
|
|
static_assert(false, "UNSUPPORTED MOUNT TYPE!");
|
|
}
|
|
|
|
ast_err = toHardware(std::move(coord), std::move(time_point), X, Y);
|
|
}
|
|
}
|
|
} else {
|
|
return MccMountTelemetryAstromTransformErrorCode::ERROR_COORD_PAIR_KIND;
|
|
}
|
|
|
|
if (pec_err) {
|
|
if constexpr (std::same_as<decltype(pec_err), error_t>) {
|
|
return pec_err;
|
|
} else {
|
|
return MccMountTelemetryAstromTransformErrorCode::ERROR_PEC;
|
|
}
|
|
}
|
|
|
|
if (ast_err) {
|
|
if constexpr (std::same_as<decltype(ast_err), error_t>) {
|
|
return ast_err;
|
|
} else {
|
|
return MccMountTelemetryAstromTransformErrorCode::ERROR_ASTROMETRY_COMP;
|
|
}
|
|
}
|
|
|
|
return MccMountTelemetryAstromTransformErrorCode::ERROR_OK;
|
|
}
|
|
|
|
protected:
|
|
astrom_engine_t* _astromEngine;
|
|
pec_t* _pec;
|
|
};
|
|
|
|
|
|
} // namespace mcc
|