Kstars

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

KDE's Doxygen guidelines are available online.