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

KDE's Doxygen guidelines are available online.