Kstars

gmath.cpp
1/*
2 SPDX-FileCopyrightText: 2012 Andrew Stepanenko
3
4 Modified by Jasem Mutlaq <mutlaqja@ikarustech.com> for KStars:
5 SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9
10#include "gmath.h"
11
12#include "Options.h"
13#include "fitsviewer/fitsdata.h"
14#include "fitsviewer/fitsview.h"
15#include "auxiliary/kspaths.h"
16#include "ekos_guide_debug.h"
17#include "ekos/auxiliary/stellarsolverprofileeditor.h"
18#include "guidealgorithms.h"
19#include "guidelog.h"
20#include "../guideview.h"
21
22#include <QVector3D>
23#include <cmath>
24#include <set>
25
26// Qt version calming
27#include <qtendl.h>
28
29#include <QRandomGenerator>
30namespace
31{
32QRandomGenerator generator;
33double getNoise(double maxAbsVal)
34{
35 return (maxAbsVal - generator.bounded(maxAbsVal * 2));
36}
37}
38GuiderUtils::Vector cgmath::findLocalStarPosition(QSharedPointer<FITSData> &imageData,
39 QSharedPointer<GuideView> &guideView, bool firstFrame)
40{
41 GuiderUtils::Vector position;
42 if (usingSEPMultiStar())
43 {
44 QRect trackingBox = guideView->getTrackingBox();
45 position = guideStars.findGuideStar(imageData, trackingBox, guideView, firstFrame);
46
47 }
48 else
49 position = GuideAlgorithms::findLocalStarPosition(
50 imageData, algorithm, video_width, video_height,
51 guideView->getTrackingBox());
52
53 if (position.x == -1 || position.y == -1)
54 setLostStar(true);
55 return position;
56}
57
58
59cgmath::cgmath() : QObject()
60{
61 // sky coord. system vars.
62 starPosition = GuiderUtils::Vector(0);
63 targetPosition = GuiderUtils::Vector(0);
64
65 // processing
66 in_params.reset();
67 out_params.reset();
68 driftUpto[GUIDE_RA] = driftUpto[GUIDE_DEC] = 0;
69 drift[GUIDE_RA] = new double[CIRCULAR_BUFFER_SIZE];
70 drift[GUIDE_DEC] = new double[CIRCULAR_BUFFER_SIZE];
71 memset(drift[GUIDE_RA], 0, sizeof(double) * CIRCULAR_BUFFER_SIZE);
72 memset(drift[GUIDE_DEC], 0, sizeof(double) * CIRCULAR_BUFFER_SIZE);
73 drift_integral[GUIDE_RA] = drift_integral[GUIDE_DEC] = 0;
74
75 logFile.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath("guide_log.txt"));
76 gpg.reset(new GPG());
77}
78
79cgmath::~cgmath()
80{
81 delete[] drift[GUIDE_RA];
82 delete[] drift[GUIDE_DEC];
83}
84
85bool cgmath::setVideoParameters(int vid_wd, int vid_ht, int binX, int binY)
86{
87 if (vid_wd <= 0 || vid_ht <= 0)
88 return false;
89
90 video_width = vid_wd / binX;
91 video_height = vid_ht / binY;
92
93 calibration.setBinningUsed(binX, binY);
94 guideStars.setCalibration(calibration);
95
96 return true;
97}
98
99bool cgmath::setGuiderParameters(double ccd_pix_wd, double ccd_pix_ht, double guider_aperture, double guider_focal)
100{
101 if (ccd_pix_wd < 0)
102 ccd_pix_wd = 0;
103 if (ccd_pix_ht < 0)
104 ccd_pix_ht = 0;
105 if (guider_focal <= 0)
106 guider_focal = 1;
107
108 aperture = guider_aperture;
109 guideStars.setCalibration(calibration);
110
111 return true;
112}
113
114// This logging will be removed in favor of guidelog.h.
115void cgmath::createGuideLog()
116{
117 logFile.close();
119 QTextStream out(&logFile);
120
121 out << "Guiding rate,x15 arcsec/sec: " << Qt::endl;
122 out << "Focal,mm: " << calibration.getFocalLength() << Qt::endl;
123 out << "Aperture,mm: " << aperture << Qt::endl;
124 out << "F/D: " << calibration.getFocalLength() / aperture << Qt::endl;
125 out << "Frame #, Time Elapsed (ms), RA Error (arcsec), RA Correction (ms), RA Correction Direction, DEC Error "
126 "(arcsec), DEC Correction (ms), DEC Correction Direction"
127 << Qt::endl;
128
129 logTime.restart();
130}
131
132bool cgmath::setTargetPosition(double x, double y)
133{
134 // check frame ranges
135 if (x < 0)
136 x = 0;
137 if (y < 0)
138 y = 0;
139 if (x >= (double)video_width - 1)
140 x = (double)video_width - 1;
141 if (y >= (double)video_height - 1)
142 y = (double)video_height - 1;
143
144 targetPosition = GuiderUtils::Vector(x, y, 0);
145
146 guideStars.setCalibration(calibration);
147
148 return true;
149}
150
151bool cgmath::getTargetPosition(double *x, double *y) const
152{
153 *x = targetPosition.x;
154 *y = targetPosition.y;
155 return true;
156}
157
158int cgmath::getAlgorithmIndex(void) const
159{
160 return algorithm;
161}
162
163void cgmath::getStarScreenPosition(double *dx, double *dy) const
164{
165 *dx = starPosition.x;
166 *dy = starPosition.y;
167}
168
169bool cgmath::reset()
170{
171 iterationCounter = 0;
172 driftUpto[GUIDE_RA] = driftUpto[GUIDE_DEC] = 0;
173 drift_integral[GUIDE_RA] = drift_integral[GUIDE_DEC] = 0;
174 out_params.reset();
175
176 memset(drift[GUIDE_RA], 0, sizeof(double) * CIRCULAR_BUFFER_SIZE);
177 memset(drift[GUIDE_DEC], 0, sizeof(double) * CIRCULAR_BUFFER_SIZE);
178
179 return true;
180}
181
182void cgmath::setAlgorithmIndex(int algorithmIndex)
183{
184 if (algorithmIndex < 0 || algorithmIndex > SEP_MULTISTAR)
185 return;
186
187 algorithm = algorithmIndex;
188}
189
190bool cgmath::usingSEPMultiStar() const
191{
192 return algorithm == SEP_MULTISTAR;
193}
194
195void cgmath::updateCircularBuffers(void)
196{
197 iterationCounter++;
198
199 driftUpto[GUIDE_RA]++;
200 driftUpto[GUIDE_DEC]++;
201 if (driftUpto[GUIDE_RA] >= CIRCULAR_BUFFER_SIZE)
202 driftUpto[GUIDE_RA] = 0;
203 if (driftUpto[GUIDE_DEC] >= CIRCULAR_BUFFER_SIZE)
204 driftUpto[GUIDE_DEC] = 0;
205}
206
207//-------------------- Processing ---------------------------
208void cgmath::start()
209{
210 iterationCounter = 0;
211 driftUpto[GUIDE_RA] = driftUpto[GUIDE_DEC] = 0;
212 drift_integral[GUIDE_RA] = drift_integral[GUIDE_DEC] = 0;
213 out_params.reset();
214
215 memset(drift[GUIDE_RA], 0, sizeof(double) * CIRCULAR_BUFFER_SIZE);
216 memset(drift[GUIDE_DEC], 0, sizeof(double) * CIRCULAR_BUFFER_SIZE);
217
218 if (calibration.getFocalLength() > 0 && aperture > 0)
219 createGuideLog();
220
221 gpg->reset();
222}
223
224void cgmath::abort()
225{
226 guideStars.reset();
227}
228
229void cgmath::suspend(bool mode)
230{
231 suspended = mode;
232}
233
234bool cgmath::isSuspended() const
235{
236 return suspended;
237}
238
239bool cgmath::isStarLost() const
240{
241 return lost_star;
242}
243
244void cgmath::setLostStar(bool is_lost)
245{
246 lost_star = is_lost;
247}
248
249namespace
250{
251QString axisStr(int raDEC)
252{
253 if (raDEC == GUIDE_RA)
254 return "RA";
255 else if (raDEC == GUIDE_DEC)
256 return "DEC";
257 else
258 return "???";
259}
260
261const QString directionStr(GuideDirection dir)
262{
263 switch (dir)
264 {
265 case RA_DEC_DIR:
266 return "Decrease RA";
267 case RA_INC_DIR:
268 return "Increase RA";
269 case DEC_DEC_DIR:
270 return "Decrease DEC";
271 case DEC_INC_DIR:
272 return "Increase DEC";
273 default:
274 return "NO DIR";
275 }
276}
277} // namespace
278
279bool cgmath::configureInParams(Ekos::GuideState state)
280{
281 const bool dithering = state == Ekos::GuideState::GUIDE_DITHERING;
282
283 if (!dithering)
284 {
285 in_params.proportional_gain[0] = Options::rAProportionalGain();
286 in_params.proportional_gain[1] = Options::dECProportionalGain();
287
288 in_params.integral_gain[0] = Options::rAIntegralGain();
289 in_params.integral_gain[1] = Options::dECIntegralGain();
290
291 // Always pulse if we're dithering.
292 in_params.enabled[0] = Options::rAGuideEnabled();
293 in_params.enabled[1] = Options::dECGuideEnabled();
294
295 in_params.min_pulse_arcsec[0] = Options::rAMinimumPulseArcSec();
296 in_params.min_pulse_arcsec[1] = Options::dECMinimumPulseArcSec();
297
298 in_params.max_pulse_arcsec[0] = Options::rAMaximumPulseArcSec();
299 in_params.max_pulse_arcsec[1] = Options::dECMaximumPulseArcSec();
300
301 // RA W/E enable (but always pulse if dithering).
302 // East RA+ enabled?
303 in_params.enabled_axis1[0] = Options::eastRAGuideEnabled();
304 // West RA- enabled?
305 in_params.enabled_axis2[0] = Options::westRAGuideEnabled();
306
307 // DEC N/S enable (but always pulse if dithering).
308 // North DEC+ enabled?
309 in_params.enabled_axis1[1] = Options::northDECGuideEnabled();
310 // South DEC- enabled?
311 in_params.enabled_axis2[1] = Options::southDECGuideEnabled();
312 }
313 else
314 {
315 // If we're dithering, enable all axes and use full pulses.
316 in_params.proportional_gain[0] = 1.0;
317 in_params.proportional_gain[1] = 1.0;
318 in_params.integral_gain[0] = 0.0;
319 in_params.integral_gain[1] = 0.0;
320 in_params.min_pulse_arcsec[0] = 0.0;
321 in_params.min_pulse_arcsec[1] = 0.0;
322 in_params.max_pulse_arcsec[0] = Options::rAMaximumPulseArcSec();
323 in_params.max_pulse_arcsec[1] = Options::dECMaximumPulseArcSec();
324 in_params.enabled[0] = true;
325 in_params.enabled[1] = true;
326 in_params.enabled_axis1[0] = true;
327 in_params.enabled_axis2[0] = true;
328 in_params.enabled_axis1[1] = true;
329 in_params.enabled_axis2[1] = true;
330 }
331
332 return dithering;
333}
334
335void cgmath::updateOutParams(int k, const double arcsecDrift, int pulseLength, GuideDirection pulseDirection)
336{
337 out_params.pulse_dir[k] = pulseDirection;
338 out_params.pulse_length[k] = pulseLength;
339 out_params.delta[k] = arcsecDrift;
340}
341
342void cgmath::outputGuideLog()
343{
344 if (Options::guideLogging())
345 {
346 QTextStream out(&logFile);
347 out << iterationCounter << "," << logTime.elapsed() << "," << out_params.delta[0] << "," << out_params.pulse_length[0] <<
348 ","
349 << directionStr(out_params.pulse_dir[0]) << "," << out_params.delta[1] << ","
350 << out_params.pulse_length[1] << "," << directionStr(out_params.pulse_dir[1]) << Qt::endl;
351 }
352}
353
354void cgmath::processAxis(const int k, const bool dithering, const bool darkGuide, const Seconds &timeStep,
355 const QString &label)
356{
357 // zero all out commands
358 GuideDirection pulseDirection = NO_DIR;
359 int pulseLength = 0; // milliseconds
360 GuideDirection dir;
361
362 // Get the drift for this axis
363 const int idx = driftUpto[k];
364 const double arcsecDrift = drift[k][idx];
365
366 const double pulseConverter = (k == GUIDE_RA) ?
367 calibration.raPulseMillisecondsPerArcsecond() :
368 calibration.decPulseMillisecondsPerArcsecond();
369 const double maxPulseMilliseconds = in_params.max_pulse_arcsec[k] * pulseConverter;
370
371 // GPG pulse computation
372 bool useGPG = !dithering && Options::gPGEnabled() && (k == GUIDE_RA) && in_params.enabled[k];
373 if (useGPG && darkGuide)
374 {
375 gpg->darkGuiding(&pulseLength, &dir, calibration, timeStep);
376 pulseDirection = dir;
377 }
378 else if (darkGuide)
379 {
380 // We should not be dark guiding without GPG
381 qCDebug(KSTARS_EKOS_GUIDE) << "Warning: dark guiding without GPG or while dithering.";
382 return;
383 }
384 else if (useGPG && gpg->computePulse(arcsecDrift,
385 usingSEPMultiStar() ? &guideStars : nullptr, &pulseLength, &dir, calibration, timeStep))
386 {
387 pulseDirection = dir;
388 pulseLength = std::min(pulseLength, static_cast<int>(maxPulseMilliseconds + 0.5));
389 }
390 else
391 {
392 // This is the main non-GPG guide-pulse computation.
393 // Traditionally it was hardwired so that proportional_gain=133 was about a control gain of 1.0
394 // This is now in the 0.0 - 1.0 range, and multiplies the calibrated mount performance.
395
396 // Compute the average drift in the recent past for the integral control term.
397 drift_integral[k] = 0;
398 for (int i = 0; i < CIRCULAR_BUFFER_SIZE; ++i)
399 drift_integral[k] += drift[k][i];
400 drift_integral[k] /= (double)CIRCULAR_BUFFER_SIZE;
401
402 if (in_params.integral_gain[k] > 0)
403 qCDebug(KSTARS_EKOS_GUIDE) << label << "drift[" << axisStr(k) << "] = " << arcsecDrift
404 << " integral[" << axisStr(k) << "] = " << drift_integral[k];
405
406 const double arcsecPerMsPulse = k == GUIDE_RA ? calibration.raPulseMillisecondsPerArcsecond() :
407 calibration.decPulseMillisecondsPerArcsecond();
408 const double proportionalResponse = arcsecDrift * in_params.proportional_gain[k] * arcsecPerMsPulse;
409 const double integralResponse = drift_integral[k] * in_params.integral_gain[k] * arcsecPerMsPulse;
410 pulseLength = std::min(fabs(proportionalResponse + integralResponse), maxPulseMilliseconds);
411
412 // calc direction
413 // We do not send pulse if direction is disabled completely, or if direction in a specific axis (e.g. N or S) is disabled
414 if (!in_params.enabled[k] || // This axis not enabled
415 // Positive direction of this axis not enabled.
416 (arcsecDrift > 0 && !in_params.enabled_axis1[k]) ||
417 // Negative direction of this axis not enabled.
418 (arcsecDrift < 0 && !in_params.enabled_axis2[k]))
419 {
420 pulseDirection = NO_DIR;
421 pulseLength = 0;
422 }
423 else
424 {
425 // Check the min pulse value, and assign the direction.
426 const double pulseArcSec = pulseConverter > 0 ? pulseLength / pulseConverter : 0;
427 if (pulseArcSec >= in_params.min_pulse_arcsec[k])
428 {
429 if (k == GUIDE_RA)
430 pulseDirection = arcsecDrift > 0 ? RA_DEC_DIR : RA_INC_DIR;
431 else
432 pulseDirection = arcsecDrift > 0 ? DEC_DEC_DIR : DEC_INC_DIR;
433 }
434 else
435 pulseDirection = NO_DIR;
436 }
437
438 }
439 updateOutParams(k, arcsecDrift, pulseLength, pulseDirection);
440}
441
442void cgmath::calculatePulses(Ekos::GuideState state, const std::pair<Seconds, Seconds> &timeStep)
443{
444 const bool dithering = configureInParams(state);
445
446 processAxis(GUIDE_RA, dithering, false, timeStep.first, "Guiding:");
447 processAxis(GUIDE_DEC, dithering, false, timeStep.second, "Guiding:");
448
449 qCDebug(KSTARS_EKOS_GUIDE)
450 << QString("Guiding pulses: RA: %1ms %2 DEC: %3ms %4")
451 .arg(out_params.pulse_length[GUIDE_RA]).arg(directionStr(out_params.pulse_dir[GUIDE_RA]))
452 .arg(out_params.pulse_length[GUIDE_DEC]).arg(directionStr(out_params.pulse_dir[GUIDE_DEC]));
453
454 outputGuideLog();
455}
456
457void cgmath::performProcessing(Ekos::GuideState state, QSharedPointer<FITSData> &imageData,
458 QSharedPointer<GuideView> &guideView,
459 const std::pair<Seconds, Seconds> &timeStep, GuideLog * logger)
460{
461 if (suspended)
462 {
463 if (Options::gPGEnabled())
464 {
465 GuiderUtils::Vector guideStarPosition = findLocalStarPosition(imageData, guideView, false);
466 if (guideStarPosition.x != -1 && !std::isnan(guideStarPosition.x))
467 {
468 gpg->suspended(guideStarPosition, targetPosition,
469 usingSEPMultiStar() ? &guideStars : nullptr, calibration);
470 }
471 }
472 // do nothing if suspended
473 return;
474 }
475
476 QElapsedTimer timer;
477 timer.start();
478 GuiderUtils::Vector starPositionArcSec, targetPositionArcSec;
479
480 // find guiding star location in the image
481 starPosition = findLocalStarPosition(imageData, guideView, false);
482
483 // If no star found, mark as lost star.
484 if (starPosition.x == -1 || std::isnan(starPosition.x))
485 {
486 setLostStar(true);
487 if (logger != nullptr && state == Ekos::GUIDE_GUIDING)
488 {
489 GuideLog::GuideData data;
490 data.code = GuideLog::GuideData::NO_STAR_FOUND;
491 data.type = GuideLog::GuideData::DROP;
492 logger->addGuideData(data);
493 }
494 return;
495 }
496 else
497 setLostStar(false);
498
499 // Emit the detected star center
500 QVector3D starCenter(starPosition.x, starPosition.y, 0);
501 emit newStarPosition(starCenter, true);
502
503 // If we're only calibrating, then we're done.
504 if (state == Ekos::GUIDE_CALIBRATING)
505 return;
506
507 if (state == Ekos::GUIDE_GUIDING && (targetPosition.x <= 0.0 || targetPosition.y <= 0.0))
508 {
509 qCDebug(KSTARS_EKOS_GUIDE) << "Guiding with target 0.0 -- something's wrong!!!!!!!!!!!";
510 for (int k = GUIDE_RA; k <= GUIDE_DEC; k++)
511 {
512 out_params.pulse_dir[k] = NO_DIR;
513 out_params.pulse_length[k] = 0;
514 out_params.delta[k] = 0;
515 setLostStar(true);
516 }
517 return;
518 }
519 // translate star coords into sky coord. system
520
521 // convert from pixels into arcsecs
522 starPositionArcSec = calibration.convertToArcseconds(starPosition);
523 targetPositionArcSec = calibration.convertToArcseconds(targetPosition);
524
525 // Compute RA & DEC drift in arcseconds.
526 const GuiderUtils::Vector star_xy_arcsec_drift = starPositionArcSec - targetPositionArcSec;
527 const GuiderUtils::Vector star_drift = calibration.rotateToRaDec(star_xy_arcsec_drift);
528
529 // both coords are ready for math processing
530 // put coord to drift list
531 // Note: if we're not guiding, these will be overwritten,
532 // as driftUpto is only incremented when guiding.
533 drift[GUIDE_RA][driftUpto[GUIDE_RA]] = star_drift.x;
534 drift[GUIDE_DEC][driftUpto[GUIDE_DEC]] = star_drift.y;
535
536 qCDebug(KSTARS_EKOS_GUIDE)
537 << QString("Star %1 %2 a-s %3 %4 Target %5 %6 a-s %7 %8 Drift: RA %9 DEC %10")
538 .arg(starPosition.x, 0, 'f', 1) .arg(starPosition.y, 0, 'f', 1)
539 .arg(starPositionArcSec.x, 0, 'f', 1) .arg(starPositionArcSec.y, 0, 'f', 1)
540 .arg(targetPosition.x, 0, 'f', 1) .arg(targetPosition.y, 0, 'f', 1)
541 .arg(targetPositionArcSec.x, 0, 'f', 1).arg(targetPositionArcSec.y, 0, 'f', 1)
542 .arg(star_drift.x, 0, 'f', 2) .arg(star_drift.y, 0, 'f', 2);
543
544 if (state == Ekos::GUIDE_GUIDING && usingSEPMultiStar())
545 {
546 double multiStarRADrift, multiStarDECDrift;
547 if (guideStars.getDrift(sqrt(star_drift.x * star_drift.x + star_drift.y * star_drift.y),
548 targetPosition.x, targetPosition.y,
549 &multiStarRADrift, &multiStarDECDrift))
550 {
551#ifdef DEBUG_ADD_NOISE
552 const double raNoise = getNoise(.75);
553 const double decNoise = getNoise(.75);
554 multiStarRADrift += raNoise;
555 multiStarDECDrift += decNoise;
556 qCDebug(KSTARS_EKOS_GUIDE)
557 << "Added guide noise arcsecs" << "RA" << raNoise << "DEC" << decNoise;
558 fprintf(stderr, "Add guide noise arcsecs %.1f %.1f\n", raNoise, decNoise);
559#endif
560 qCDebug(KSTARS_EKOS_GUIDE) << QString("MultiStar drift: RA %1 DEC %2")
561 .arg(multiStarRADrift, 0, 'f', 2)
562 .arg(multiStarDECDrift, 0, 'f', 2);
563 drift[GUIDE_RA][driftUpto[GUIDE_RA]] = multiStarRADrift;
564 drift[GUIDE_DEC][driftUpto[GUIDE_DEC]] = multiStarDECDrift;
565 }
566 else
567 {
568 qCDebug(KSTARS_EKOS_GUIDE) << "MultiStar: failed, fell back to guide star";
569 }
570 }
571
572 // driftUpto will change when the circular buffer is updated,
573 // so save the values for logging.
574 const double raDrift = drift[GUIDE_RA][driftUpto[GUIDE_RA]];
575 const double decDrift = drift[GUIDE_DEC][driftUpto[GUIDE_DEC]];
576
577 // make decision by axes
578 calculatePulses(state, timeStep);
579
580 if (state == Ekos::GUIDE_GUIDING)
581 {
582 calculateRmsError();
583 emitStats();
584 updateCircularBuffers();
585 }
586 qCDebug(KSTARS_EKOS_GUIDE) << QString("performProcessing took %1s").arg(timer.elapsed() / 1000.0, 0, 'f', 3);
587
588 if (logger != nullptr)
589 {
590 GuideLog::GuideData data;
591 data.type = GuideLog::GuideData::MOUNT;
592 // These are distances in pixels.
593 // Note--these don't include the multistar algorithm, but the below ra/dec ones do.
594 data.dx = starPosition.x - targetPosition.x;
595 data.dy = starPosition.y - targetPosition.y;
596 // Above computes position - reticle. Should the reticle-position, so negate.
597 calibration.convertToPixels(-raDrift, -decDrift, &data.raDistance, &data.decDistance);
598
599 const double raGuideFactor = out_params.pulse_dir[GUIDE_RA] == NO_DIR ?
600 0 : (out_params.pulse_dir[GUIDE_RA] == RA_INC_DIR ? 1.0 : -1.0);
601 const double decGuideFactor = out_params.pulse_dir[GUIDE_DEC] == NO_DIR ?
602 0 : (out_params.pulse_dir[GUIDE_DEC] == DEC_INC_DIR ? 1.0 : -1.0);
603
604 // Phd2LogViewer wants these in pixels instead of arcseconds, so normalizing them, but
605 // that will be wrong for non-square pixels. They should really accept arcsecond units.
606 data.raGuideDistance = calibration.xPixelsPerArcsecond() * raGuideFactor * out_params.pulse_length[GUIDE_RA] /
607 calibration.raPulseMillisecondsPerArcsecond();
608 data.decGuideDistance = calibration.yPixelsPerArcsecond() * decGuideFactor * out_params.pulse_length[GUIDE_DEC] /
609 calibration.decPulseMillisecondsPerArcsecond();
610
611 data.raDuration = out_params.pulse_dir[GUIDE_RA] == NO_DIR ? 0 : out_params.pulse_length[GUIDE_RA];
612 data.raDirection = out_params.pulse_dir[GUIDE_RA];
613 data.decDuration = out_params.pulse_dir[GUIDE_DEC] == NO_DIR ? 0 : out_params.pulse_length[GUIDE_DEC];
614 data.decDirection = out_params.pulse_dir[GUIDE_DEC];
615 data.code = GuideLog::GuideData::NO_ERRORS;
616 data.snr = guideStars.getGuideStarSNR();
617 data.mass = guideStars.getGuideStarMass();
618 // Add SNR and MASS from SEP stars.
619 logger->addGuideData(data);
620 }
621}
622
623void cgmath::performDarkGuiding(Ekos::GuideState state, const std::pair<Seconds, Seconds> &timeStep)
624{
625
626 const bool dithering = configureInParams(state);
627 //out_params.sigma[GUIDE_RA] = 0;
628
629 processAxis(GUIDE_RA, dithering, true, timeStep.first, "Dark Guiding:");
630 qCDebug(KSTARS_EKOS_GUIDE)
631 << QString("Dark Guiding pulses: RA: %1ms %2")
632 .arg(out_params.pulse_length[GUIDE_RA]).arg(directionStr(out_params.pulse_dir[GUIDE_RA]));
633
634
635 // Don't guide in DEC when dark guiding
636 updateOutParams(GUIDE_DEC, 0, 0, NO_DIR);
637
638 outputGuideLog();
639}
640
641void cgmath::emitStats()
642{
643 double pulseRA = 0;
644 if (out_params.pulse_dir[GUIDE_RA] == RA_DEC_DIR)
645 pulseRA = out_params.pulse_length[GUIDE_RA];
646 else if (out_params.pulse_dir[GUIDE_RA] == RA_INC_DIR)
647 pulseRA = -out_params.pulse_length[GUIDE_RA];
648 double pulseDEC = 0;
649 if (out_params.pulse_dir[GUIDE_DEC] == DEC_DEC_DIR)
650 pulseDEC = -out_params.pulse_length[GUIDE_DEC];
651 else if (out_params.pulse_dir[GUIDE_DEC] == DEC_INC_DIR)
652 pulseDEC = out_params.pulse_length[GUIDE_DEC];
653
654 const bool hasGuidestars = usingSEPMultiStar();
655 const double snr = hasGuidestars ? guideStars.getGuideStarSNR() : 0;
656 const double skyBG = hasGuidestars ? guideStars.skybackground().mean : 0;
657 const int numStars = hasGuidestars ? guideStars.skybackground().starsDetected : 0; // wait for rob's release
658
659 emit guideStats(-out_params.delta[GUIDE_RA], -out_params.delta[GUIDE_DEC],
660 pulseRA, pulseDEC, snr, skyBG, numStars);
661}
662
663void cgmath::calculateRmsError(void)
664{
665 if (!do_statistics)
666 return;
667
668 if (iterationCounter == 0)
669 return;
670
671 int count = std::min(iterationCounter, static_cast<unsigned int>(CIRCULAR_BUFFER_SIZE));
672 for (int k = GUIDE_RA; k <= GUIDE_DEC; k++)
673 {
674 double sqr_avg = 0;
675 for (int i = 0; i < count; ++i)
676 sqr_avg += drift[k][i] * drift[k][i];
677
678 out_params.sigma[k] = sqrt(sqr_avg / (double)count);
679 }
680}
681
682
683QVector3D cgmath::selectGuideStar(const QSharedPointer<FITSData> &imageData)
684{
685 return guideStars.selectGuideStar(imageData);
686}
687
688double cgmath::getGuideStarSNR()
689{
690 return guideStars.getGuideStarSNR();
691}
692
693//---------------------------------------------------------------------------------------
694cproc_in_params::cproc_in_params()
695{
696 reset();
697}
698
699void cproc_in_params::reset(void)
700{
701 average = true;
702
703 for (int k = GUIDE_RA; k <= GUIDE_DEC; k++)
704 {
705 enabled[k] = true;
706 integral_gain[k] = 0;
707 max_pulse_arcsec[k] = 5000;
708 min_pulse_arcsec[k] = 0;
709 }
710}
711
712cproc_out_params::cproc_out_params()
713{
714 reset();
715}
716
717void cproc_out_params::reset(void)
718{
719 for (int k = GUIDE_RA; k <= GUIDE_DEC; k++)
720 {
721 delta[k] = 0;
722 pulse_dir[k] = NO_DIR;
723 pulse_length[k] = 0;
724 sigma[k] = 0;
725 }
726}
727
KIOCORE_EXPORT QString dir(const QString &fileClass)
QString label(StandardShortcut id)
QCA_EXPORT Logger * logger()
qint64 elapsed() const const
double bounded(double highest)
QTextStream & endl(QTextStream &stream)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Jan 31 2025 11:53:47 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.