10#include "guidestars.h"
12#include "ekos_guide_debug.h"
14#include "calibration.h"
16#include <QElapsedTimer>
23constexpr double MAX_ARCSEC_ERROR = 5.0;
26constexpr int MAX_SKIPPED_SAMPLES = 4;
32 parameters->control_gain_ = Options::rAProportionalGain();
34 parameters->min_move_ = 0.25;
37 parameters->min_periods_for_inference_ = Options::gPGMinPeriodsForInference();
38 parameters->SE0KLengthScale_ = Options::gPGSE0KLengthScale();
39 parameters->SE0KSignalVariance_ = Options::gPGSE0KSignalVariance();
40 parameters->PKLengthScale_ = Options::gPGPKLengthScale();
41 parameters->PKPeriodLength_ = Options::gPGPeriod();
42 parameters->PKSignalVariance_ = Options::gPGPKSignalVariance();
43 parameters->SE1KLengthScale_ = Options::gPGSE1KLengthScale();
44 parameters->SE1KSignalVariance_ = Options::gPGSE1KSignalVariance();
45 parameters->min_periods_for_period_estimation_ = Options::gPGMinPeriodsForPeriodEstimate();
46 parameters->points_for_approximation_ = Options::gPGPointsForApproximation();
47 parameters->prediction_gain_ = Options::gPGpWeight();
48 parameters->compute_period_ = Options::gPGEstimatePeriod();
53double getSNR(
const GuideStars *guideStars,
const double raArcsecError)
55 if (fabs(raArcsecError) > MAX_ARCSEC_ERROR)
59 if (guideStars ==
nullptr)
62 return guideStars->getGuideStarSNR();
65const QString directionStr(GuideDirection dir)
74 return "Decrease DEC";
76 return "Increase DEC";
84double GPG::predictionContribution()
86 if (gpg.get() ==
nullptr)
88 qCDebug(KSTARS_EKOS_GUIDE) <<
"Nullptr in predictionContribution()";
91 return gpg->getPredictionContribution();
94void GPG::updateParameters()
97 if (gpg.get() ==
nullptr)
return;
100 getGPGParameters(¶meters);
101 gpg->SetControlGain(parameters.control_gain_);
102 gpg->SetPeriodLengthsInference(parameters.min_periods_for_inference_);
103 gpg->SetMinMove(parameters.min_move_);
104 gpg->SetPeriodLengthsPeriodEstimation(parameters.min_periods_for_period_estimation_);
105 gpg->SetNumPointsForApproximation(parameters.points_for_approximation_);
106 gpg->SetPredictionGain(parameters.prediction_gain_);
107 gpg->SetBoolComputePeriod(parameters.compute_period_);
111 std::vector<double> hyperparameters(NumParameters);
112 hyperparameters[SE0KLengthScale] = parameters.SE0KLengthScale_;
113 hyperparameters[SE0KSignalVariance] = parameters.SE0KSignalVariance_;
114 hyperparameters[PKLengthScale] = parameters.PKLengthScale_;
115 hyperparameters[PKSignalVariance] = parameters.PKSignalVariance_;
116 hyperparameters[SE1KLengthScale] = parameters.SE1KLengthScale_;
117 hyperparameters[SE1KSignalVariance] = parameters.SE1KSignalVariance_;
118 hyperparameters[PKPeriodLength] = parameters.PKPeriodLength_;
119 gpg->SetGPHyperparameters(hyperparameters);
126 getGPGParameters(¶meters);
134 gpgSkippedSamples = 0;
136 qCDebug(KSTARS_EKOS_GUIDE) <<
"Resetting GPG";
139void GPG::startDithering(
double dx,
double dy,
const Calibration &cal)
142 double raPixels, decPixels;
143 cal.rotateToRaDec(dx, dy, &raPixels, &decPixels);
149 const double amount = raPixels * cal.raPulseMillisecondsPerArcsecond() * cal.xArcsecondsPerPixel() / 1000.0;
151 qCDebug(KSTARS_EKOS_GUIDE) <<
"GPG Dither started. Gear-seconds =" << amount <<
"x,y was: " << dx << dy;
152 gpg->GuidingDithered(amount, 1.0);
155void GPG::ditheringSettled(
bool success)
157 gpg->GuidingDitherSettleDone(success);
159 qCDebug(KSTARS_EKOS_GUIDE) <<
"GPG Dither done (success)";
161 qCDebug(KSTARS_EKOS_GUIDE) <<
"GPG Dither done (failed)";
164void GPG::suspended(
const GuiderUtils::Vector &guideStarPosition,
165 const GuiderUtils::Vector &reticlePosition,
166 GuideStars *guideStars,
167 const Calibration &cal)
169 constexpr int MaxGpgSamplesForReset = 25;
173 if (gpgSamples < MaxGpgSamplesForReset)
179 const GuiderUtils::Vector arc_star = cal.convertToArcseconds(guideStarPosition);
180 const GuiderUtils::Vector arc_reticle = cal.convertToArcseconds(reticlePosition);
181 const GuiderUtils::Vector star_drift = cal.rotateToRaDec(arc_star - arc_reticle);
183 double gpgInput = star_drift.x;
184 if (guideStars !=
nullptr)
186 double multiStarRADrift, multiStarDECDrift;
187 if (guideStars->getDrift(sqrt(star_drift.x * star_drift.x + star_drift.y * star_drift.y),
188 reticlePosition.x, reticlePosition.y,
189 &multiStarRADrift, &multiStarDECDrift))
190 gpgInput = multiStarRADrift;
195 double predictionGain = gpg->GetPredictionGain();
196 gpg->SetPredictionGain(0.0);
197 double controlGain = gpg->GetControlGain();
198 gpg->SetControlGain(0.0);
202 const double gpgResult = gpg->result(gpgInput, getSNR(guideStars, gpgInput), Options::guideExposure());
204 std::vector<double> gpgParams = gpg->GetGPHyperparameters();
205 Options::setGPGPeriod(gpgParams[PKPeriodLength]);
207 const double gpgTime = gpgTimer.
elapsed();
208 qCDebug(KSTARS_EKOS_GUIDE) <<
QString(
"GPG(suspended): elapsed %1s. RA in %2, result: %3")
209 .
arg(gpgTime / 1000.0)
213 gpg->SetPredictionGain(predictionGain);
214 gpg->SetControlGain(controlGain);
217bool GPG::computePulse(
double raArcsecError, GuideStars *guideStars,
218 int *pulseLength, GuideDirection *pulseDir,
219 const Calibration &cal, Seconds timeStep)
221 if (!Options::gPGEnabled())
224 if (fabs(raArcsecError) > MAX_ARCSEC_ERROR)
226 if (++gpgSkippedSamples > MAX_SKIPPED_SAMPLES)
228 qCDebug(KSTARS_EKOS_GUIDE) <<
"Resetting GPG because RA error = "
233 qCDebug(KSTARS_EKOS_GUIDE) <<
"Skipping GPG because RA error = "
237 gpgSkippedSamples = 0;
242 if (gpgSamples == 0 && fabs(raArcsecError) > 1)
244 qCDebug(KSTARS_EKOS_GUIDE) <<
"Delaying GPG startup. RA error = "
251 gpg->SetControlGain(Options::rAProportionalGain());
252 gpg->SetMinMove(Options::rAMinimumPulseArcSec());
259 auto const rawTime = timeStep.count();
261 const double gpgResult = gpg->result(raArcsecError, getSNR(guideStars, raArcsecError), rawTime);
262 const double gpgTime = gpgTimer.
elapsed();
266 const double gpgPulse = convertCorrectionToPulseMilliseconds(cal, pulseLength, pulseDir, gpgResult);
268 qCDebug(KSTARS_EKOS_GUIDE)
269 <<
QString(
"GPG: elapsed %1s. RA in %2, result: %3 * %4 --> %5 : %6ms %7")
270 .
arg(gpgTime / 1000.0)
271 .
arg(raArcsecError, 0,
'f', 2)
272 .
arg(gpgResult, 0,
'f', 2)
273 .
arg(cal.raPulseMillisecondsPerArcsecond(), 0,
'f', 1)
274 .
arg(gpgPulse, 0,
'f', 1)
276 .
arg(directionStr(*pulseDir));
277 if (Options::gPGEstimatePeriod())
279 double period_length = gpg->GetGPHyperparameters()[PKPeriodLength];
280 Options::setGPGPeriod(period_length);
285double GPG::convertCorrectionToPulseMilliseconds(
const Calibration &cal,
int *pulseLength,
286 GuideDirection *pulseDir,
const double gpgResult)
288 const double gpgPulse = gpgResult * cal.raPulseMillisecondsPerArcsecond();
290 *pulseDir = gpgPulse > 0 ? RA_DEC_DIR : RA_INC_DIR;
291 *pulseLength = fabs(gpgPulse);
295bool GPG::darkGuiding(
int *pulseLength, GuideDirection *pulseDir,
const Calibration &cal,
298 if (!Options::gPGEnabled() || !Options::gPGDarkGuiding())
300 qCDebug(KSTARS_EKOS_GUIDE) <<
"dark guiding isn't enabled!";
305 gpg->SetControlGain(Options::rAProportionalGain());
306 gpg->SetMinMove(Options::rAMinimumPulseArcSec());
310 const double gpgResult = gpg->deduceResult(timeStep.count());
311 const double gpgTime = gpgTimer.
elapsed();
314 const double gpgPulse = convertCorrectionToPulseMilliseconds(cal, pulseLength, pulseDir, gpgResult);
316 qCDebug(KSTARS_EKOS_GUIDE)
317 <<
QString(
"GPG dark guiding: elapsed %1s. RA result: %2 * %3 --> %4 : %5ms %6")
318 .
arg(gpgTime / 1000.0)
320 .
arg(cal.raPulseMillisecondsPerArcsecond())
323 .
arg(directionStr(*pulseDir));
This class provides a guiding algorithm for the right ascension axis that learns and predicts the per...
qint64 elapsed() const const
QString arg(Args &&... args) const const
Holds all data that is needed for the GP guiding.