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"
20#include "../guideview.h"
32 GuiderUtils::Vector position;
33 if (usingSEPMultiStar())
40 position = GuideAlgorithms::findLocalStarPosition(
41 imageData, algorithm, video_width, video_height,
44 if (position.x == -1 || position.y == -1)
53 starPosition = GuiderUtils::Vector(0);
54 targetPosition = GuiderUtils::Vector(0);
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;
72 delete[] drift[GUIDE_RA];
73 delete[] drift[GUIDE_DEC];
84 calibration.setBinningUsed(
binX,
binY);
85 guideStars.setCalibration(calibration);
100 guideStars.setCalibration(calibration);
106void cgmath::createGuideLog()
112 out <<
"Guiding rate,x15 arcsec/sec: " <<
Qt::endl;
113 out <<
"Focal,mm: " << calibration.getFocalLength() <<
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"
123bool cgmath::setTargetPosition(
double x,
double y)
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;
135 targetPosition = GuiderUtils::Vector(x, y, 0);
137 guideStars.setCalibration(calibration);
142bool cgmath::getTargetPosition(
double *x,
double *y)
const
144 *x = targetPosition.x;
145 *y = targetPosition.y;
149int cgmath::getAlgorithmIndex(
void)
const
154void cgmath::getStarScreenPosition(
double *dx,
double *dy)
const
156 *dx = starPosition.x;
157 *dy = starPosition.y;
162 iterationCounter = 0;
163 driftUpto[GUIDE_RA] = driftUpto[GUIDE_DEC] = 0;
164 drift_integral[GUIDE_RA] = drift_integral[GUIDE_DEC] = 0;
167 memset(drift[GUIDE_RA], 0,
sizeof(
double) * CIRCULAR_BUFFER_SIZE);
168 memset(drift[GUIDE_DEC], 0,
sizeof(
double) * CIRCULAR_BUFFER_SIZE);
181bool cgmath::usingSEPMultiStar()
const
183 return algorithm == SEP_MULTISTAR;
186void cgmath::updateCircularBuffers(
void)
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;
201 iterationCounter = 0;
202 driftUpto[GUIDE_RA] = driftUpto[GUIDE_DEC] = 0;
203 drift_integral[GUIDE_RA] = drift_integral[GUIDE_DEC] = 0;
206 memset(drift[GUIDE_RA], 0,
sizeof(
double) * CIRCULAR_BUFFER_SIZE);
207 memset(drift[GUIDE_DEC], 0,
sizeof(
double) * CIRCULAR_BUFFER_SIZE);
209 if (calibration.getFocalLength() > 0 && aperture > 0)
220void cgmath::suspend(
bool mode)
225bool cgmath::isSuspended()
const
230bool cgmath::isStarLost()
const
235void cgmath::setLostStar(
bool is_lost)
244 if (
raDEC == GUIDE_RA)
246 else if (
raDEC == GUIDE_DEC)
257 return "Decrease RA";
259 return "Increase RA";
261 return "Decrease DEC";
263 return "Increase DEC";
270bool cgmath::configureInParams(Ekos::GuideState state)
272 const bool dithering = state == Ekos::GuideState::GUIDE_DITHERING;
276 in_params.proportional_gain[0] = Options::rAProportionalGain();
277 in_params.proportional_gain[1] = Options::dECProportionalGain();
279 in_params.integral_gain[0] = Options::rAIntegralGain();
280 in_params.integral_gain[1] = Options::dECIntegralGain();
283 in_params.enabled[0] = Options::rAGuideEnabled();
284 in_params.enabled[1] = Options::dECGuideEnabled();
286 in_params.min_pulse_arcsec[0] = Options::rAMinimumPulseArcSec();
287 in_params.min_pulse_arcsec[1] = Options::dECMinimumPulseArcSec();
289 in_params.max_pulse_arcsec[0] = Options::rAMaximumPulseArcSec();
290 in_params.max_pulse_arcsec[1] = Options::dECMaximumPulseArcSec();
294 in_params.enabled_axis1[0] = Options::eastRAGuideEnabled();
296 in_params.enabled_axis2[0] = Options::westRAGuideEnabled();
300 in_params.enabled_axis1[1] = Options::northDECGuideEnabled();
302 in_params.enabled_axis2[1] = Options::southDECGuideEnabled();
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;
328 out_params.pulse_dir[
k] = pulseDirection;
333void cgmath::outputGuideLog()
335 if (Options::guideLogging())
338 out << iterationCounter <<
"," << logTime.
elapsed() <<
"," << out_params.delta[0] <<
"," << out_params.pulse_length[0] <<
340 <<
directionStr(out_params.pulse_dir[0]) <<
"," << out_params.delta[1] <<
","
345void cgmath::processAxis(
const int k,
const bool dithering,
const bool darkGuide,
const Seconds &
timeStep,
349 GuideDirection pulseDirection = NO_DIR;
354 const int idx = driftUpto[
k];
358 calibration.raPulseMillisecondsPerArcsecond() :
359 calibration.decPulseMillisecondsPerArcsecond();
363 bool useGPG = !
dithering && Options::gPGEnabled() && (
k == GUIDE_RA) && in_params.enabled[
k];
367 pulseDirection =
dir;
372 qCDebug(
KSTARS_EKOS_GUIDE) <<
"Warning: dark guiding without GPG or while dithering.";
378 pulseDirection =
dir;
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;
393 if (in_params.integral_gain[
k] > 0)
395 <<
" integral[" <<
axisStr(
k) <<
"] = " << drift_integral[
k];
397 const double arcsecPerMsPulse =
k == GUIDE_RA ? calibration.raPulseMillisecondsPerArcsecond() :
398 calibration.decPulseMillisecondsPerArcsecond();
405 if (!in_params.enabled[
k] ||
411 pulseDirection = NO_DIR;
421 pulseDirection =
arcsecDrift > 0 ? RA_DEC_DIR : RA_INC_DIR;
423 pulseDirection =
arcsecDrift > 0 ? DEC_INC_DIR : DEC_DEC_DIR;
426 pulseDirection = NO_DIR;
433void cgmath::calculatePulses(Ekos::GuideState state,
const std::pair<Seconds, Seconds> &
timeStep)
435 const bool dithering = configureInParams(state);
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]));
450 const std::pair<Seconds, Seconds> &
timeStep, GuideLog * logger)
454 if (Options::gPGEnabled())
460 usingSEPMultiStar() ? &guideStars :
nullptr, calibration);
470 starPosition = findLocalStarPosition(imageData,
guideView,
false);
473 if (starPosition.x == -1 || std::isnan(starPosition.x))
476 if (logger !=
nullptr && state == Ekos::GUIDE_GUIDING)
478 GuideLog::GuideData data;
479 data.code = GuideLog::GuideData::NO_STAR_FOUND;
480 data.type = GuideLog::GuideData::DROP;
481 logger->addGuideData(data);
489 QVector3D starCenter(starPosition.x, starPosition.y, 0);
490 emit newStarPosition(starCenter,
true);
493 if (state == Ekos::GUIDE_CALIBRATING)
496 if (state == Ekos::GUIDE_GUIDING && (targetPosition.x <= 0.0 || targetPosition.y <= 0.0))
498 qCDebug(
KSTARS_EKOS_GUIDE) <<
"Guiding with target 0.0 -- something's wrong!!!!!!!!!!!";
499 for (
int k = GUIDE_RA;
k <= GUIDE_DEC;
k++)
501 out_params.pulse_dir[
k] = NO_DIR;
502 out_params.pulse_length[
k] = 0;
503 out_params.delta[
k] = 0;
522 drift[GUIDE_RA][driftUpto[GUIDE_RA]] =
star_drift.x;
523 drift[GUIDE_DEC][driftUpto[GUIDE_DEC]] =
star_drift.y;
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)
529 .
arg(targetPosition.x, 0,
'f', 1) .
arg(targetPosition.y, 0,
'f', 1)
533 if (state == Ekos::GUIDE_GUIDING && usingSEPMultiStar())
537 targetPosition.x, targetPosition.y,
554 const double raDrift = drift[GUIDE_RA][driftUpto[GUIDE_RA]];
555 const double decDrift = drift[GUIDE_DEC][driftUpto[GUIDE_DEC]];
560 if (state == Ekos::GUIDE_GUIDING)
564 updateCircularBuffers();
567 if (logger !=
nullptr)
569 GuideLog::GuideData data;
570 data.type = GuideLog::GuideData::MOUNT;
573 data.dx = starPosition.x - targetPosition.x;
574 data.dy = starPosition.y - targetPosition.y;
576 calibration.convertToPixels(-
raDrift, -
decDrift, &data.raDistance, &data.decDistance);
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);
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();
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();
598 logger->addGuideData(data);
602void cgmath::performDarkGuiding(Ekos::GuideState state,
const std::pair<Seconds, Seconds> &
timeStep)
605 const bool dithering = configureInParams(state);
610 <<
QString(
"Dark Guiding pulses: RA: %1ms %2")
611 .
arg(out_params.pulse_length[GUIDE_RA]).
arg(
directionStr(out_params.pulse_dir[GUIDE_RA]));
615 updateOutParams(GUIDE_DEC, 0, 0, NO_DIR);
620void cgmath::emitStats()
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];
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];
634 const double snr =
hasGuidestars ? guideStars.getGuideStarSNR() : 0;
638 emit guideStats(-out_params.delta[GUIDE_RA], -out_params.delta[GUIDE_DEC],
642void cgmath::calculateRmsError(
void)
647 if (iterationCounter == 0)
650 int count = std::min(iterationCounter,
static_cast<unsigned int>(CIRCULAR_BUFFER_SIZE));
651 for (
int k = GUIDE_RA;
k <= GUIDE_DEC;
k++)
654 for (
int i = 0; i < count; ++i)
664 return guideStars.selectGuideStar(imageData);
667double cgmath::getGuideStarSNR()
669 return guideStars.getGuideStarSNR();
673cproc_in_params::cproc_in_params()
678void cproc_in_params::reset(
void)
682 for (
int k = GUIDE_RA;
k <= GUIDE_DEC;
k++)
685 integral_gain[
k] = 0;
686 max_pulse_arcsec[
k] = 5000;
687 min_pulse_arcsec[
k] = 0;
691cproc_out_params::cproc_out_params()
696void cproc_out_params::reset(
void)
698 for (
int k = GUIDE_RA;
k <= GUIDE_DEC;
k++)
701 pulse_dir[
k] = NO_DIR;
KIOCORE_EXPORT QString dir(const QString &fileClass)
QString label(StandardShortcut id)
QCA_EXPORT Logger * logger()
qint64 elapsed() const const
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
virtual void close() override
QString arg(Args &&... args) const const
QTextStream & endl(QTextStream &stream)