...
This commit is contained in:
parent
d663f6b54a
commit
6646ef6aca
@ -80,7 +80,9 @@ public:
|
|||||||
typedef MccAngle coord_t;
|
typedef MccAngle coord_t;
|
||||||
|
|
||||||
typedef MccAngle sideral_time_t;
|
typedef MccAngle sideral_time_t;
|
||||||
|
// typedef juldate_t terr_time_t;
|
||||||
typedef MccAngle pa_t;
|
typedef MccAngle pa_t;
|
||||||
|
typedef MccAngle eo_t;
|
||||||
|
|
||||||
struct refract_result_t {
|
struct refract_result_t {
|
||||||
double refa, refb;
|
double refa, refb;
|
||||||
@ -156,34 +158,67 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
engine_err_t apparentSiderTime(juldate_t juldate, sideral_time_t& gst, bool islocal = false)
|
engine_err_t terrestialTime(juldate_t juldate, juldate_t& tt)
|
||||||
{
|
{
|
||||||
std::lock_guard lock{_stateMutex};
|
std::lock_guard lock{_stateMutex};
|
||||||
|
|
||||||
using real_days_t = std::chrono::duration<double, std::ratio<86400>>;
|
using real_days_t = std::chrono::duration<double, std::ratio<86400>>;
|
||||||
|
|
||||||
double ut1 = juldate.mjd, tt = juldate.mjd;
|
|
||||||
|
|
||||||
auto dut1 = _currentState._bulletinA.DUT1(juldate.mjd);
|
|
||||||
|
|
||||||
if (dut1.has_value()) {
|
|
||||||
ut1 += std::chrono::duration_cast<real_days_t>(dut1.value()).count();
|
|
||||||
} else { // out of range
|
|
||||||
return ERROR_BULLETINA_OUT_OF_RANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tai_utc = _currentState._leapSeconds[juldate.mjd];
|
auto tai_utc = _currentState._leapSeconds[juldate.mjd];
|
||||||
if (tai_utc.has_value()) {
|
if (tai_utc.has_value()) {
|
||||||
tt += 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 ERROR_LEAPSECONDS_OUT_OF_RANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto tt_tai = _currentState._bulletinA.TT_TAI();
|
auto tt_tai = _currentState._bulletinA.TT_TAI();
|
||||||
tt += std::chrono::duration_cast<real_days_t>(tt_tai).count();
|
tt.mjd = juldate.mjd + std::chrono::duration_cast<real_days_t>(tt_tai).count();
|
||||||
|
|
||||||
gst = eraGst06a(juldate.MJD0, ut1, juldate.MJD0, tt);
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
engine_err_t apparentSiderTime(juldate_t juldate, sideral_time_t& gst, bool islocal = false)
|
||||||
|
{
|
||||||
|
// std::lock_guard lock{_stateMutex};
|
||||||
|
|
||||||
|
using real_days_t = std::chrono::duration<double, std::ratio<86400>>;
|
||||||
|
|
||||||
|
double ut1 = juldate.mjd;
|
||||||
|
// double tt = juldate.mjd;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard lock{_stateMutex};
|
||||||
|
|
||||||
|
auto dut1 = _currentState._bulletinA.DUT1(juldate.mjd);
|
||||||
|
|
||||||
|
if (dut1.has_value()) {
|
||||||
|
ut1 += std::chrono::duration_cast<real_days_t>(dut1.value()).count();
|
||||||
|
} else { // out of range
|
||||||
|
return ERROR_BULLETINA_OUT_OF_RANGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// auto tai_utc = _currentState._leapSeconds[juldate.mjd];
|
||||||
|
// if (tai_utc.has_value()) {
|
||||||
|
// tt += std::chrono::duration_cast<real_days_t>(tai_utc.value()).count();
|
||||||
|
// } else {
|
||||||
|
// return ERROR_LEAPSECONDS_OUT_OF_RANGE;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// auto tt_tai = _currentState._bulletinA.TT_TAI();
|
||||||
|
// tt += std::chrono::duration_cast<real_days_t>(tt_tai).count();
|
||||||
|
// gst = eraGst06a(juldate.MJD0, ut1, juldate.MJD0, tt);
|
||||||
|
|
||||||
|
juldate_t tt;
|
||||||
|
auto err = terrestialTime(juldate, tt);
|
||||||
|
if (err != ERROR_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst = eraGst06a(juldate.MJD0, ut1, juldate.MJD0, tt.mjd);
|
||||||
if (islocal) {
|
if (islocal) {
|
||||||
gst += _currentState.lon;
|
gst += _currentState.lon;
|
||||||
}
|
}
|
||||||
@ -192,6 +227,20 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
engine_err_t eqOrigins(juldate_t juldate, eo_t& eo)
|
||||||
|
{
|
||||||
|
juldate_t tt;
|
||||||
|
|
||||||
|
auto err = terrestialTime(juldate, tt);
|
||||||
|
if (err != ERROR_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
eo = eraEo06a(tt.MJD0, tt.mjd);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* atmospheric refraction-related methods */
|
/* atmospheric refraction-related methods */
|
||||||
|
|
||||||
engine_err_t refraction(refract_result_t& refr)
|
engine_err_t refraction(refract_result_t& refr)
|
||||||
@ -205,6 +254,18 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
engine_err_t refractCorrection(const coord_t& alt, const refract_result_t& ref_params, coord_t& corr)
|
||||||
|
{
|
||||||
|
if (alt <= 0.0) {
|
||||||
|
corr = 35.4 / 60.0 * std::numbers::pi / 180.0; // 35.4 arcminutes
|
||||||
|
} else {
|
||||||
|
auto tanALT = std::tan(alt);
|
||||||
|
corr = ref_params.refa / tanALT + ref_params.refb / tanALT / tanALT / tanALT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* coordinates conversional methods */
|
/* coordinates conversional methods */
|
||||||
|
|
||||||
engine_err_t icrs2obs(coord_t ra,
|
engine_err_t icrs2obs(coord_t ra,
|
||||||
|
|||||||
@ -83,6 +83,10 @@ concept mcc_astrom_engine_c = requires(T t, const T t_const) {
|
|||||||
std::declval<bool>())
|
std::declval<bool>())
|
||||||
} -> std::same_as<typename T::engine_err_t>;
|
} -> std::same_as<typename T::engine_err_t>;
|
||||||
|
|
||||||
|
// equation of origins
|
||||||
|
{
|
||||||
|
t.eqOrigins(std::declval<typename T::juldate_t>(), std::declval<typename T::eo_t&>())
|
||||||
|
} -> std::same_as<typename T::engine_err_t>;
|
||||||
|
|
||||||
/* atmospheric refraction-related methods */
|
/* atmospheric refraction-related methods */
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,36 @@ static constexpr std::string_view MccMountTypeStr = TYPE == MccMountType::GERMAN
|
|||||||
: TYPE == MccMountType::ALTAZ_TYPE ? "ALTAZ"
|
: TYPE == MccMountType::ALTAZ_TYPE ? "ALTAZ"
|
||||||
: "UNKNOWN";
|
: "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;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace mcc
|
} // namespace mcc
|
||||||
|
|
||||||
@ -99,108 +129,114 @@ concept mcc_astrom_engine_c = requires(T t, const T t_const) {
|
|||||||
|
|
||||||
/* atmospheric refraction-related methods */
|
/* atmospheric refraction-related methods */
|
||||||
|
|
||||||
|
// compute refraction-related quantities: refraction(refr_params)
|
||||||
{ t.refraction(std::declval<typename T::refract_result_t&>()) } -> std::same_as<typename T::engine_err_t>;
|
{ t.refraction(std::declval<typename T::refract_result_t&>()) } -> std::same_as<typename T::engine_err_t>;
|
||||||
|
|
||||||
|
// compute refraction correction for given altitude: refractCorrection(alt, refr_params, refr_corr)
|
||||||
|
{
|
||||||
|
t.refractCorrection(std::declval<typename T::coord_t>(), std::declval<typename T::refract_result_t>(),
|
||||||
|
std::declval<typename T::coord_t&>())
|
||||||
|
} -> std::same_as<typename T::engine_err_t>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* MOUNT AXES AND MOTORS HARDWARE GENERIC ABSTRACTION */
|
/* MOUNT AXES AND MOTORS HARDWARE GENERIC ABSTRACTION */
|
||||||
|
|
||||||
// encoder basic concept (e.g. mount axis encoder or motor shaft one)
|
// // encoder basic concept (e.g. mount axis encoder or motor shaft one)
|
||||||
template <typename T>
|
// template <typename T>
|
||||||
concept mcc_hw_encoder_c = requires(T t, const T t_const) {
|
// concept mcc_hw_encoder_c = requires(T t, const T t_const) {
|
||||||
typename T::error_t;
|
// requires mcc_error_c<typename T::error_t>;
|
||||||
|
|
||||||
typename T::time_point_t;
|
// typename T::time_point_t;
|
||||||
typename T::coord_t;
|
// typename T::coord_t;
|
||||||
typename T::speed_t;
|
// typename T::speed_t;
|
||||||
typename T::accel_t;
|
// typename T::accel_t;
|
||||||
|
|
||||||
requires requires(typename T::state_t st) {
|
// requires requires(typename T::state_t st) {
|
||||||
requires std::same_as<decltype(st.time), typename T::time_point_t>;
|
// requires std::same_as<decltype(st.time), typename T::time_point_t>;
|
||||||
requires std::same_as<decltype(st.pos), typename T::coord_t>;
|
// requires std::same_as<decltype(st.pos), typename T::coord_t>;
|
||||||
requires std::same_as<decltype(st.speed), typename T::speed_t>;
|
// requires std::same_as<decltype(st.speed), typename T::speed_t>;
|
||||||
requires std::same_as<decltype(st.accel), typename T::accel_t>;
|
// requires std::same_as<decltype(st.accel), typename T::accel_t>;
|
||||||
};
|
// };
|
||||||
|
|
||||||
{ t_const.errorString(std::declval<typename T::error_t>()) } -> mcc_formattable;
|
// { t_const.errorString(std::declval<typename T::error_t>()) } -> mcc_formattable;
|
||||||
|
|
||||||
{ t_const.id() } -> mcc_formattable;
|
// { t_const.id() } -> mcc_formattable;
|
||||||
|
|
||||||
{ t.getState(std::declval<typename T::state_t&>()) } -> std::same_as<typename T::error_t>;
|
// { t.getState(std::declval<typename T::state_t&>()) } -> std::same_as<typename T::error_t>;
|
||||||
};
|
// };
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
// template <typename T>
|
||||||
concept mcc_hw_motor_c = requires(T t, const T t_const) {
|
// concept mcc_hw_motor_c = requires(T t, const T t_const) {
|
||||||
typename T::error_t;
|
// requires mcc_error_c<typename T::error_t>;
|
||||||
|
|
||||||
typename T::coord_t;
|
// typename T::coord_t;
|
||||||
typename T::speed_t;
|
// typename T::speed_t;
|
||||||
typename T::accel_t;
|
// typename T::accel_t;
|
||||||
|
|
||||||
requires requires(typename T::pos_t st) {
|
// requires requires(typename T::pos_t st) {
|
||||||
requires std::same_as<decltype(st.pos), typename T::coord_t>;
|
// requires std::same_as<decltype(st.pos), typename T::coord_t>;
|
||||||
requires std::same_as<decltype(st.speed), typename T::speed_t>; // means maximal allowed speed
|
// requires std::same_as<decltype(st.speed), typename T::speed_t>; // means maximal allowed speed
|
||||||
requires std::same_as<decltype(st.accel), typename T::accel_t>; // means a maximal allowed acceleration (jerk)
|
// requires std::same_as<decltype(st.accel), typename T::accel_t>; // means a maximal allowed acceleration
|
||||||
};
|
// (jerk)
|
||||||
|
// };
|
||||||
|
|
||||||
|
|
||||||
{ t_const.errorString(std::declval<typename T::error_t>()) } -> mcc_formattable;
|
// { t_const.errorString(std::declval<typename T::error_t>()) } -> mcc_formattable;
|
||||||
|
|
||||||
{ t_const.id() } -> mcc_formattable;
|
// { t_const.id() } -> mcc_formattable;
|
||||||
|
|
||||||
{ t.toPos(std::declval<typename T::pos_t>()) } -> std::same_as<typename T::error_t>;
|
// { t.toPos(std::declval<typename T::pos_t>()) } -> std::same_as<typename T::error_t>;
|
||||||
|
|
||||||
{ t.stop() } -> std::same_as<typename T::error_t>;
|
// { t.stop() } -> std::same_as<typename T::error_t>;
|
||||||
};
|
// };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace details
|
// namespace details
|
||||||
{
|
// {
|
||||||
template <typename T>
|
// template <typename T>
|
||||||
concept mcc_tuple_enc_ref_c = mcc_tuple_c<T> && requires(T t) {
|
// concept mcc_hw_enc_lvref_c = mcc_nonconst_lvref<T> && mcc_hw_encoder_c<std::remove_reference_t<T>>;
|
||||||
[]<template <typename...> typename TT, mcc_hw_encoder_c... Ts>(TT<Ts & ...>) {}(t);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
// template <typename T>
|
||||||
concept mcc_tuple_enc_cref_c = mcc_tuple_c<T> && requires(T t) {
|
// concept mcc_hw_motor_lvref_c = mcc_nonconst_lvref<T> && mcc_hw_motor_c<std::remove_reference_t<T>>;
|
||||||
[]<template <typename...> typename TT, mcc_hw_encoder_c... Ts>(TT<const Ts & ...>) {}(t);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
// } // namespace details
|
||||||
concept mcc_tuple_motor_ref_c = mcc_tuple_c<T> && requires(T t) {
|
|
||||||
[]<template <typename...> typename TT, mcc_hw_motor_c... Ts>(TT<Ts & ...>) {}(t);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept mcc_hw_enc_lref_c = std::is_lvalue_reference_v<T> && mcc_hw_encoder_c<std::remove_reference_t<T>>;
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept mcc_hw_motor_lref_c = std::is_lvalue_reference_v<T> && mcc_hw_motor_c<std::remove_reference_t<T>>;
|
|
||||||
|
|
||||||
} // namespace details
|
|
||||||
|
|
||||||
|
|
||||||
// a very generic mount hardware concept
|
// a very generic mount hardware concept
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept mcc_mount_hardware_c = requires(T t, const T t_const) {
|
concept mcc_mount_hardware_c = requires(T t, const T t_const) {
|
||||||
|
requires mcc_error_c<typename T::error_t>;
|
||||||
|
typename T::config_t;
|
||||||
|
|
||||||
|
typename T::time_point_t;
|
||||||
|
typename T::coord_t;
|
||||||
|
|
||||||
{ t_const.id() } -> mcc_formattable;
|
{ t_const.id() } -> mcc_formattable;
|
||||||
|
|
||||||
// access to encoders
|
// hardware configuration
|
||||||
{ t_const.encoders() } -> details::mcc_tuple_enc_cref_c;
|
{ t.setConfig(std::declval<typename T::config_t>()) } -> std::same_as<typename T::error_t>;
|
||||||
{ t.encoders() } -> details::mcc_tuple_enc_ref_c;
|
{ t.getConfig(std::declval<typename T::config_t&>()) } -> std::same_as<typename T::error_t>;
|
||||||
|
|
||||||
{ t.encoderPosX() } -> details::mcc_hw_enc_lref_c;
|
// at least contains time of measurement and coordinates for x,y axes
|
||||||
{ t.encoderPosY() } -> details::mcc_hw_enc_lref_c;
|
requires requires(typename T::axes_pos_t pos) {
|
||||||
|
requires std::same_as<decltype(pos.time_point), typename T::time_point_t>;
|
||||||
|
requires std::same_as<decltype(pos.x), typename T::coord_t>;
|
||||||
|
requires std::same_as<decltype(pos.y), typename T::coord_t>;
|
||||||
|
};
|
||||||
|
|
||||||
// access to motors
|
{ t.setPos(std::declval<typename T::axes_pos_t>()) } -> std::same_as<typename T::error_t>;
|
||||||
{ t.motors() } -> details::mcc_tuple_motor_ref_c;
|
{ t.getPos(std::declval<typename T::axes_pos_t&>()) } -> std::same_as<typename T::error_t>;
|
||||||
|
|
||||||
{ t.motorX() } -> details::mcc_hw_motor_lref_c;
|
// // access to encoders
|
||||||
{ t.motorY() } -> details::mcc_hw_motor_lref_c;
|
// { t.encoderPosX() } -> details::mcc_hw_enc_lvref_c;
|
||||||
|
// { t.encoderPosY() } -> details::mcc_hw_enc_lvref_c;
|
||||||
|
|
||||||
|
// // access to motors
|
||||||
|
// { t.motorX() } -> details::mcc_hw_motor_lvref_c;
|
||||||
|
// { t.motorY() } -> details::mcc_hw_motor_lvref_c;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -245,5 +281,4 @@ concept mcc_mount_config_c = requires(T t) {
|
|||||||
{ t.pec() } -> mcc_mount_pec_c;
|
{ t.pec() } -> mcc_mount_pec_c;
|
||||||
{ t.hardware() } -> mcc_mount_hardware_c;
|
{ t.hardware() } -> mcc_mount_hardware_c;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mcc::traits
|
} // namespace mcc::traits
|
||||||
|
|||||||
@ -9,27 +9,28 @@
|
|||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include "fitpack/fitpack.h"
|
#include "fitpack/fitpack.h"
|
||||||
|
#include "mcc_mount_concepts.h"
|
||||||
#include "mcc_mount_coord.h"
|
#include "mcc_mount_coord.h"
|
||||||
|
|
||||||
namespace mcc
|
namespace mcc
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
namespace traits
|
// namespace traits
|
||||||
{
|
// {
|
||||||
|
|
||||||
template <typename T, typename XT, typename YT>
|
// template <typename T, typename XT, typename YT>
|
||||||
concept mcc_mount_pec_c = requires(T t, const T t_const, XT x, YT y) {
|
// concept mcc_mount_pec_c = requires(T t, const T t_const, XT x, YT y) {
|
||||||
typename T::pec_data_t;
|
// typename T::pec_data_t;
|
||||||
typename T::pec_result_t;
|
// typename T::pec_result_t;
|
||||||
|
|
||||||
{ t.setData(std::declval<typename T::pec_data_t>()) };
|
// { t.setData(std::declval<typename T::pec_data_t>()) };
|
||||||
{ t_const.getData() } -> std::same_as<typename T::pec_data_t>;
|
// { t_const.getData() } -> std::same_as<typename T::pec_data_t>;
|
||||||
|
|
||||||
{ t.compute(std::declval<const XT&>(), std::declval<const YT&>()) } -> std::same_as<typename T::pec_result_t>;
|
// { t.compute(std::declval<const XT&>(), std::declval<const YT&>()) } -> std::same_as<typename T::pec_result_t>;
|
||||||
};
|
// };
|
||||||
|
|
||||||
} // namespace traits
|
// } // namespace traits
|
||||||
|
|
||||||
// type of PEC corrections (algorithm used):
|
// type of PEC corrections (algorithm used):
|
||||||
// PEC_TYPE_GEOMETRY - "classic" geometry-based correction coefficients
|
// PEC_TYPE_GEOMETRY - "classic" geometry-based correction coefficients
|
||||||
@ -37,9 +38,14 @@ concept mcc_mount_pec_c = requires(T t, const T t_const, XT x, YT y) {
|
|||||||
// PEC_TYPE_BSPLINE - pure 2D B-spline corrections
|
// PEC_TYPE_BSPLINE - pure 2D B-spline corrections
|
||||||
enum class MccMountDefaultPECType { PEC_TYPE_GEOMETRY, PEC_TYPE_GEOMETRY_BSPLINE, PEC_TYPE_BSPLINE };
|
enum class MccMountDefaultPECType { PEC_TYPE_GEOMETRY, PEC_TYPE_GEOMETRY_BSPLINE, PEC_TYPE_BSPLINE };
|
||||||
|
|
||||||
|
template <MccMountType MOUNT_TYPE>
|
||||||
class MccMountDefaultPEC
|
class MccMountDefaultPEC
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static constexpr MccMountType mountType = MOUNT_TYPE;
|
||||||
|
|
||||||
|
typedef MccAngle coord_t;
|
||||||
|
|
||||||
struct pec_result_t {
|
struct pec_result_t {
|
||||||
MccAngle dx, dy;
|
MccAngle dx, dy;
|
||||||
};
|
};
|
||||||
@ -128,16 +134,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// X and Y axis encoder coordinates
|
// X and Y axis encoder coordinates
|
||||||
template <std::derived_from<MccAngle> XT, std::derived_from<MccAngle> YT>
|
pec_result_t compute(const coord_t& x, const coord_t& y)
|
||||||
pec_result_t compute(const XT& x, const YT& y)
|
|
||||||
{
|
{
|
||||||
static constexpr MccCoordPairKind coord_kind = traits::mcc_type_pair_hash<XT, YT>();
|
|
||||||
|
|
||||||
pec_result_t res{0.0, 0.0};
|
pec_result_t res{0.0, 0.0};
|
||||||
|
|
||||||
std::lock_guard lock(_pecDataMutex);
|
std::lock_guard lock(_pecDataMutex);
|
||||||
|
|
||||||
if constexpr (coord_kind == MccCoordPairKind::COORDS_KIND_HADEC_APP) {
|
if constexpr (mcc_is_equatorial_mount<MOUNT_TYPE>) { // equatorial
|
||||||
if (_pecData.type == MccMountDefaultPECType::PEC_TYPE_GEOMETRY) {
|
if (_pecData.type == MccMountDefaultPECType::PEC_TYPE_GEOMETRY) {
|
||||||
const auto cosPhi = std::cos(_phi);
|
const auto cosPhi = std::cos(_phi);
|
||||||
const auto sinPhi = std::sin(_phi);
|
const auto sinPhi = std::sin(_phi);
|
||||||
@ -190,7 +193,7 @@ public:
|
|||||||
res.dx += spl_valX;
|
res.dx += spl_valX;
|
||||||
res.dy += spl_valY;
|
res.dy += spl_valY;
|
||||||
}
|
}
|
||||||
} else if constexpr (coord_kind == MccCoordPairKind::COORDS_KIND_AZALT) {
|
} else if constexpr (mcc_is_altaz_mount<MOUNT_TYPE>) {
|
||||||
} else {
|
} else {
|
||||||
static_assert(false, "UNSUPPORTED");
|
static_assert(false, "UNSUPPORTED");
|
||||||
}
|
}
|
||||||
@ -199,22 +202,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// X and Y apparent equatorial/altazimuthal coordinates (not corrected for refraction)
|
|
||||||
template <std::derived_from<MccAngle> XT, std::derived_from<MccAngle> YT>
|
|
||||||
pec_result_t computeInverse(const XT& x, const YT& y)
|
|
||||||
{
|
|
||||||
static constexpr MccCoordPairKind coord_kind = traits::mcc_type_pair_hash<XT, YT>();
|
|
||||||
|
|
||||||
pec_result_t res{0.0, 0.0};
|
|
||||||
|
|
||||||
if constexpr (coord_kind == MccCoordPairKind::COORDS_KIND_HADEC_APP) {
|
|
||||||
} else if constexpr (coord_kind == MccCoordPairKind::COORDS_KIND_AZALT) {
|
|
||||||
} else {
|
|
||||||
static_assert(false, "UNSUPPORTED");
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pec_data_t _pecData;
|
pec_data_t _pecData;
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
/* MOUNT TELEMETRY OBJECT CONCEPT AND POSSIBLE IMPLEMENTATION */
|
/* MOUNT TELEMETRY OBJECT CONCEPT AND POSSIBLE IMPLEMENTATION */
|
||||||
|
|
||||||
#include <chrono>
|
#include <functional>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
// #include "mcc_mount_config.h"
|
// #include "mcc_mount_config.h"
|
||||||
@ -32,73 +32,166 @@ namespace mcc
|
|||||||
|
|
||||||
// } // namespace traits
|
// } // namespace traits
|
||||||
|
|
||||||
|
template <traits::mcc_astrom_engine_c ASTROM_ENGINE_T,
|
||||||
|
traits::mcc_mount_pec_c PEC_T,
|
||||||
|
traits::mcc_mount_hardware_c HARDWARE_T>
|
||||||
class MccMountTelemetry
|
class MccMountTelemetry
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
typedef ASTROM_ENGINE_T astrom_engine_t;
|
||||||
|
typedef PEC_T pec_t;
|
||||||
|
typedef HARDWARE_T hardware_t;
|
||||||
|
|
||||||
|
enum error_t : int { TEL_ERROR_OK = 0, TEL_ERROR_HARDWARE, TEL_ERROR_ASTROMETRY_COMP };
|
||||||
|
|
||||||
|
// check for coordinate types consistency
|
||||||
|
static_assert(std::convertible_to<typename hardware_t::coord_t, typename astrom_engine_t::coord_t>,
|
||||||
|
"HARDWARE COORDINATE TYPE MUST BE CONVERTIBLE TO ASTROMETRY ENGINE ONE!");
|
||||||
|
|
||||||
|
static_assert(std::convertible_to<typename astrom_engine_t::coord_t, typename pec_t::coord_t>,
|
||||||
|
"ASTROMETRY ENGINE COORDINATE TYPE MUST BE CONVERTIBLE TO PEC ONE!");
|
||||||
|
|
||||||
|
static_assert(std::same_as<typename astrom_engine_t::time_point_t, typename hardware_t::time_point_t>,
|
||||||
|
"TIME-POINT TYPE IN ASTROMETRY ENGINE AND HARDWARE MUST BE THE SAME!");
|
||||||
|
|
||||||
// mount current telemetry data: time, position and related quantities
|
// mount current telemetry data: time, position and related quantities
|
||||||
struct mount_telemetry_data_t {
|
struct mount_telemetry_data_t {
|
||||||
typedef double mnt_coord_t;
|
typedef astrom_engine_t::coord_t mnt_coord_t;
|
||||||
typedef double mnt_speed_t;
|
// typedef astrom_engine_t::coord_t mnt_speed_t;
|
||||||
typedef double time_point_t;
|
|
||||||
typedef std::vector<double> refr_coeff_t;
|
|
||||||
|
|
||||||
// time-related
|
// time-related
|
||||||
std::chrono::system_clock::time_point utc;
|
typename astrom_engine_t::time_point_t utc; // time point of measurements, UTC
|
||||||
time_point_t mjd; // modified Julian date
|
typename astrom_engine_t::juldate_t jd; // Julian date
|
||||||
time_point_t ut1;
|
typename astrom_engine_t::sideral_time_t siderTime; // local apperant sideral time
|
||||||
time_point_t tt;
|
// astrom_engine_t::time_point_t ut1; // Universal time
|
||||||
time_point_t siderTime; // sideral time (in radians)
|
// astrom_engine_t::time_point_t tt; // Terrestial time
|
||||||
|
|
||||||
// apparent target (user-input) current coordinates (in radians)
|
// apparent target (user-input) current coordinates (in radians)
|
||||||
mnt_coord_t tagRA, tagDEC;
|
mnt_coord_t tagRA, tagDEC;
|
||||||
mnt_coord_t tagHA;
|
mnt_coord_t tagHA;
|
||||||
mnt_coord_t tagAZ, tagZD;
|
mnt_coord_t tagAZ, tagALT;
|
||||||
mnt_coord_t tagPA; // paralactic angle
|
mnt_coord_t tagPA; // paralactic angle
|
||||||
|
|
||||||
// encoder-measured current mount coordinates (in radians)
|
// encoder-measured current mount coordinates (in radians)
|
||||||
mnt_coord_t mntRA, mntDEC;
|
mnt_coord_t mntRA, mntDEC;
|
||||||
mnt_coord_t mntHA;
|
mnt_coord_t mntHA;
|
||||||
mnt_coord_t mntAZ, mntZD;
|
mnt_coord_t mntAZ, mntALT;
|
||||||
mnt_coord_t mntPA;
|
typename astrom_engine_t::pa_t mntPA;
|
||||||
|
|
||||||
// encoder-measured (non-corrected for PCS) current mount position and moving speed (in radians, radians/s)
|
// 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 - ZD for horizontal-type one
|
// X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ALT for horizontal-type one
|
||||||
mnt_coord_t mntPosX, mntPosY;
|
mnt_coord_t mntPosX, mntPosY;
|
||||||
mnt_speed_t mntSpeedX, mntSpeedY;
|
// mnt_speed_t mntSpeedX, mntSpeedY;
|
||||||
|
|
||||||
// current refraction coefficients
|
// current refraction coefficients
|
||||||
refr_coeff_t currRefrCoeffs;
|
typename pec_t::pec_result_t currRefrCoeffs;
|
||||||
// current refraction correction (for tagZD)
|
// current refraction correction (for mntALT)
|
||||||
mnt_coord_t currRefr;
|
mnt_coord_t currRefr;
|
||||||
|
|
||||||
// PCS (pointing correction system) corrections
|
// PEC (pointing error correction):
|
||||||
// X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ZD for horizontal-type one
|
// X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ALT for horizontal-type one
|
||||||
mnt_coord_t pcsX, pcsY;
|
mnt_coord_t pecX, pecY;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <MccMountType MOUNT_TYPE>
|
MccMountTelemetry(astrom_engine_t& astrom_engine, pec_t& pec, hardware_t& hardware)
|
||||||
MccMountTelemetry(MccMountConfig<MOUNT_TYPE>& mount_config)
|
|
||||||
{
|
{
|
||||||
// to be sure that mount_config is captured by reference
|
// to be sure that arguments are captured by reference
|
||||||
const auto config_ptr = &mount_config;
|
const auto astrom_engine_ptr = &astrom_engine;
|
||||||
|
const auto pec_ptr = &pec;
|
||||||
|
const auto hardware_ptr = &hardware;
|
||||||
|
|
||||||
_updateImpl = [config_ptr, this]() {
|
_updateImpl = [astrom_engine_ptr, pec_ptr, hardware_ptr, this]() {
|
||||||
mount_telemetry_data_t current_data;
|
mount_telemetry_data_t current_data;
|
||||||
|
|
||||||
// computing ...
|
// computing ...
|
||||||
|
|
||||||
|
typename hardware_t::axes_pos_t ax_pos;
|
||||||
|
|
||||||
|
auto err = hardware_ptr->getPos(ax_pos);
|
||||||
|
if (err) {
|
||||||
|
// logging?!!!
|
||||||
|
return TEL_ERROR_HARDWARE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_data.utc = ax_pos.time_point;
|
||||||
|
_data.mntPosX = ax_pos.x;
|
||||||
|
_data.mntPosY = ax_pos.y;
|
||||||
|
|
||||||
|
// compute Julian date
|
||||||
|
auto ast_err = astrom_engine_ptr->greg2jul(_data.utc, _data.jd);
|
||||||
|
if (ast_err) {
|
||||||
|
return TEL_ERROR_ASTROMETRY_COMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute local apparent sideral time
|
||||||
|
ast_err = astrom_engine_ptr->apparentSiderTime(_data.jd, _data.siderTime, true);
|
||||||
|
if (ast_err) {
|
||||||
|
return TEL_ERROR_ASTROMETRY_COMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute equation of origins
|
||||||
|
typename astrom_engine_t::eo_t eo;
|
||||||
|
ast_err = astrom_engine_ptr->eqOrigins(_data.jd, eo);
|
||||||
|
if (ast_err) {
|
||||||
|
return TEL_ERROR_ASTROMETRY_COMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typename pec_t::pec_result_t pec_res;
|
||||||
|
pec_res = pec_ptr->compute(ax_pos.x, ax_pos.y);
|
||||||
|
|
||||||
|
if constexpr (mccIsEquatorialMount(pec_t::mountType)) {
|
||||||
|
_data.mntHA = pec_res.x + ax_pos.x;
|
||||||
|
_data.mntDEC = pec_res.y + ax_pos.y;
|
||||||
|
|
||||||
|
ast_err = astrom_engine_ptr->hadec2azalt(_data.mntHA, _data.mntDEC, _data.mntAZ, _data.mntALT);
|
||||||
|
if (ast_err) {
|
||||||
|
return TEL_ERROR_ASTROMETRY_COMP;
|
||||||
|
}
|
||||||
|
} else if constexpr (mccIsAltAzMount(pec_t::mountType)) {
|
||||||
|
_data.mntAZ = pec_res.x + ax_pos.x;
|
||||||
|
_data.mntALT = pec_res.y + ax_pos.x;
|
||||||
|
|
||||||
|
ast_err = astrom_engine_ptr->azalt2hadec(_data.mntAZ, _data.mntALT, _data.mntHA, _data.mntDEC);
|
||||||
|
if (ast_err) {
|
||||||
|
return TEL_ERROR_ASTROMETRY_COMP;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
static_assert(false, "UNSUPPORTED MOUNT TYPE!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute CIO-based apparent RA
|
||||||
|
_data.mntRA = _data.siderTime - _data.mntHA + eo;
|
||||||
|
|
||||||
|
// compute PA
|
||||||
|
ast_err = astrom_engine_ptr->hadec2pa(_data.mntHA, _data.mntDEC, _data.mntPA);
|
||||||
|
if (ast_err) {
|
||||||
|
return TEL_ERROR_ASTROMETRY_COMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_err = astrom_engine_ptr->refraction(_data.currRefrCoeffs);
|
||||||
|
if (ast_err) {
|
||||||
|
return TEL_ERROR_ASTROMETRY_COMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_err = astrom_engine_ptr->refractCorrection(_data.mntALT, _data.currRefrCoeffs, _data.currRefr);
|
||||||
|
if (ast_err) {
|
||||||
|
return TEL_ERROR_ASTROMETRY_COMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::lock_guard lock{_updateMutex};
|
std::lock_guard lock{_updateMutex};
|
||||||
|
|
||||||
_data = current_data;
|
_data = std::move(current_data);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~MccMountTelemetry() = default;
|
virtual ~MccMountTelemetry() = default;
|
||||||
|
|
||||||
// update current data method
|
// update current data method
|
||||||
void update()
|
error_t update()
|
||||||
{
|
{
|
||||||
_updateImpl();
|
_updateImpl();
|
||||||
}
|
}
|
||||||
@ -116,7 +209,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
mount_telemetry_data_t _data{};
|
mount_telemetry_data_t _data{};
|
||||||
|
|
||||||
std::function<void()> _updateImpl{};
|
std::function<error_t()> _updateImpl{};
|
||||||
|
|
||||||
std::mutex _updateMutex;
|
std::mutex _updateMutex;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -160,9 +160,12 @@ concept mcc_tuple_c = requires {
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept mcc_nonconst_ref = std::is_lvalue_reference_v<T> && !std::is_const_v<std::remove_reference_t<T>>;
|
concept mcc_nonconst_lvref = std::is_lvalue_reference_v<T> && !std::is_const_v<std::remove_reference_t<T>>;
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept mcc_error_c = std::convertible_to<T, bool> && mcc_formattable<T>;
|
||||||
|
|
||||||
namespace details
|
namespace details
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@ -163,9 +163,9 @@ int main(int argc, char* argv[])
|
|||||||
erfa.greg2jul(now, jd);
|
erfa.greg2jul(now, jd);
|
||||||
std::cout << "MJD(" << now << ") = " << jd.mjd << "\n";
|
std::cout << "MJD(" << now << ") = " << jd.mjd << "\n";
|
||||||
|
|
||||||
mcc::MccAngle gst;
|
mcc::MccAngle lst;
|
||||||
erfa.apparentSiderTime(jd, gst, true);
|
erfa.apparentSiderTime(jd, lst, true);
|
||||||
std::cout << "GST(MJD = " << jd.mjd << ") = " << gst.sexagesimal(true) << "\n\n";
|
std::cout << "LST(MJD = " << jd.mjd << ") = " << lst.sexagesimal(true) << "\n\n";
|
||||||
|
|
||||||
|
|
||||||
mcc::MccAngle ra1{"10:00:00", mcc::mcc_hms}, dec1{"68:25:10.43"}, ra_o, dec_o, ha1, az1, alt1;
|
mcc::MccAngle ra1{"10:00:00", mcc::mcc_hms}, dec1{"68:25:10.43"}, ra_o, dec_o, ha1, az1, alt1;
|
||||||
@ -173,13 +173,21 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
auto res = erfa.icrs2obs(ra1, dec1, jd, ra_o, dec_o, ha1, az1, alt1);
|
auto res = erfa.icrs2obs(ra1, dec1, jd, ra_o, dec_o, ha1, az1, alt1);
|
||||||
|
|
||||||
|
mcc::MccAngle eor;
|
||||||
|
|
||||||
std::cout << "ret code (icrs2obs) = " << erfa.errorString(res) << "\n";
|
std::cout << "ret code (icrs2obs) = " << erfa.errorString(res) << "\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";
|
||||||
|
|
||||||
|
std::cout << "HA_app = " << ha1.sexagesimal(true) << "\n";
|
||||||
std::cout << "RA_app = " << ra_o.sexagesimal(true) << "\n";
|
std::cout << "RA_app = " << ra_o.sexagesimal(true) << "\n";
|
||||||
std::cout << "DEC_app = " << dec_o.sexagesimal() << "\n";
|
std::cout << "DEC_app = " << dec_o.sexagesimal() << "\n";
|
||||||
|
|
||||||
|
res = erfa.eqOrigins(jd, eor);
|
||||||
|
|
||||||
|
std::cout << "eq of origins = " << eor.sexagesimal(true) << "\n";
|
||||||
|
std::cout << "RA_app_comp = " << (lst - ha1 + eor).sexagesimal(true) << "\n";
|
||||||
|
|
||||||
|
|
||||||
return ecode;
|
return ecode;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user