Instrument Neutral Distributed Interface INDI 2.2.5
scopesim_helper.cpp
Go to the documentation of this file.
1/*
2 * scopesim_helper.cpp
3 *
4 * Copyright 2020 Chris Rowland <[email protected]>
5 *
6 * implementation of telescope simulator helper classes Angle, Axis and Alignment
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 * MA 02110-1301, USA.
22 */
23
24#include "scopesim_helper.h"
25
26#include "indilogger.h"
27#include "indicom.h"
28
29#include <libnova/julian_day.h>
30#include <libnova/sidereal_time.h>
31
32char device_str[64] = "Telescope Simulator";
33
35
36// Angle implementation
37
39{
40 switch(type)
41 {
42 case DEGREES:
43 angle = range(value);
44 break;
45 case HOURS:
46 angle = range(value * 15.0);
47 break;
48 case RADIANS:
49 angle = range(value * 180.0 / M_PI);
50 break;
51 }
52}
53
55{
56 return this->angle * M_PI / 180.0;
57}
58
60{
61 return std::abs(difference(a)) < 10E-6;
62}
63
65{
66 return std::abs(difference(a)) >= 10E-6;
67}
68
70
71// Axis Implementation
72
73void Axis::setDegrees(double degrees)
74{
75 this->position = degrees;
76 this->target = degrees;
77}
78
79void Axis::setHours(double hours)
80{
81 this->position = hours * 15.0;
82 this->target = hours * 15.0;
83}
84
86{
87 LOGF_DEBUG("%s StartSlew to %f", axisName, angle.Degrees());
88 target = angle;
89 isSlewing = true;
90}
91
92void Axis::Tracking(bool enabled)
93{
94 tracking = enabled;
95 LOGF_EXTRA1("%s Tracking enabled %s", axisName, enabled ? "true" : "false");
96}
97
99{
100 trackingRate = rate;
101 switch (trackingRate)
102 {
105 break;
107 TrackingRateDegSec = siderealRate;
108 break;
110 TrackingRateDegSec = solarRate;
111 break;
113 TrackingRateDegSec = lunarRate;
114 break;
115 }
116 LOGF_EXTRA1("%s: TrackRate %i, trackingRateDegSec %f arcsec", axisName, trackingRate, TrackingRateDegSec.Degrees() * 3600);
117}
118
120{
121 return trackingRate;
122}
123
128
129void Axis::StartGuide(double rate, uint32_t durationMs)
130{
131 // rate is fraction of sidereal, signed to give the direction
132
133 guideRateDegSec = (360.0 / 86400) * rate;
134 guideDuration = durationMs / 1000.0;
135 LOGF_DEBUG("%s StartGuide rate %f=>%f, dur %d =>%f", axisName, rate, guideRateDegSec.Degrees(), durationMs, guideDuration);
136}
137
138void Axis::update() // called about once a second to update the position and mode
139{
140 struct timeval currentTime
141 {
142 0, 0
143 };
144
145 /* update elapsed time since last poll, don't presume exactly POLLMS */
146 gettimeofday(&currentTime, nullptr);
147
148 if (lastTime.tv_sec == 0 && lastTime.tv_usec == 0)
149 lastTime = currentTime;
150
151 // Time diff in seconds
152 double interval = currentTime.tv_sec - lastTime.tv_sec + (currentTime.tv_usec - lastTime.tv_usec) / 1e6;
153 lastTime = currentTime;
154 double change = 0;
155
156 //LOGF_DEBUG("%s: position %f, target %f, interval %f", axisName, position.Degrees(), target.Degrees(), interval);
157
158 // tracking
159 if (isTracking())
160 {
161 position += TrackingRateDegSec * interval;
162 target += TrackingRateDegSec * interval;
163 LOGF_EXTRA1("%s: tracking, rate %f, position %f, target %f", axisName, TrackingRateDegSec.Degrees(), position.Degrees(), target.Degrees());
164 }
165
166 // handle the slew
167 if (isSlewing)
168 {
169 // get positions relative to the rotate centre
170 Angle trc = target - rotateCentre;
171 Angle prc = position - rotateCentre;
172 // get the change, don't use Angle so the change goes through the rotate centre
173 double delta = trc.Degrees() - prc.Degrees();
174 double fastChange = mcRates[4].Degrees() * interval;
175 double slowChange = fastChange / 5;
176 //LOGF_DEBUG("slew: trc %f prc %f, delta %f", trc.Degrees(), prc.Degrees(), delta);
177 // apply the change to the relative position
178 if (delta < -fastChange)
179 {
180 change = -fastChange;
181 }
182 else if (delta < -slowChange)
183 {
184 change = -slowChange;
185 }
186 else if (delta > fastChange)
187 {
188 change = fastChange;
189 }
190 else if (delta > slowChange)
191 {
192 change = slowChange;
193 }
194 else
195 {
196 position = target;
197 isSlewing = false;
198 //OnMoveFinished();
199 }
200 position += change;
201 //LOGF_DEBUG("move %s: change %f, position %f", b, change, position.Degrees());
202 }
203
204 int rate = std::max(-4,std::min(4,mcRate));
205 if(rate != mcRate) {
206 LOGF_ERROR("Invalid mcRate Detected = %d",mcRate);
207 }
208
209 // handle the motion control
210 if (rate < 0)
211 {
212 change = -mcRates[-rate].Degrees() * interval;
213 //LOGF_DEBUG("mcRate %d, rate %f, change %f", mcRate, mcRates[-mcRate].Degrees(), change);
214 position += change;
215 }
216 else if (rate > 0)
217 {
218 change = mcRates[rate].Degrees() * interval;
219 //LOGF_DEBUG("mcRate %d, rate %f, change %f", mcRate, mcRates[mcRate].Degrees(), change);
220 position += change;
221 }
222
223 // handle guiding
224 if (guideDuration > 0)
225 {
226 change = guideRateDegSec.Degrees() * (guideDuration > interval ? interval : guideDuration);
227 guideDuration -= interval;
228 LOGF_DEBUG("guide rate %f, remaining duration %f, change %f", guideRateDegSec.Degrees(), guideDuration, change);
229 position += change;
230 }
231}
232
234
235// Alignment methods
236
238{
239 return ln_get_julian_from_sys() + clockOffsetDays;
240}
241
243{
244 return Angle(range24(ln_get_apparent_sidereal_time(julianDate()) + longitude.Degrees360() / 15.0) * 15.0);
245}
246
247void Alignment::mountToApparentHaDec(Angle primary, Angle secondary, Angle * apparentHa, Angle* apparentDec)
248{
249
250 Angle prio, seco;
251 // get instrument place
252 switch (mountType)
253 {
255 // Primary instrument axis: Negative PA-system looking down from Zenith:Nadir, origin "HA-like"!!!
256 // Secondary instrument axis: Positive PA-system looking at E, origin "DEC-like"
258 // Primary instrument axis: ??
259 // Secondary instrument axis: ??
260 seco = (latitude >= 0) ? secondary : -secondary;
261 prio = primary;
262 break;
264 seco = (latitude >= 0) ? secondary : -secondary; // northern : southern hemisphere
265 prio = primary;
266 if (seco > 90 || seco < -90) // pierside west/looking east (cf. apparentHaDecToMount())
267 {
268 // Primary instrument axis: Negative PA-system looking down from NCP:SCP, origin opposite HA-like
269 // Secondary instrument axis: Negative PA-system looking at E, origin opposite DEC-like
270 prio = primary + Angle(180.0); // Primary to Ha transformation to get negative PA-system with origin HA-like
271 seco = Angle(180.0) - seco; // Secondary to Dec transformation to get positive PA-system origin DEC-like
272 }
273 break;
274 }
275 // instrument to observed, ignore apparent
276 instrumentToObserved(prio, seco, apparentHa, apparentDec);
277 // finally rotate an AltAzm mount to the Ha/Dec coordinates
279 {
280 Angle rot = latitude - Angle(90);
281 // apparentHa and apparentDec hold corrected INDI Az and Altitude.
282 // Vector uses scopesim Az (0=South); subtract 180 deg to convert from INDI Az.
283 Vector trueAzAlt(*apparentHa - Angle(180.0), *apparentDec);
284 Vector haDec = trueAzAlt.rotateY(rot);
285 // Primary instrument axis: Negative PA-system looking down from Zenith:Nadir, origin "HA-like" ...
286 *apparentHa = haDec.primary(); // ... so there is no transformation needed!
287 // Secondary instrument axis: Positive PA-system looking east, origin "DEC-like" ...
288 *apparentDec = haDec.secondary(); // ... so there is no transformation needed!
289 LOGF_EXTRA1("ALTAZ to apparent HaDec: pri %f, sec %f to ha %f, dec %f rot %f", prio.Degrees(), seco.Degrees(), apparentHa->Degrees(),
290 apparentDec->Degrees(), rot.Degrees());
291 }
292 else
293 LOGF_EXTRA1("EQ to apparent HaDec: pri %f, sec %f to ha %f, dec %f", prio.Degrees(), seco.Degrees(), apparentHa->Degrees(),
294 apparentDec->Degrees());
295}
296
297void Alignment::mountToApparentRaDec(Angle primary, Angle secondary, Angle * apparentRa, Angle* apparentDec)
298{
299 Angle ha;
300 mountToApparentHaDec(primary, secondary, &ha, apparentDec);
301 *apparentRa = lst() - ha;
302 LOGF_EXTRA1("mount to apparent RaDec: pri %f, sec %f to ha %f, ra %f, dec %f", primary.Degrees(), secondary.Degrees(), ha.Degrees(),
303 apparentRa->Degrees(), apparentDec->Degrees());
304}
305
306void Alignment::mountToInstrumentHaDec(Angle primary, Angle secondary, Angle *instrumentHa, Angle *instrumentDec)
307{
308 // Convert axis positions to equatorial HA/Dec without any Wallace pointing-model correction.
309 // For EQ mounts the axes are already in HA/Dec space; for ALTAZ we must apply the inverse
310 // spherical rotation (Az/Alt → HA/Dec) to match what apparentHaDecToMount does, but skip
311 // the instrumentToObserved step (which applies IH/ID/CH/NP).
312 switch (mountType)
313 {
315 {
316 // primary = INDI Az (0=North), secondary = Alt.
317 // Vector uses scopesim Az (0=South); subtract 180 deg before rotating to HA/Dec.
318 Angle rot = latitude - Angle(90); // inverse of rotateY(90 - lat)
319 Vector haDec = Vector(primary - Angle(180.0), secondary).rotateY(rot);
320 *instrumentHa = haDec.primary();
321 *instrumentDec = haDec.secondary();
322 break;
323 }
325 *instrumentDec = (latitude >= 0) ? secondary : -secondary;
326 *instrumentHa = primary;
327 break;
329 {
330 Angle seco = (latitude >= 0) ? secondary : -secondary;
331 if (seco.Degrees() > 90 || seco.Degrees() < -90)
332 {
333 *instrumentHa = primary + Angle(180.0);
334 *instrumentDec = Angle(180.0) - seco;
335 }
336 else
337 {
338 *instrumentHa = primary;
339 *instrumentDec = seco;
340 }
341 break;
342 }
343 }
344}
345
346void Alignment::instrumentHaDecToMount(Angle instrumentHa, Angle instrumentDec, Angle *primary, Angle *secondary)
347{
348 switch (mountType)
349 {
351 {
352 // Convert equatorial HA/Dec to Az/Alt via spherical rotation (no Wallace errors),
353 // mirroring apparentHaDecToMount but skipping the observedToInstrument step.
354 // Vector.primary() returns scopesim Az (0=South); add 180 deg to yield INDI Az (0=North).
355 Vector altAzm = Vector(instrumentHa, instrumentDec).rotateY(Angle(90) - latitude);
356 *primary = altAzm.primary() + Angle(180.0); // INDI Az (0=North)
357 *secondary = altAzm.secondary();
358 break;
359 }
361 // Primary instrument axis: HA (negative PA-system looking down to NCP:SCP)
362 // Secondary instrument axis: Dec (positive PA-system looking E)
363 *primary = instrumentHa;
364 *secondary = (latitude >= 0) ? instrumentDec : -instrumentDec;
365 break;
367 if (instrumentHa < flipHourAngle) // pierside west (looking east)
368 {
369 // Ha axis: Negative PA-system looking down from NCP:SCP, origin HA-like
370 // Dec axis: Positive PA-system looking at E, origin DEC-like
371 *primary = instrumentHa + Angle(180); // Ha to Primary: negative PA-system with origin opposite HA-like
372 *secondary = Angle(180) - instrumentDec; // Dec to Secondary: positive PA-system with origin DEC-like
373 }
374 else
375 {
376 *primary = instrumentHa; // Ha already rotated by 180
377 *secondary = instrumentDec; // Dec already rotated by 180
378 }
379 if (latitude < 0) // southern hemisphere
380 *secondary = -*secondary;
381 break;
382 }
383}
384
385void Alignment::apparentHaDecToMount(Angle apparentHa, Angle apparentDec, Angle* primary, Angle* secondary)
386{
387 // convert to Alt Azm first
389 {
390 // rotate the apparent HaDec vector to the vertical
391 // TODO sort out Southern Hemisphere
392 Vector altAzm = Vector(apparentHa, apparentDec).rotateY(Angle(90) - latitude);
393 // azimuth in scopesim convention is 0 deg = South, increasing clockwise West->North->East
394 // INDI's IHorizontalCoordinates uses 0 deg = North.
395 Angle apparentAz = altAzm.primary() + Angle(180.0);
396 Angle apparentAlt = altAzm.secondary();
397
398 Angle instrumentAz, instrumentAlt;
399 observedToInstrument(apparentAz, apparentAlt, &instrumentAz, &instrumentAlt);
400
401 *primary = instrumentAz;
402 *secondary = instrumentAlt;
403 LOGF_EXTRA1("apparent HaDec to ALTAZ: ha %f, dec %f to pri %f, sec %f", apparentHa.Degrees(), apparentDec.Degrees(), primary->Degrees(),
404 secondary->Degrees() );
405 return; // Prevent fallthrough to equatorial override
406 }
407 // EQ: apply Wallace pointing-model correction in HA/Dec space, then delegate axis mapping.
408 // (For ALTAZ the correction is applied in Az/Alt space above, before the early return.)
409 Angle instrumentHa, instrumentDec;
410 observedToInstrument(apparentHa, apparentDec, &instrumentHa, &instrumentDec);
411 instrumentHaDecToMount(instrumentHa, instrumentDec, primary, secondary);
412 LOGF_EXTRA1("apparent HaDec to EQ: ha %f, dec %f to pri %f, sec %f", apparentHa.Degrees(), apparentDec.Degrees(), primary->Degrees(),
413 secondary->Degrees() );
414}
415
416void Alignment::apparentRaDecToMount(Angle apparentRa, Angle apparentDec, Angle* primary, Angle* secondary)
417{
418 Angle ha = lst() - apparentRa;
419 apparentHaDecToMount(ha, apparentDec, primary, secondary);
420 LOGF_EXTRA1("apparent RaDec to mount: ra %f, ha %f, dec %f to pri %f, sec %f", apparentRa.Degrees(), ha.Degrees(), apparentDec.Degrees(),
421 primary->Degrees(), secondary->Degrees());
422}
423
424#define NEW
425
426void Alignment::instrumentToObserved(Angle instrumentHa, Angle instrumentDec, Angle * observedHa, Angle* observedDec)
427{
428 static Angle maxDec = Angle(89);
429
430 // do the corrections consecutively
431 // apply Ha and Dec zero offsets
432 *observedHa = instrumentHa + IH;
433 *observedDec = instrumentDec + ID;
434
435 // apply collimation (cone) error, limited to CH * 10
436 double cosDec = *observedDec < maxDec ? std::cos(observedDec->radians()) : std::cos(maxDec.radians());
437 double tanDec = *observedDec < maxDec ? std::tan(observedDec->radians()) : std::tan(maxDec.radians());
438
439 *observedHa += (CH / cosDec);
440 // apply Ha and Dec axis non perpendiculary, limited to NP * 10
441 *observedHa += (NP * tanDec);
442
443 // Use rotations so the corrections work at the pole
444 // apply polar axis Azimuth error using rotation in the East, West, Pole plane (X)
445 Vector vMa = Vector(*observedHa, *observedDec).rotateX(MA);
446
447 // apply polar axis elevation error using rotation in the North, South, Pole plane (Y)
448 Vector vMe = vMa.rotateY(Angle(ME));
449
450 *observedHa = vMe.primary();
451 *observedDec = vMe.secondary();
452}
453
454void Alignment::observedToInstrument(Angle observedHa, Angle observedDec, Angle * instrumentHa, Angle *instrumentDec)
455{
456#ifdef NEW
457
458 // avoid errors near dec 90 by limiting sec and tan dec to 57
459 static Angle maxDec = Angle(89);
460
461 // do the corrections consecutively
462 // use vector rotations for MA and ME so they work close to the pole
463 // rotate about the EW axis (Y)
464 Vector vMe = Vector(observedHa, observedDec).rotateY(Angle(-ME));
465
466 // apply polar axis Azimuth error
467 Vector vMa = vMe.rotateX(-MA);
468
469 *instrumentHa = vMa.primary();
470 *instrumentDec = vMa.secondary();
471
472 // apply Ha and Dec axis non perpendiculary, limited to maxDec
473 double tanDec = *instrumentDec < maxDec ? std::tan(instrumentDec->radians()) : std::tan(maxDec.radians());
474 *instrumentHa -= (NP * tanDec);
475 // apply collimation (cone) error, limited to maxDec
476 double cosDec = *instrumentDec < maxDec ? std::cos(instrumentDec->radians()) : std::cos(maxDec.radians());
477 *instrumentHa -= (CH / cosDec);
478
479 // apply Ha and Dec zero offsets
480 *instrumentHa -= IH;
481 *instrumentDec -= ID;
482
483#else
484
485
486 Angle correctionHa, correctionDec;
487 correction(observedHa, observedDec, &correctionHa, &correctionDec);
488 // subtract the correction to get a first pass at the instrument
489 *instrumentHa = observedHa - correctionHa;
490 *instrumentDec = observedDec - correctionDec;
491
492 static const Angle minDelta(1.0 / 3600.0); // 1.0 arc seconds
493 Angle dHa(180);
494 Angle dDec(180);
495 int num = 0;
496 while ( num < 10)
497 {
498 // use the previously calculated instrument to get a new position
499 Angle newHa, newDec;
500 correction(*instrumentHa, *instrumentDec, &correctionHa, &correctionDec);
501 newHa = *instrumentHa + correctionHa;
502 newDec = *instrumentDec + correctionDec;
503 // get the deltas
504 dHa = observedHa - newHa;
505 dDec = observedDec - newDec;
506 // LOGF_DEBUG("observedToInstrument %i: observed %f, %f, new %f, %f, delta %f, %f", num,
507 // observedHa.Degrees(), observedDec.Degrees(),
508 // newHa.Degrees(), newDec.Degrees(), dHa.Degrees(), dDec.Degrees());
509 if (Angle(fabs(dHa.Degrees())) < minDelta && Angle(fabs(dDec.Degrees())) < minDelta)
510 {
511 return;
512 }
513 // apply the delta
514 *instrumentHa += dHa;
515 *instrumentDec += dDec;
516 num++;
517 }
518 LOGF_DEBUG("mountToObserved iterations %i, delta %f, %f", num, dHa.Degrees(), dDec.Degrees());
519#endif
520}
521
522// corrections based on the instrument position, add to instrument to get observed
523// see Patrick Wallace's white paper for details
524void Alignment::correction(Angle instrumentHa, Angle instrumentDec, Angle * correctionHa, Angle * correctionDec)
525{
526 // apply Ha and Dec zero offsets
527 *correctionHa = IH;
528 *correctionDec = ID;
529
530 // avoid errors near dec 90 by limiting sec and tan dec to 100
531 static const double minCos = 0.01;
532 static const double maxTan = 100.0;
533
534 double cosDec = std::cos(instrumentDec.radians());
535 if (cosDec >= 0 && cosDec < minCos) cosDec = minCos;
536 else if (cosDec <= 0 && cosDec > -minCos) cosDec = -minCos;
537
538 double tanDec = std::tan(instrumentDec.radians());
539 if (tanDec > maxTan) tanDec = maxTan;
540 if (tanDec < -maxTan) tanDec = -maxTan;
541
542 double cosHa = std::cos(instrumentHa.radians());
543 double sinHa = std::sin(instrumentHa.radians());
544
545 // apply collimation (cone) error, limited to CH * 10
546 *correctionHa += (CH / cosDec);
547 // apply Ha and Dec axis non perpendiculary, limited to NP * 10
548 *correctionHa += (NP * tanDec);
549
550 // apply polar axis Azimuth error
551 *correctionHa += (-MA * cosHa * tanDec);
552 *correctionDec += (MA * sinHa);
553
554 // apply polar axis elevation error
555 *correctionHa += (ME * sinHa * tanDec);
556 *correctionDec += (ME * cosHa);
557
558 LOGF_EXTRA1("correction %f, %f", correctionHa->Degrees(), correctionDec->Degrees());
559}
560
561#ifdef FALSE
563{
564 // rotate by IH and ID
565 Vector vIh = HaDec.rotateZ(Angle(IH));
566 Vector vId = vIh.rotateX(Angle(ID));
567}
568#endif
569
570void Alignment::setCorrections(double ih, double id, double ch, double np, double ma, double me)
571{
572 IH = ih;
573 ID = id;
574 CH = ch;
575 NP = np;
576 MA = ma;
577 ME = me;
578 LOGF_DEBUG("setCorrections IH %f, ID %f, CH %f, NP %f, MA %f, ME %f", IH, ID, CH, NP, MA, ME);
579}
580
582
583// Vector methods
584
585Vector::Vector(double x, double y, double z)
586{
587 double len = std::sqrt(x * x + y * y + z * z);
588 L = x / len;
589 M = y / len;
590 N = z / len;
591}
592
593Vector::Vector(Angle primary, Angle secondary)
594{
595 double sp = std::sin(primary.radians());
596 double cp = std::cos(primary.radians());
597 double ss = std::sin(secondary.radians());
598 double cs = std::cos(secondary.radians());
599
600 L = cs * cp;
601 M = cs * sp;
602 N = ss;
603}
604
606{
607 double len = length();
608 L /= len;
609 M /= len;
610 N /= len;
611}
612
614{
615 Angle a = Angle(atan2(M, L), Angle::RADIANS);
616 //IDLog("primary %f", a.Degrees());
617 return a;
618}
619
621{
622 Angle a = Angle(std::asin(N), Angle::RADIANS);
623 //IDLog("secondary %f", a.Degrees());
624 return a;
625}
626
628{
629 double ca = std::cos(angle.radians());
630 double sa = std::sin(angle.radians());
631 return Vector(L, M * ca + N * sa, N * ca - M * sa);
632}
633
635{
636 double ca = std::cos(angle.radians());
637 double sa = std::sin(angle.radians());
638 return Vector(L * ca - N * sa, M, L * sa + N * ca);
639}
640
642{
643 double ca = std::cos(angle.radians());
644 double sa = std::sin(angle.radians());
645 return Vector(L * ca + M * sa, M * ca - L * sa, N);
646}
void setCorrections(double ih, double id, double ch, double np, double ma, double me)
setCorrections set the values of the six corrections
double julianDate()
void instrumentHaDecToMount(Angle instrumentHa, Angle instrumentDec, Angle *primary, Angle *secondary)
void apparentRaDecToMount(Angle apparentRa, Angle apparentDec, Angle *primary, Angle *secondary)
void mountToApparentHaDec(Angle primary, Angle secondary, Angle *apparentHa, Angle *apparentDec)
mountToApparentHaDec: convert mount position to apparent Ha, Dec
void apparentHaDecToMount(Angle apparentHa, Angle apparentDec, Angle *primary, Angle *secondary)
apparentHaDecToMount
double clockOffsetDays
void observedToInstrument(Angle observedHa, Angle observedDec, Angle *instrumentHa, Angle *instrumentDec)
void mountToApparentRaDec(Angle primary, Angle secondary, Angle *apparentRa, Angle *apparentDec)
mountToApparentRaDec: convert mount position to apparent Ra, Dec
void instrumentToObserved(Angle instrumentHa, Angle instrumentDec, Angle *observedHa, Angle *observedDec)
MOUNT_TYPE mountType
void mountToInstrumentHaDec(Angle primary, Angle secondary, Angle *instrumentHa, Angle *instrumentDec)
mountToInstrumentHaDec: convert mount axis positions to instrument (encoder) HA/Dec without applying ...
The Angle class This class implements an angle type. This holds an angle that is always in the range ...
double Degrees360()
Degrees360.
double difference(Angle a)
double radians()
radians
bool operator==(const Angle &a)
bool operator!=(const Angle &a)
double Degrees()
Degrees.
Angle TrackingRateDegSec
TrackingRateDegSec.
bool isSlewing
const char * axisName
void setDegrees(double degrees)
void StartGuide(double rate, uint32_t durationMs)
StartGuide start guiding.
void Tracking(bool enabled)
AXIS_TRACK_RATE TrackRate()
TrackRate returns the AXIS_TRACK_RATE property.
void StartSlew(Angle angle)
void update()
Angle position
double getTrackingRateDegSec()
bool isTracking()
AXIS_TRACK_RATE
The AXIS_TRACK_RATE enum defines the common track rates.
void setHours(double hours)
The Vector class This implements the Directional Cosine used by Taki in his Matrix method....
Vector rotateY(Angle angle)
rotateY rotates this vector through angle about the Y axis
Vector rotateX(Angle angle)
rotateX rotates this vector through angle about the X axis
double length()
Vector()
Vector creates an empty vector.
Vector rotateZ(Angle angle)
rotateZ rotates this vector through angle about the Z axis
void normalise()
Angle secondary()
secondary returns the secondary angle (dec, altitude) from this vector
Angle primary()
primary returns the primary angle (Ra, Ha, Azimuth) from this vector
#define M_PI
Definition dsp.h:52
double range24(double r)
range24 Limits a number to be between 0-24 range.
Definition indicom.c:1311
Implementations for common driver routines.
char * me
Definition indidriver.c:50
#define LOGF_DEBUG(fmt,...)
Definition indilogger.h:83
#define LOGF_ERROR(fmt,...)
Definition indilogger.h:80
#define LOGF_EXTRA1(fmt,...)
Definition indilogger.h:84
uint16_t type
Definition pwc-ioctl.h:0
char device_str[64]
The transformations are based on the paper "Matrix Method for Coordinates Transformation" written by ...