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,
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{
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{
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;
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,
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 GuiderUtils::Vector starPositionArcSec, targetPositionArcSec;
468
469 // find guiding star location in the image
470 starPosition = findLocalStarPosition(imageData, guideView, false);
471
472 // If no star found, mark as lost star.
473 if (starPosition.x == -1 || std::isnan(starPosition.x))
474 {
475 setLostStar(true);
476 if (logger != nullptr && state == Ekos::GUIDE_GUIDING)
477 {
478 GuideLog::GuideData data;
479 data.code = GuideLog::GuideData::NO_STAR_FOUND;
480 data.type = GuideLog::GuideData::DROP;
481 logger->addGuideData(data);
482 }
483 return;
484 }
485 else
486 setLostStar(false);
487
488 // Emit the detected star center
489 QVector3D starCenter(starPosition.x, starPosition.y, 0);
490 emit newStarPosition(starCenter, true);
491
492 // If we're only calibrating, then we're done.
493 if (state == Ekos::GUIDE_CALIBRATING)
494 return;
495
496 if (state == Ekos::GUIDE_GUIDING && (targetPosition.x <= 0.0 || targetPosition.y <= 0.0))
497 {
498 qCDebug(KSTARS_EKOS_GUIDE) << "Guiding with target 0.0 -- something's wrong!!!!!!!!!!!";
499 for (int k = GUIDE_RA; k <= GUIDE_DEC; k++)
500 {
501 out_params.pulse_dir[k] = NO_DIR;
502 out_params.pulse_length[k] = 0;
503 out_params.delta[k] = 0;
504 setLostStar(true);
505 }
506 return;
507 }
508 // translate star coords into sky coord. system
509
510 // convert from pixels into arcsecs
511 starPositionArcSec = calibration.convertToArcseconds(starPosition);
512 targetPositionArcSec = calibration.convertToArcseconds(targetPosition);
513
514 // Compute RA & DEC drift in arcseconds.
516 const GuiderUtils::Vector star_drift = calibration.rotateToRaDec(star_xy_arcsec_drift);
517
518 // both coords are ready for math processing
519 // put coord to drift list
520 // Note: if we're not guiding, these will be overwritten,
521 // as driftUpto is only incremented when guiding.
522 drift[GUIDE_RA][driftUpto[GUIDE_RA]] = star_drift.x;
523 drift[GUIDE_DEC][driftUpto[GUIDE_DEC]] = star_drift.y;
524
525 qCDebug(KSTARS_EKOS_GUIDE)
526 << QString("Star %1 %2 a-s %3 %4 Target %5 %6 a-s %7 %8 Drift: RA %9 DEC %10")
527 .arg(starPosition.x, 0, 'f', 1) .arg(starPosition.y, 0, 'f', 1)
528 .arg(starPositionArcSec.x, 0, 'f', 1) .arg(starPositionArcSec.y, 0, 'f', 1)
529 .arg(targetPosition.x, 0, 'f', 1) .arg(targetPosition.y, 0, 'f', 1)
530 .arg(targetPositionArcSec.x, 0, 'f', 1).arg(targetPositionArcSec.y, 0, 'f', 1)
531 .arg(star_drift.x, 0, 'f', 2) .arg(star_drift.y, 0, 'f', 2);
532
533 if (state == Ekos::GUIDE_GUIDING && usingSEPMultiStar())
534 {
536 if (guideStars.getDrift(sqrt(star_drift.x * star_drift.x + star_drift.y * star_drift.y),
537 targetPosition.x, targetPosition.y,
539 {
540 qCDebug(KSTARS_EKOS_GUIDE) << QString("MultiStar drift: RA %1 DEC %2")
541 .arg(multiStarRADrift, 0, 'f', 2)
542 .arg(multiStarDECDrift, 0, 'f', 2);
543 drift[GUIDE_RA][driftUpto[GUIDE_RA]] = multiStarRADrift;
544 drift[GUIDE_DEC][driftUpto[GUIDE_DEC]] = multiStarDECDrift;
545 }
546 else
547 {
548 qCDebug(KSTARS_EKOS_GUIDE) << "MultiStar: failed, fell back to guide star";
549 }
550 }
551
552 // driftUpto will change when the circular buffer is updated,
553 // so save the values for logging.
554 const double raDrift = drift[GUIDE_RA][driftUpto[GUIDE_RA]];
555 const double decDrift = drift[GUIDE_DEC][driftUpto[GUIDE_DEC]];
556
557 // make decision by axes
558 calculatePulses(state, timeStep);
559
560 if (state == Ekos::GUIDE_GUIDING)
561 {
562 calculateRmsError();
563 emitStats();
564 updateCircularBuffers();
565 }
566
567 if (logger != nullptr)
568 {
569 GuideLog::GuideData data;
570 data.type = GuideLog::GuideData::MOUNT;
571 // These are distances in pixels.
572 // Note--these don't include the multistar algorithm, but the below ra/dec ones do.
573 data.dx = starPosition.x - targetPosition.x;
574 data.dy = starPosition.y - targetPosition.y;
575 // Above computes position - reticle. Should the reticle-position, so negate.
576 calibration.convertToPixels(-raDrift, -decDrift, &data.raDistance, &data.decDistance);
577
578 const double raGuideFactor = out_params.pulse_dir[GUIDE_RA] == NO_DIR ?
579 0 : (out_params.pulse_dir[GUIDE_RA] == RA_DEC_DIR ? -1.0 : 1.0);
580 const double decGuideFactor = out_params.pulse_dir[GUIDE_DEC] == NO_DIR ?
581 0 : (out_params.pulse_dir[GUIDE_DEC] == DEC_INC_DIR ? -1.0 : 1.0);
582
583 // Phd2LogViewer wants these in pixels instead of arcseconds, so normalizing them, but
584 // that will be wrong for non-square pixels. They should really accept arcsecond units.
585 data.raGuideDistance = calibration.xPixelsPerArcsecond() * raGuideFactor * out_params.pulse_length[GUIDE_RA] /
586 calibration.raPulseMillisecondsPerArcsecond();
587 data.decGuideDistance = calibration.yPixelsPerArcsecond() * decGuideFactor * out_params.pulse_length[GUIDE_DEC] /
588 calibration.decPulseMillisecondsPerArcsecond();
589
590 data.raDuration = out_params.pulse_dir[GUIDE_RA] == NO_DIR ? 0 : out_params.pulse_length[GUIDE_RA];
591 data.raDirection = out_params.pulse_dir[GUIDE_RA];
592 data.decDuration = out_params.pulse_dir[GUIDE_DEC] == NO_DIR ? 0 : out_params.pulse_length[GUIDE_DEC];
593 data.decDirection = out_params.pulse_dir[GUIDE_DEC];
594 data.code = GuideLog::GuideData::NO_ERRORS;
595 data.snr = guideStars.getGuideStarSNR();
596 data.mass = guideStars.getGuideStarMass();
597 // Add SNR and MASS from SEP stars.
598 logger->addGuideData(data);
599 }
600}
601
602void cgmath::performDarkGuiding(Ekos::GuideState state, const std::pair<Seconds, Seconds> &timeStep)
603{
604
605 const bool dithering = configureInParams(state);
606 //out_params.sigma[GUIDE_RA] = 0;
607
608 processAxis(GUIDE_RA, dithering, true, timeStep.first, "Dark Guiding:");
609 qCDebug(KSTARS_EKOS_GUIDE)
610 << QString("Dark Guiding pulses: RA: %1ms %2")
611 .arg(out_params.pulse_length[GUIDE_RA]).arg(directionStr(out_params.pulse_dir[GUIDE_RA]));
612
613
614 // Don't guide in DEC when dark guiding
615 updateOutParams(GUIDE_DEC, 0, 0, NO_DIR);
616
617 outputGuideLog();
618}
619
620void cgmath::emitStats()
621{
622 double pulseRA = 0;
623 if (out_params.pulse_dir[GUIDE_RA] == RA_DEC_DIR)
624 pulseRA = out_params.pulse_length[GUIDE_RA];
625 else if (out_params.pulse_dir[GUIDE_RA] == RA_INC_DIR)
626 pulseRA = -out_params.pulse_length[GUIDE_RA];
627 double pulseDEC = 0;
628 if (out_params.pulse_dir[GUIDE_DEC] == DEC_DEC_DIR)
629 pulseDEC = -out_params.pulse_length[GUIDE_DEC];
630 else if (out_params.pulse_dir[GUIDE_DEC] == DEC_INC_DIR)
631 pulseDEC = out_params.pulse_length[GUIDE_DEC];
632
633 const bool hasGuidestars = usingSEPMultiStar();
634 const double snr = hasGuidestars ? guideStars.getGuideStarSNR() : 0;
635 const double skyBG = hasGuidestars ? guideStars.skybackground().mean : 0;
636 const int numStars = hasGuidestars ? guideStars.skybackground().starsDetected : 0; // wait for rob's release
637
638 emit guideStats(-out_params.delta[GUIDE_RA], -out_params.delta[GUIDE_DEC],
640}
641
642void cgmath::calculateRmsError(void)
643{
644 if (!do_statistics)
645 return;
646
647 if (iterationCounter == 0)
648 return;
649
650 int count = std::min(iterationCounter, static_cast<unsigned int>(CIRCULAR_BUFFER_SIZE));
651 for (int k = GUIDE_RA; k <= GUIDE_DEC; k++)
652 {
653 double sqr_avg = 0;
654 for (int i = 0; i < count; ++i)
655 sqr_avg += drift[k][i] * drift[k][i];
656
657 out_params.sigma[k] = sqrt(sqr_avg / (double)count);
658 }
659}
660
661
662QVector3D cgmath::selectGuideStar(const QSharedPointer<FITSData> &imageData)
663{
664 return guideStars.selectGuideStar(imageData);
665}
666
667double cgmath::getGuideStarSNR()
668{
669 return guideStars.getGuideStarSNR();
670}
671
672//---------------------------------------------------------------------------------------
673cproc_in_params::cproc_in_params()
674{
675 reset();
676}
677
678void cproc_in_params::reset(void)
679{
680 average = true;
681
682 for (int k = GUIDE_RA; k <= GUIDE_DEC; k++)
683 {
684 enabled[k] = true;
685 integral_gain[k] = 0;
686 max_pulse_arcsec[k] = 5000;
687 min_pulse_arcsec[k] = 0;
688 }
689}
690
691cproc_out_params::cproc_out_params()
692{
693 reset();
694}
695
696void cproc_out_params::reset(void)
697{
698 for (int k = GUIDE_RA; k <= GUIDE_DEC; k++)
699 {
700 delta[k] = 0;
701 pulse_dir[k] = NO_DIR;
702 pulse_length[k] = 0;
703 sigma[k] = 0;
704 }
705}
706
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 Tue Mar 26 2024 11:19:02 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.