Back to Pytheia 2.1.1

Using a Pytheia model in a telescope control system

These 2.1.0 term definitions and control-system conventions are retained in Pytheia 2.1.1.

Pytheia fits the coefficients of a pointing model and writes them to a file, coefficients_<data>.txt. The modules in this folder apply that model in a telescope control system, exactly as Pytheia defines it:

File Language
pointing_model.py Python 3, standard library only
pointing_model.c, pointing_model.h C99; also usable from C++ as they are

Use the module for your language in your control system subject to the Orionis evaluation terms in pytheia200.html#evaluation. These instructions do not grant additional redistribution or commercial-use rights. Both give the same results, and both match Pytheia to better than a millionth of an arcsecond. For a control system in another language, TERMS.md describes the model step by step, with reference values to check an implementation against.


Windows package notes

The numerical examples below illustrate API usage; their coefficients and latitude are not the supplied Orionis synthetic reference model. Load the coefficient file produced by your own fit, and check its mode and latitude.

The standalone Python module uses the standard library for built-in terms. Custom terms may need NumPy. Configure dependencies in your control-system environment; do not modify the bundled Pytheia runtime.

Module self-tests check numerical consistency. They do not replace validation of units, coordinate conventions, timing, auxiliary inputs and telescope behaviour in the receiving control system.


What the modules do

Each module answers three questions, in degrees:

Function Question When to use it
encoder position where must the encoders go so that the telescope points at this star? every time the telescope points
correction the same, as an offset: encoder position minus star position if your control system adds offsets to its demands
star position where does the telescope actually point, for these encoder readings? displays, logs, checks

The star position is the star's observed place: its catalogue position corrected for proper motion, precession, nutation, aberration, parallax and atmospheric refraction — where it actually appears in the sky from the site. Your control system computes that, as it does today; the module then adds the pointing correction.

Positions are in azimuth (from north through east) and elevation, or in hour angle (positive west) and declination, according to the mode the model was fitted in.


Python

from pointing_model import PointingModel

model = PointingModel.from_file("coefficients_mydata.txt")   # mode and latitude from the file

az_enc, el_enc = model.encoder_position(az, el)               # where to send the encoders
d_az, d_el = model.correction(az, el)                         # or: the offset to add
az_sky, el_sky = model.star_position(az_enc, el_enc)          # where the telescope points

If your control system keeps the coefficients in its own configuration, give them directly:

model = PointingModel({"IA": 95.35, "IE": 12.26, "CA": 60.23}, "azel", latitude=-29.259)

Auxiliary terms. If the model contains AUX terms, pass the current readings: model.encoder_position(az, el, aux1=temperature).

Your own terms. In the Windows package, editable terms are defined in app/additional_terms.py. Make the corresponding module available to your control-system Python environment. If the model contains terms you defined in that file, pass that file as a module: PointingModel.from_file(path, user_terms=additional_terms) after import additional_terms. That file needs numpy, as it does in Pytheia.

Errors. A coefficient file with an unknown term raises ValueError. A position where the calculation cannot settle — only possible very close to the horizon with large flexure terms — raises RuntimeError.


C and C++

#include "pointing_model.h"

pm_model m;
if (pm_load_file(&m, "coefficients_mydata.txt") != PM_OK) { /* handle the error */ }

double az_enc, el_enc;
if (pm_encoder_position(&m, az, el, 0.0, 0.0, &az_enc, &el_enc) != PM_OK) { /* ... */ }

Compile pointing_model.c with your control system. With compilers that require it, link the maths library using -lm; this flag is not an MSVC option. Orionis also checked the module with MSVC as C11 and C++14, using /W4 /WX. The module allocates no memory and keeps no global state, so it can run in real-time code; one pm_model holds one model.

If your control system keeps the coefficients in its own configuration:

pm_init(&m, PM_AZEL, -29.259);          /* PM_AZEL or PM_HADEC, latitude in degrees */
pm_set_term(&m, "IA", 95.35);           /* arcsec */
pm_set_term(&m, "IE", 12.26);

The two arguments after the position are the auxiliary readings aux1 and aux2; pass 0 if the model has no AUX terms.

Every function returns PM_OK (0) or a negative error code: an unknown term, a file that cannot be read, a missing mode or latitude, or a position where the calculation cannot settle. pointing_model.h lists them.

Your own terms go in the function user_term() at the top of pointing_model.c, which explains how, with an example.

From C++, include pointing_model.h as it is: the header declares the functions as C functions, so no wrapper is needed.


Checking an integration

Each module checks itself against reference values computed by Pytheia:

import pointing_model
pointing_model.selftest()              # returns 0 when everything agrees
if (pm_selftest(1) != 0) { /* the module does not behave as Pytheia defines the model */ }

Run it once inside your control system after integrating the module — built with your compiler, on your machine — and again after any change to it.


When you refit

A new fit gives a new coefficient file. Load it in place of the old one; nothing else changes. Coefficients belong to the term definitions they were fitted with: never mix coefficients and modules from different versions of Pytheia.