...
This commit is contained in:
parent
9cd52267d6
commit
6d65efd0af
@ -10,40 +10,13 @@
|
||||
|
||||
|
||||
#include "mcc_astrom_iers.h"
|
||||
#include "mcc_mount_concepts.h"
|
||||
#include "mcc_mount_coord.h"
|
||||
|
||||
// #include "mcc_mount_astrom.h"
|
||||
#include "mcc_mount_concepts.h"
|
||||
|
||||
namespace mcc::astrom::erfa
|
||||
{
|
||||
|
||||
#include <erfa.h>
|
||||
#include <erfam.h>
|
||||
|
||||
|
||||
/* A concept for ERFA-library compatible type to represent anglular quantities */
|
||||
template <typename T>
|
||||
concept mcc_erfa_angle_t = std::constructible_from<T, double> && std::convertible_to<T, double>;
|
||||
|
||||
template <mcc_erfa_angle_t AngleT = MccAngle>
|
||||
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:
|
||||
static constexpr double DEFAULT_WAVELENGTH = 0.55; // default observed wavelength in mkm
|
||||
enum error_t : size_t {
|
||||
enum class MccMountAstromEngineERFAErrorCode : int {
|
||||
ERROR_OK = 0,
|
||||
ERROR_INVALID_INPUT_ARG,
|
||||
ERROR_JULDATE_INVALID_YEAR,
|
||||
@ -56,6 +29,96 @@ public:
|
||||
ERROR_UPDATE_BULLETINA,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <>
|
||||
class is_error_code_enum<mcc::astrom::erfa::MccMountAstromEngineERFAErrorCode> : public true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
|
||||
namespace mcc::astrom::erfa
|
||||
{
|
||||
|
||||
#include <erfa.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 */
|
||||
template <typename T>
|
||||
concept mcc_erfa_angle_t = std::constructible_from<T, double> && std::convertible_to<T, double>;
|
||||
|
||||
template <mcc_erfa_angle_t AngleT = MccAngle>
|
||||
class MccMountAstromEngineERFA
|
||||
{
|
||||
public:
|
||||
static constexpr double DEFAULT_WAVELENGTH = 0.55; // default observed wavelength in mkm
|
||||
|
||||
typedef std::error_code error_t;
|
||||
|
||||
|
||||
// meteo parameters (to compute refraction)
|
||||
struct meteo_t {
|
||||
@ -140,10 +203,10 @@ public:
|
||||
std::lock_guard lock{_stateMutex};
|
||||
|
||||
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};
|
||||
|
||||
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};
|
||||
|
||||
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};
|
||||
|
||||
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 */
|
||||
|
||||
// templated generic version
|
||||
@ -203,10 +260,10 @@ public:
|
||||
static constexpr std::chrono::year MIN_YEAR = -4799y;
|
||||
|
||||
if (ymd.year() < MIN_YEAR) {
|
||||
return ERROR_JULDATE_INVALID_YEAR;
|
||||
return MccMountAstromEngineERFAErrorCode::ERROR_JULDATE_INVALID_YEAR;
|
||||
}
|
||||
if (!ymd.month().ok()) {
|
||||
return ERROR_JULDATE_INVALID_MONTH;
|
||||
return MccMountAstromEngineERFAErrorCode::ERROR_JULDATE_INVALID_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
|
||||
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)
|
||||
@ -242,14 +299,14 @@ public:
|
||||
if (tai_utc.has_value()) {
|
||||
tt.mjd += std::chrono::duration_cast<real_days_t>(tai_utc.value()).count();
|
||||
} else {
|
||||
return ERROR_LEAPSECONDS_OUT_OF_RANGE;
|
||||
return MccMountAstromEngineERFAErrorCode::ERROR_LEAPSECONDS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
|
||||
auto tt_tai = _currentState._bulletinA.TT_TAI();
|
||||
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()) {
|
||||
ut1 += std::chrono::duration_cast<real_days_t>(dut1.value()).count();
|
||||
} 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;
|
||||
auto err = terrestrialTime(juldate, tt);
|
||||
if (err != ERROR_OK) {
|
||||
if (err != MccMountAstromEngineERFAErrorCode::ERROR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -297,7 +354,7 @@ public:
|
||||
gst += _currentState.lon;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
return MccMountAstromEngineERFAErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -306,13 +363,13 @@ public:
|
||||
juldate_t tt;
|
||||
|
||||
auto err = terrestrialTime(juldate, tt);
|
||||
if (err != ERROR_OK) {
|
||||
if (err != MccMountAstromEngineERFAErrorCode::ERROR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
eo = eraEo06a(tt.MJD0, tt.mjd);
|
||||
|
||||
return ERROR_OK;
|
||||
return MccMountAstromEngineERFAErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
/* atmospheric refraction-related methods */
|
||||
@ -324,7 +381,7 @@ public:
|
||||
eraRefco(_currentState.meteo.pressure, _currentState.meteo.temperature, _currentState.meteo.humidity,
|
||||
_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;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
return MccMountAstromEngineERFAErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
/* coordinates conversional methods */
|
||||
@ -357,12 +414,12 @@ public:
|
||||
auto dut1 = _currentState._bulletinA.DUT1(juldate.mjd);
|
||||
|
||||
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);
|
||||
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;
|
||||
pol_pos->x *= arcsec2rad;
|
||||
@ -376,9 +433,9 @@ public:
|
||||
&oaz, &ozd, &oha, &odec, &ora, &eo_);
|
||||
|
||||
if (ret == 1) {
|
||||
return ERROR_DUBIOUS_YEAR;
|
||||
return MccMountAstromEngineERFAErrorCode::ERROR_DUBIOUS_YEAR;
|
||||
} else if (ret == -1) {
|
||||
return ERROR_UNACCEPTABLE_DATE;
|
||||
return MccMountAstromEngineERFAErrorCode::ERROR_UNACCEPTABLE_DATE;
|
||||
}
|
||||
|
||||
ra_app = ora;
|
||||
@ -388,7 +445,7 @@ public:
|
||||
ha = oha;
|
||||
eo = eo_;
|
||||
|
||||
return ERROR_OK;
|
||||
return MccMountAstromEngineERFAErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -402,7 +459,7 @@ public:
|
||||
az = r_az;
|
||||
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)
|
||||
@ -416,7 +473,7 @@ public:
|
||||
ha = r_ha;
|
||||
dec = r_dec;
|
||||
|
||||
return ERROR_OK;
|
||||
return MccMountAstromEngineERFAErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -426,7 +483,7 @@ public:
|
||||
|
||||
pa = eraHd2pa(ha, dec, _currentState.lat);
|
||||
|
||||
return ERROR_OK;
|
||||
return MccMountAstromEngineERFAErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -97,12 +97,6 @@ concept mcc_astrom_engine_c = requires(T t, const T t_const) {
|
||||
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 */
|
||||
|
||||
// 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>
|
||||
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
|
||||
// requires requires(typename T::mount_telemetry_data_t telemetry) {
|
||||
|
||||
@ -12,6 +12,65 @@
|
||||
#include "mcc_mount_concepts.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
|
||||
{
|
||||
|
||||
@ -165,7 +224,7 @@ public:
|
||||
if (ret) {
|
||||
res.dx = 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) {
|
||||
res.dx = 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");
|
||||
}
|
||||
|
||||
return std::error_code();
|
||||
return MccMountDefaultPECErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
// from celestial to encoder (use of iterative scheme)
|
||||
@ -196,35 +255,59 @@ public:
|
||||
coord_t e2 = eps * eps;
|
||||
|
||||
coord_t xi = x, yi = y;
|
||||
coord_t xp, yp;
|
||||
coord_t xe, ye;
|
||||
size_t iter = 1;
|
||||
|
||||
// the first iteration
|
||||
auto err = compute(x, y, res);
|
||||
|
||||
if (!err) {
|
||||
xp = x - res.dx;
|
||||
yp = y - res.dy;
|
||||
// 'encoder' cocordinates
|
||||
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) {
|
||||
return std::error_code();
|
||||
return MccMountDefaultPECErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
while (iter < max_iter) {
|
||||
xi = xp;
|
||||
yi = xp;
|
||||
err = compute(xi, yi, res);
|
||||
xp -= res.dx;
|
||||
yp -= res.dy;
|
||||
err = compute(xi, yi, res); // to encoder
|
||||
if (err) {
|
||||
return MccMountDefaultPECErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
|
||||
}
|
||||
xe = x - res.dx;
|
||||
ye = y - res.dy;
|
||||
|
||||
ok = ((xp - xi) * (xp - xi) + (yp - yi) * (yp - yi)) <= 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;
|
||||
|
||||
ok = ((x - xi) * (x - xi) + (y - yi) * (y - yi)) <= e2;
|
||||
if (ok) {
|
||||
return std::error_code();
|
||||
}
|
||||
return MccMountDefaultPECErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
// err = "exceed max iterations";!!!
|
||||
++iter;
|
||||
}
|
||||
|
||||
err = MccMountDefaultPECErrorCode::ERROR_EXCEED_MAX_ITERS;
|
||||
}
|
||||
|
||||
return err;
|
||||
|
||||
@ -139,42 +139,6 @@ public:
|
||||
|
||||
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)
|
||||
: _astromEngine(astrom_engine), _pec(pec), _hardware(hardware)
|
||||
|
||||
@ -19,7 +19,6 @@ namespace mcc
|
||||
* [azimuth, zenithal distance] (see sources code below)
|
||||
*/
|
||||
|
||||
template <traits::mcc_mount_telemetry_c TELEMETRY_T>
|
||||
class MccSimpleSlewModel
|
||||
{
|
||||
public:
|
||||
@ -37,26 +36,47 @@ public:
|
||||
};
|
||||
|
||||
|
||||
template <traits::mcc_mount_hardware_c HARDWARE_T,
|
||||
traits::mcc_astrom_engine_c ASTROM_T,
|
||||
traits::mcc_mount_pec_c PEC_T>
|
||||
MccSimpleSlewModel(HARDWARE_T& hardware, ASTROM_T& astrom_engine, PEC_T& pec)
|
||||
template <traits::mcc_mount_controls_c MOUNT_CONTROLS_T>
|
||||
MccSimpleSlewModel(MOUNT_CONTROLS_T& mount_controls)
|
||||
{
|
||||
const auto p_hardware = &hardware;
|
||||
const auto p_astrom_engine = &astrom_engine;
|
||||
const auto p_pec = &pec;
|
||||
// deduce controls types
|
||||
using astrom_engine_t = decltype(mount_controls.astrometryEngine);
|
||||
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,
|
||||
TELEMETRY_T& telemetry) {
|
||||
using coord_t = typename ASTROM_T::coord_t;
|
||||
using jd_t = typename ASTROM_T::juldate_t;
|
||||
using coord_t = typename astrom_engine_t::coord_t;
|
||||
using jd_t = typename astrom_engine_t::juldate_t;
|
||||
|
||||
typename HARDWARE_T::axes_pos_t ax_pos;
|
||||
typename hardware_t::axes_pos_t ax_pos;
|
||||
|
||||
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) {
|
||||
// trivial case (the pair is interpretated as raw encoder coordinates)
|
||||
@ -66,26 +86,24 @@ public:
|
||||
mcc::MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // catalog coordinates
|
||||
jd_t jd;
|
||||
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) {
|
||||
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 constexpr (mccIsEquatorialMount(PEC_T::mountType)) {
|
||||
if constexpr (mccIsEquatorialMount(pec_t::mountType)) {
|
||||
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP,
|
||||
.x = ha,
|
||||
.y = dec_app,
|
||||
.stop = slew_pars.stop},
|
||||
telemetry);
|
||||
} else if constexpr (mccIsAltAzMount(PEC_T::mountType)) {
|
||||
.stop = slew_pars.stop});
|
||||
} else if constexpr (mccIsAltAzMount(pec_t::mountType)) {
|
||||
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_AZALT,
|
||||
.x = az,
|
||||
.y = alt,
|
||||
.stop = slew_pars.stop},
|
||||
telemetry);
|
||||
.stop = slew_pars.stop});
|
||||
} else {
|
||||
static_assert(false, "UNKNOWN MOUNT TYPE!");
|
||||
}
|
||||
@ -94,78 +112,73 @@ public:
|
||||
|
||||
} else if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_RADEC_APP) { // apparent
|
||||
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) {
|
||||
typename ASTROM_T::sideral_time_t lst;
|
||||
ast_err = p_astrom_engine->apparentSiderTime(jd, lst, true);
|
||||
typename astrom_engine_t::sideral_time_t lst;
|
||||
ast_err = astrom_engine->apparentSiderTime(jd, lst, true);
|
||||
|
||||
if (!ast_err) {
|
||||
ast_err = p_astrom_engine->eqOrigins(jd, eo);
|
||||
ast_err = astrom_engine->eqOrigins(jd, eo);
|
||||
if (!ast_err) {
|
||||
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP,
|
||||
.x = lst - slew_pars.x + eo, // HA = LST - RA_APP + EO
|
||||
.y = slew_pars.y,
|
||||
.stop = slew_pars.stop},
|
||||
telemetry);
|
||||
.stop = slew_pars.stop});
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
|
||||
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);
|
||||
if (!err) {
|
||||
pec_err = pec->reverseCompute(slew_pars.x, slew_pars.y, pec_res, eps, 10);
|
||||
if (!pec_err) {
|
||||
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_XY,
|
||||
.x = slew_pars.x - pec_res.dx,
|
||||
.y = slew_pars.y - pec_res.dy,
|
||||
.stop = slew_pars.stop},
|
||||
telemetry);
|
||||
.stop = slew_pars.stop});
|
||||
}
|
||||
} else if constexpr (mccIsAltAzMount(PEC_T::mountType)) {
|
||||
} else if constexpr (mccIsAltAzMount(pec_t::mountType)) {
|
||||
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) {
|
||||
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_AZALT,
|
||||
.x = az,
|
||||
.y = alt,
|
||||
.stop = slew_pars.stop},
|
||||
telemetry);
|
||||
.stop = slew_pars.stop});
|
||||
}
|
||||
} else {
|
||||
static_assert(false, "UNKNOWN MOUNT TYPE!");
|
||||
}
|
||||
} 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;
|
||||
|
||||
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) {
|
||||
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP,
|
||||
.x = ha,
|
||||
.y = dec,
|
||||
.stop = slew_pars.stop},
|
||||
telemetry);
|
||||
.stop = slew_pars.stop});
|
||||
}
|
||||
} 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;
|
||||
|
||||
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);
|
||||
if (!err) {
|
||||
pec_err = pec->reverseCompute(slew_pars.x, slew_pars.y, pec_res, eps, 10);
|
||||
if (!pec_err) {
|
||||
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_XY,
|
||||
.x = slew_pars.x - pec_res.dx,
|
||||
.y = slew_pars.y - pec_res.dy,
|
||||
.stop = slew_pars.stop},
|
||||
telemetry);
|
||||
.stop = slew_pars.stop});
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -178,32 +191,57 @@ public:
|
||||
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_AZALT,
|
||||
.x = slew_pars.x,
|
||||
.y = std::numbers::pi / 2.0 - slew_pars.y,
|
||||
.stop = slew_pars.stop},
|
||||
telemetry);
|
||||
.stop = slew_pars.stop});
|
||||
}
|
||||
|
||||
if (res_err) {
|
||||
return res_err;
|
||||
}
|
||||
|
||||
if (!ast_err) {
|
||||
auto err = p_hardware->setPos(std::move(ax_pos));
|
||||
if (pec_err) {
|
||||
// ???????????
|
||||
return std::error_code(); // !!!!!!!!!!!!!!!
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::function<error_t(const slew_params_t&, TELEMETRY_T&)> _slewFunc{};
|
||||
std::function<error_t(const slew_params_t&)> _slewFunc{};
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
|
||||
struct tel_data_t {
|
||||
typedef mcc::MccAngle coord_t;
|
||||
typedef std::chrono::system_clock::time_point time_point_t;
|
||||
|
||||
coord_t mntRA, mntDEC, mntHA;
|
||||
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);
|
||||
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 << "az = " << az1.sexagesimal() << "\n";
|
||||
|
||||
@ -232,7 +233,7 @@ int main(int argc, char* argv[])
|
||||
ra1 = "17:00:00"_hms;
|
||||
dec1 = "40:25:10.43"_dms;
|
||||
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 << "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";
|
||||
}
|
||||
|
||||
ra_o = 1.0;
|
||||
dec_o = 2.0;
|
||||
ha1 = ra_o * dec_o;
|
||||
std::cout << "mult: " << ha1.degrees() << "\n";
|
||||
|
||||
return ecode;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user