9 #include "focusadaptor.h"
10 #include "focusalgorithms.h"
11 #include "focusfwhm.h"
12 #include "polynomialfit.h"
14 #include "kstarsdata.h"
18 #include "ekos/guide/guide.h"
19 #include "ekos/manager.h"
22 #include "auxiliary/kspaths.h"
23 #include "auxiliary/ksmessagebox.h"
26 #include "ekos/auxiliary/darklibrary.h"
27 #include "ekos/auxiliary/profilesettings.h"
28 #include "ekos/auxiliary/opticaltrainmanager.h"
29 #include "ekos/auxiliary/opticaltrainsettings.h"
30 #include "ekos/auxiliary/filtermanager.h"
33 #include "fitsviewer/fitsdata.h"
34 #include "fitsviewer/fitsview.h"
37 #include "indi/indifilterwheel.h"
38 #include "ksnotification.h"
39 #include "kconfigdialog.h"
41 #include <basedevice.h>
42 #include <gsl/gsl_fit.h>
43 #include <gsl/gsl_vector.h>
44 #include <gsl/gsl_min.h>
46 #include <ekos_focus_debug.h>
50 #define MAXIMUM_ABS_ITERATIONS 30
51 #define MAXIMUM_RESET_ITERATIONS 3
52 #define AUTO_STAR_TIMEOUT 45000
53 #define MINIMUM_PULSE_TIMER 32
54 #define MAX_RECAPTURE_RETRIES 3
55 #define MINIMUM_POLY_SOLUTIONS 2
68 qRegisterMetaType<Ekos::FocusState>(
"Ekos::FocusState");
69 qDBusRegisterMetaType<Ekos::FocusState>();
70 new FocusAdaptor(
this);
92 tabWidget->setCurrentIndex(0);
99 for (
auto &button : qButtons)
100 button->setAutoDefault(
false);
105 m_FocusMotionTimer.
setInterval(focusMotionTimeout->value() * 1000);
120 optionsProfileEditor =
new StellarSolverProfileEditor(
this, Ekos::FocusProfiles, optionsEditor);
127 optionsProfileEditor->loadProfile(focusSEPProfile->currentText());
128 optionsEditor->
show();
145 m_DarkProcessor =
new DarkProcessor(
this);
147 connect(m_DarkProcessor, &DarkProcessor::darkFrameCompleted,
this, [
this](
bool completed)
149 useFocusDarkFrame->setChecked(completed);
150 m_FocusView->setProperty(
"suspended",
false);
153 m_FocusView->rescale(ZOOM_KEEP_LEVEL);
154 m_FocusView->updateFrame();
156 setCaptureComplete();
160 setupOpticalTrainManager();
162 connectFilterManager();
166 void Focus::prepareGUI()
169 gridLayoutProcessBucket->removeWidget(focusMultiRowAverageLabel);
170 gridLayoutProcessBucket->removeWidget(focusMultiRowAverage);
171 gridLayoutProcessBucket->removeWidget(focusGaussianSigmaLabel);
172 gridLayoutProcessBucket->removeWidget(focusGaussianSigma);
173 gridLayoutProcessBucket->removeWidget(focusThresholdLabel);
174 gridLayoutProcessBucket->removeWidget(focusThreshold);
175 gridLayoutProcessBucket->removeWidget(focusGaussianKernelSizeLabel);
176 gridLayoutProcessBucket->removeWidget(focusGaussianKernelSize);
177 gridLayoutProcessBucket->removeWidget(focusToleranceLabel);
178 gridLayoutProcessBucket->removeWidget(focusTolerance);
179 delete gridLayoutProcessBucket;
182 gridLayoutMechanics->replaceWidget(focusOutStepsLabel, focusNumStepsLabel);
183 gridLayoutMechanics->replaceWidget(focusOutSteps, focusNumSteps);
187 for (
int i = 0; i < focusStarMeasure->count(); i++)
188 m_StarMeasureText.
append(focusStarMeasure->itemText(i));
189 for (
int i = 0; i < focusCurveFit->count(); i++)
190 m_CurveFitText.
append(focusCurveFit->itemText(i));
191 for (
int i = 0; i < focusWalk->count(); i++)
192 m_FocusWalkText.
append(focusWalk->itemText(i));
197 QString savedOptionsProfiles =
QDir(KSPaths::writableLocation(
200 m_StellarSolverProfiles = StellarSolver::loadSavedOptionsProfiles(savedOptionsProfiles);
202 m_StellarSolverProfiles = getDefaultFocusOptionsProfiles();
203 focusSEPProfile->clear();
204 for(
auto ¶m : m_StellarSolverProfiles)
205 focusSEPProfile->addItem(param.listName);
206 auto profile = m_Settings[
"focusSEPProfile"];
207 if (profile.isValid())
208 focusSEPProfile->setCurrentText(profile.toString());
214 for (
auto param : m_StellarSolverProfiles)
215 profiles << param.listName;
222 if (focusingWidget->parent() ==
nullptr)
223 toggleFocusingWidgetFullScreen();
225 m_FocusLogFile.
close();
230 if (m_Camera && m_Camera->isConnected())
232 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
237 targetChip->resetFrame();
240 targetChip->getFrame(&
x, &
y, &w, &h);
242 qCDebug(KSTARS_EKOS_FOCUS) <<
"Frame is reset. X:" <<
x <<
"Y:" <<
y <<
"W:" << w <<
"H:" << h <<
"binX:" << 1 <<
"binY:" <<
245 QVariantMap settings;
250 settings[
"binx"] = 1;
251 settings[
"biny"] = 1;
252 frameSettings[targetChip] = settings;
254 starSelected =
false;
258 m_FocusView->setTrackingBox(
QRect());
259 checkMosaicMaskLimits();
267 return m_Camera->getDeviceName();
292 case FOCUS_CHANGING_FILTER:
297 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
298 if (targetChip && targetChip->isCapturing())
303 focusBinning->setEnabled(targetChip->canBin());
304 focusSubFrame->setEnabled(targetChip->canSubframe());
305 if (targetChip->canBin())
307 int subBinX = 1, subBinY = 1;
308 focusBinning->clear();
309 targetChip->getMaxBin(&subBinX, &subBinY);
310 for (
int i = 1; i <= subBinX; i++)
311 focusBinning->addItem(
QString(
"%1x%2").arg(i).arg(i));
313 auto binning = m_Settings[
"focusBinning"];
314 if (binning.isValid())
315 focusBinning->setCurrentText(binning.toString());
319 liveVideoB->setEnabled(m_Camera->hasVideoStream());
320 if (m_Camera->hasVideoStream())
321 setVideoStreamEnabled(m_Camera->isStreamingEnabled());
333 if (m_Camera ==
nullptr)
336 auto targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
337 if (targetChip ==
nullptr || (targetChip && targetChip->isCapturing()))
340 auto isoList = targetChip->getISOList();
343 if (isoList.isEmpty())
345 focusISO->setEnabled(
false);
346 ISOLabel->setEnabled(
false);
350 focusISO->setEnabled(
true);
351 ISOLabel->setEnabled(
true);
352 focusISO->addItems(isoList);
353 focusISO->setCurrentIndex(targetChip->getISOIndex());
356 bool hasGain = m_Camera->hasGain();
357 gainLabel->setEnabled(hasGain);
358 focusGain->setEnabled(hasGain && m_Camera->getGainPermission() != IP_RO);
361 double gain = 0, min = 0, max = 0, step = 1;
362 m_Camera->getGainMinMaxStep(&min, &max, &step);
363 if (m_Camera->getGain(&gain))
366 GainSpinSpecialValue = min - step;
367 focusGain->setRange(GainSpinSpecialValue, max);
368 focusGain->setSpecialValueText(
i18n(
"--"));
370 focusGain->setSingleStep(step);
372 auto defaultGain = m_Settings[
"focusGain"];
373 if (defaultGain.isValid())
374 focusGain->setValue(defaultGain.toDouble());
376 focusGain->setValue(GainSpinSpecialValue);
385 if (m_Camera ==
nullptr)
388 auto targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
389 if (targetChip ==
nullptr || (targetChip && targetChip->isCapturing()))
392 focusSubFrame->setEnabled(targetChip->canSubframe());
394 if (frameSettings.
contains(targetChip) ==
false)
397 if (targetChip->getFrame(&
x, &
y, &w, &h))
399 int binx = 1, biny = 1;
400 targetChip->getBinning(&binx, &biny);
403 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
404 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
406 QVariantMap settings;
408 settings[
"x"] = focusSubFrame->isChecked() ?
x : minX;
409 settings[
"y"] = focusSubFrame->isChecked() ?
y : minY;
410 settings[
"w"] = focusSubFrame->isChecked() ? w : maxW;
411 settings[
"h"] = focusSubFrame->isChecked() ? h : maxH;
412 settings[
"binx"] = binx;
413 settings[
"biny"] = biny;
415 frameSettings[targetChip] = settings;
423 if (m_FilterWheel && m_FilterWheel == device)
430 m_FilterWheel->disconnect(
this);
432 m_FilterWheel = device;
436 connect(m_FilterWheel, &ISD::ConcreteDevice::Connected,
this, [
this]()
438 FilterPosLabel->setEnabled(
true);
439 focusFilter->setEnabled(
true);
440 filterManagerB->setEnabled(
true);
442 connect(m_FilterWheel, &ISD::ConcreteDevice::Disconnected,
this, [
this]()
444 FilterPosLabel->setEnabled(
false);
445 focusFilter->setEnabled(
false);
446 filterManagerB->setEnabled(
false);
450 auto isConnected = m_FilterWheel && m_FilterWheel->isConnected();
451 FilterPosLabel->setEnabled(isConnected);
452 focusFilter->setEnabled(isConnected);
453 filterManagerB->setEnabled(isConnected);
455 FilterPosLabel->setEnabled(
true);
456 focusFilter->setEnabled(
true);
467 for (
auto &oneSource : m_TemperatureSources)
469 if (oneSource->getDeviceName() == device->getDeviceName())
473 m_TemperatureSources.append(device);
474 defaultFocusTemperatureSource->addItem(device->getDeviceName());
476 auto targetSource = m_Settings[
"defaultFocusTemperatureSource"];
477 if (targetSource.isValid())
487 source = defaultFocusTemperatureSource->currentText();
488 if (source.isEmpty())
494 for (
auto &oneSource : m_TemperatureSources)
496 if (oneSource->getDeviceName() == name)
498 currentSource = oneSource;
508 for (
const auto &oneSource : m_TemperatureSources)
511 if (findTemperatureElement(currentSource))
513 m_LastSourceAutofocusTemperature = currentTemperatureSourceElement->value;
514 absoluteTemperatureLabel->setText(
QString(
"%1 °C").arg(currentTemperatureSourceElement->value, 0,
'f', 2));
515 deltaTemperatureLabel->setText(
QString(
"%1 °C").arg(0.0, 0,
'f', 2));
518 m_LastSourceAutofocusTemperature = INVALID_VALUE;
526 auto temperatureProperty = device->getProperty(
"FOCUS_TEMPERATURE");
527 if (!temperatureProperty)
528 temperatureProperty = device->getProperty(
"CCD_TEMPERATURE");
529 if (temperatureProperty)
531 currentTemperatureSourceElement = temperatureProperty.getNumber()->at(0);
535 temperatureProperty = device->getProperty(
"WEATHER_PARAMETERS");
536 if (temperatureProperty)
538 for (
int i = 0; i < temperatureProperty.getNumber()->count(); i++)
540 if (strstr(temperatureProperty.getNumber()->at(i)->getName(),
"_TEMPERATURE"))
542 currentTemperatureSourceElement = temperatureProperty.getNumber()->at(i);
554 return m_FilterWheel->getDeviceName();
564 focusFilter->setCurrentText(filter);
573 return focusFilter->currentText();
578 focusFilter->clear();
582 FilterPosLabel->setEnabled(
false);
583 focusFilter->setEnabled(
false);
584 filterManagerB->setEnabled(
false);
588 m_FilterManager->disconnect(
this);
590 m_FilterManager.
reset();
595 FilterPosLabel->setEnabled(
true);
596 focusFilter->setEnabled(
true);
597 filterManagerB->setEnabled(
true);
601 focusFilter->addItems(m_FilterManager->getFilterLabels());
603 currentFilterPosition = m_FilterManager->getFilterPosition();
605 focusFilter->setCurrentIndex(currentFilterPosition - 1);
607 focusExposure->setValue(m_FilterManager->getFilterExposure());
612 if (m_Focuser && m_Focuser == device)
625 connect(m_Focuser, &ISD::ConcreteDevice::Connected,
this, [
this]()
629 connect(m_Focuser, &ISD::ConcreteDevice::Disconnected,
this, [
this]()
642 return m_Focuser->getDeviceName();
652 m_FilterManager->setFocusReady(
false);
653 canAbsMove = canRelMove = canTimerMove =
false;
658 focuserLabel->setText(m_Focuser->getDeviceName());
661 m_FilterManager->setFocusReady(m_Focuser->isConnected());
663 hasDeviation = m_Focuser->hasDeviation();
665 canAbsMove = m_Focuser->canAbsMove();
669 getAbsFocusPosition();
671 absTicksSpin->setEnabled(
true);
672 absTicksLabel->setEnabled(
true);
673 startGotoB->setEnabled(
true);
675 absTicksSpin->setValue(currentPosition);
679 absTicksSpin->setEnabled(
false);
680 absTicksLabel->setEnabled(
false);
681 startGotoB->setEnabled(
false);
684 canRelMove = m_Focuser->canRelMove();
689 if (canAbsMove ==
false && canRelMove ==
true)
691 currentPosition = 50000;
692 absMotionMax = 100000;
696 canTimerMove = m_Focuser->canTimerMove();
702 if (!canAbsMove && !canRelMove && canTimerMove)
704 currentPosition = 50000;
705 absMotionMax = 100000;
709 m_FocusType = (canRelMove || canAbsMove || canTimerMove) ? FOCUS_AUTO : FOCUS_MANUAL;
710 profilePlot->setFocusAuto(m_FocusType == FOCUS_AUTO);
712 bool hasBacklash = m_Focuser->hasBacklash();
713 focusBacklash->setEnabled(hasBacklash);
714 focusBacklash->disconnect(
this);
717 double min = 0, max = 0, step = 0;
718 m_Focuser->getMinMaxStep(
"FOCUS_BACKLASH_STEPS",
"FOCUS_BACKLASH_VALUE", &min, &max, &step);
719 focusBacklash->setMinimum(min);
720 focusBacklash->setMaximum(max);
721 focusBacklash->setSingleStep(step);
722 focusBacklash->setValue(m_Focuser->getBacklash());
727 if (m_Focuser->getBacklash() == value)
733 m_Focuser->setBacklash(value);
741 focusBacklash->setValue(0);
751 if (m_Camera && m_Camera == device)
764 connect(m_Camera, &ISD::ConcreteDevice::Connected,
this, [
this]()
766 focuserGroup->setEnabled(
true);
767 ccdGroup->setEnabled(
true);
768 tabWidget->setEnabled(
true);
770 connect(m_Camera, &ISD::ConcreteDevice::Disconnected,
this, [
this]()
772 focuserGroup->setEnabled(
false);
773 ccdGroup->setEnabled(
false);
774 tabWidget->setEnabled(
false);
778 auto isConnected = m_Camera && m_Camera->isConnected();
779 focuserGroup->setEnabled(isConnected);
780 ccdGroup->setEnabled(isConnected);
781 tabWidget->setEnabled(isConnected);
789 checkMosaicMaskLimits();
793 void Focus::getAbsFocusPosition()
798 auto absMove = m_Focuser->getNumber(
"ABS_FOCUS_POSITION");
802 const auto &it = absMove->at(0);
803 currentPosition =
static_cast<int>(it->getValue());
804 absMotionMax = it->getMax();
805 absMotionMin = it->getMin();
807 absTicksSpin->setMinimum(it->getMin());
808 absTicksSpin->setMaximum(it->getMax());
809 absTicksSpin->setSingleStep(it->getStep());
812 double const travel = std::abs(it->getMax() - it->getMin());
813 focusMaxTravel->setMaximum(travel);;
817 focusTicks->setMaximum(it->getMax() / 2);
824 if (currentTemperatureSourceElement && currentTemperatureSourceElement->nvp->name == prop.getName())
826 if (m_LastSourceAutofocusTemperature != INVALID_VALUE)
828 delta = currentTemperatureSourceElement->value - m_LastSourceAutofocusTemperature;
829 emit newFocusTemperatureDelta(abs(delta), currentTemperatureSourceElement->value);
833 emit newFocusTemperatureDelta(0, currentTemperatureSourceElement->value);
836 absoluteTemperatureLabel->setText(
QString(
"%1 °C").arg(currentTemperatureSourceElement->value, 0,
'f', 2));
837 deltaTemperatureLabel->setText(
QString(
"%1%2 °C").arg((delta > 0.0 ?
"+" :
"")).arg(delta, 0,
'f', 2));
839 deltaTemperatureLabel->setStyleSheet(
"color: lightgreen");
841 deltaTemperatureLabel->setStyleSheet(
"color: lightcoral");
843 deltaTemperatureLabel->setStyleSheet(
"color: lightblue");
847 void Focus::setLastFocusTemperature()
849 m_LastSourceAutofocusTemperature = currentTemperatureSourceElement ? currentTemperatureSourceElement->value : INVALID_VALUE;
852 deltaTemperatureLabel->setText(
QString(
"0 °C"));
853 deltaTemperatureLabel->setStyleSheet(
"color: lightgreen");
855 emit newFocusTemperatureDelta(0, -1e6);
858 void Focus::setLastFocusAlt()
860 if (mountAlt < 0.0 || mountAlt > 90.0)
861 m_LastSourceAutofocusAlt = INVALID_VALUE;
863 m_LastSourceAutofocusAlt = mountAlt;
866 void Focus::setAdaptiveFocusCounters()
868 m_LastAdaptiveFocusTemperature = m_LastSourceAutofocusTemperature;
869 m_LastAdaptiveFocusAlt = m_LastSourceAutofocusAlt;
870 m_LastAdaptiveFocusTempError = 0.0;
871 m_LastAdaptiveFocusAltError = 0.0;
878 double tempTicksDelta = 0.0;
879 double altTicksDelta = 0.0;
880 double currentTemp = INVALID_VALUE;
881 double currentAlt = INVALID_VALUE;
883 if (inAutoFocus || inFocusLoop || inAdjustFocus)
885 qCDebug(KSTARS_EKOS_FOCUS) <<
"adaptiveFocus called whilst other focus activity in progress. Ignoring.";
886 emit focusAdaptiveComplete(
false);
892 qCDebug(KSTARS_EKOS_FOCUS) <<
"adaptiveFocus called whilst already inAdaptiveFocus. Ignoring.";
893 emit focusAdaptiveComplete(
false);
897 if (!focusAdaptive->isChecked())
899 emit focusAdaptiveComplete(
false);
903 inAdaptiveFocus =
true;
906 if (currentTemperatureSourceElement && m_LastSourceAutofocusTemperature != INVALID_VALUE &&
907 m_LastAdaptiveFocusTemperature != INVALID_VALUE)
909 currentTemp = currentTemperatureSourceElement->value;
912 double tempDelta = currentTemp - m_LastAdaptiveFocusTemperature;
915 tempTicksDelta = getAdaptiveTempTicks() * tempDelta;
919 if (m_LastSourceAutofocusAlt != INVALID_VALUE && m_LastAdaptiveFocusAlt != INVALID_VALUE)
921 currentAlt = mountAlt;
923 double altDelta = currentAlt - m_LastAdaptiveFocusAlt;
926 altTicksDelta = getAdaptiveAltTicks() * altDelta;
933 const double tempTicksPlusLastError = tempTicksDelta + m_LastAdaptiveFocusTempError;
934 m_LastAdaptiveFocusTempTicks =
static_cast<int> (round(tempTicksPlusLastError));
936 const double altTicksPlusLastError = altTicksDelta + m_LastAdaptiveFocusAltError;
937 m_LastAdaptiveFocusAltTicks =
static_cast<int> (round(altTicksPlusLastError));
939 m_LastAdaptiveFocusTotalTicks = m_LastAdaptiveFocusTempTicks + m_LastAdaptiveFocusAltTicks;
940 m_LastAdaptiveFocusPosition = currentPosition + m_LastAdaptiveFocusTotalTicks;
942 appendLogText(
i18n(
"Adaptive Focus: Temp delta %1 ticks; Alt delta %2 ticks", m_LastAdaptiveFocusTempTicks,
943 m_LastAdaptiveFocusAltTicks));
946 if (abs(m_LastAdaptiveFocusTotalTicks) < focusAdaptiveMinMove->value())
948 emit focusAdaptiveComplete(
true);
949 inAdaptiveFocus =
false;
954 if (abs(initialFocuserAbsPosition - currentPosition + m_LastAdaptiveFocusTotalTicks) > focusMaxTravel->value())
958 focusAdaptive->setChecked(
false);
959 appendLogText(
i18n(
"Adaptive Focus suspended. Total movement would exceed Max Travel limit"));
960 emit focusAdaptiveComplete(
false);
961 inAdaptiveFocus =
false;
963 else if (abs(m_AdaptiveTotalMove + m_LastAdaptiveFocusTotalTicks) > focusAdaptiveMaxMove->value())
967 focusAdaptive->setChecked(
false);
968 appendLogText(
i18n(
"Adaptive Focus suspended. Total movement would exceed adaptive limit"));
969 emit focusAdaptiveComplete(
false);
970 inAdaptiveFocus =
false;
976 currentPosition + m_LastAdaptiveFocusTotalTicks));
977 if (changeFocus(m_LastAdaptiveFocusTotalTicks))
980 m_LastAdaptiveFocusTemperature = currentTemp;
981 m_LastAdaptiveFocusTempError = tempTicksPlusLastError -
static_cast<double> (m_LastAdaptiveFocusTempTicks);
982 m_LastAdaptiveFocusAlt = currentAlt;
983 m_LastAdaptiveFocusAltError = altTicksPlusLastError -
static_cast<double> (m_LastAdaptiveFocusAltTicks);
984 m_AdaptiveTotalMove += m_LastAdaptiveFocusTotalTicks;
990 emit focusAdaptiveComplete(
false);
991 inAdaptiveFocus =
false;
997 double Focus::getAdaptiveTempTicks()
1000 return m_FilterManager->getFilterTicksPerTemp(filter());
1005 double Focus::getAdaptiveAltTicks()
1007 if (m_FilterManager)
1008 return m_FilterManager->getFilterTicksPerAlt(filter());
1014 void Focus::initializeFocuserTemperature()
1016 auto temperatureProperty = currentFocuser->getBaseDevice()->getNumber(
"FOCUS_TEMPERATURE");
1018 if (temperatureProperty && temperatureProperty->getState() != IPS_ALERT)
1020 focuserTemperature = temperatureProperty->at(0)->getValue();
1021 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Setting current focuser temperature: %1").
arg(focuserTemperature, 0,
'f', 2);
1025 focuserTemperature = INVALID_VALUE;
1026 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Focuser temperature is not available");
1030 void Focus::setLastFocusTemperature()
1034 if (focuserTemperature != INVALID_VALUE)
1036 lastFocusTemperature = focuserTemperature;
1037 lastFocusTemperatureSource = FOCUSER_TEMPERATURE;
1039 else if (observatoryTemperature != INVALID_VALUE)
1041 lastFocusTemperature = observatoryTemperature;
1042 lastFocusTemperatureSource = OBSERVATORY_TEMPERATURE;
1046 lastFocusTemperature = INVALID_VALUE;
1047 lastFocusTemperatureSource = NO_TEMPERATURE;
1050 emit newFocusTemperatureDelta(0, -1e6);
1054 void Focus::updateTemperature(TemperatureSource source,
double newTemperature)
1056 if (source == FOCUSER_TEMPERATURE && focuserTemperature != newTemperature)
1058 focuserTemperature = newTemperature;
1059 emitTemperatureEvents(source, newTemperature);
1061 else if (source == OBSERVATORY_TEMPERATURE && observatoryTemperature != newTemperature)
1063 observatoryTemperature = newTemperature;
1064 emitTemperatureEvents(source, newTemperature);
1068 void Focus::emitTemperatureEvents(TemperatureSource source,
double newTemperature)
1070 if (source != lastFocusTemperatureSource)
1075 if (lastFocusTemperature != INVALID_VALUE && newTemperature != INVALID_VALUE)
1077 emit newFocusTemperatureDelta(abs(newTemperature - lastFocusTemperature), newTemperature);
1081 emit newFocusTemperatureDelta(0, newTemperature);
1088 if (m_Focuser ==
nullptr)
1091 completeFocusProcedure(Ekos::FOCUS_ABORTED);
1095 if (m_Camera ==
nullptr)
1098 completeFocusProcedure(Ekos::FOCUS_ABORTED);
1102 if (!canAbsMove && !canRelMove && focusTicks->value() <= MINIMUM_PULSE_TIMER)
1104 appendLogText(
i18n(
"Starting pulse step is too low. Increase the step size to %1 or higher...",
1105 MINIMUM_PULSE_TIMER * 5));
1106 completeFocusProcedure(Ekos::FOCUS_ABORTED);
1115 else if (inAdjustFocus)
1117 appendLogText(
i18n(
"Discarding Autofocus start request - AdjustFocus in progress."));
1120 else if (inAdaptiveFocus)
1122 appendLogText(
i18n(
"Discarding Autofocus start request - AdaptiveFocus in progress."));
1125 else inAutoFocus =
true;
1127 m_LastFocusDirection = FOCUS_NONE;
1129 waitStarSelectTimer.
stop();
1132 m_FocusMotionTimerCounter = 0;
1133 m_FocusMotionTimer.
stop();
1134 m_FocusMotionTimer.
setInterval(focusMotionTimeout->value() * 1000);
1137 m_FocuserReconnectCounter = 0;
1140 m_FocuserReconnectCounter = 0;
1141 m_DebugFocuserCounter = 0;
1148 m_RestartState = RESTART_NONE;
1156 getAbsFocusPosition();
1157 pulseDuration = focusTicks->value();
1159 else if (canRelMove)
1163 pulseDuration = focusTicks->value();
1165 absMotionMax = 100000;
1170 pulseDuration = focusTicks->value();
1172 absMotionMax = 100000;
1176 focuserAdditionalMovement = 0;
1177 starMeasureFrames.
clear();
1189 profilePlot->clear();
1190 FWHMOut->setText(
"");
1192 qCInfo(KSTARS_EKOS_FOCUS) <<
"Starting Autofocus on" << focuserLabel->text()
1193 <<
" Filter:" << filter()
1194 <<
" Exp:" << focusExposure->value()
1195 <<
" Bin:" << focusBinning->currentText()
1196 <<
" Gain:" << focusGain->value()
1197 <<
" ISO:" << focusISO->currentText();
1198 qCInfo(KSTARS_EKOS_FOCUS) <<
"Settings Tab."
1199 <<
" Auto Select Star:" << ( focusAutoStarEnabled->isChecked() ?
"yes" :
"no" )
1200 <<
" Dark Frame:" << ( useFocusDarkFrame->isChecked() ?
"yes" :
"no" )
1201 <<
" Sub Frame:" << ( focusSubFrame->isChecked() ?
"yes" :
"no" )
1202 <<
" Box:" << focusBoxSize->value()
1203 <<
" Full frame:" << ( focusUseFullField->isChecked() ?
"yes" :
"no " )
1204 <<
" Focus Mask: " << (focusNoMaskRB->isChecked() ?
"Use all stars" :
1205 (focusRingMaskRB->isChecked() ?
QString(
"Ring Mask: [%1%, %2%]").
1206 arg(focusFullFieldInnerRadius->value()).
arg(focusFullFieldOuterRadius->value()) :
1207 QString(
"Mosaic Mask: [%1%, space=%2px]").
1208 arg(focusMosaicTileWidth->value()).
arg(focusMosaicSpace->value())))
1209 <<
" Suspend Guiding:" << ( focusSuspendGuiding->isChecked() ?
"yes" :
"no " )
1210 <<
" Guide Settle:" << guideSettleTime->value()
1211 <<
" Display Units:" << focusUnits->currentText()
1212 <<
" Adaptive Focus:" << ( focusAdaptive->isChecked() ?
"yes" :
"no" )
1213 <<
" Min Move:" << focusAdaptiveMinMove->value()
1214 <<
" Adapt Start:" << ( focusAdaptStart->isChecked() ?
"yes" :
"no" )
1215 <<
" Max Total Move:" << focusAdaptiveMaxMove->value();
1216 qCInfo(KSTARS_EKOS_FOCUS) <<
"Process Tab."
1217 <<
" Detection:" << focusDetection->currentText()
1218 <<
" SEP Profile:" << focusSEPProfile->currentText()
1219 <<
" Algorithm:" << focusAlgorithm->currentText()
1220 <<
" Curve Fit:" << focusCurveFit->currentText()
1221 <<
" Measure:" << focusStarMeasure->currentText()
1222 <<
" PSF:" << focusStarPSF->currentText()
1223 <<
" Use Weights:" << ( focusUseWeights->isChecked() ?
"yes" :
"no" )
1224 <<
" R2 Limit:" << focusR2Limit->value()
1225 <<
" Refine Curve Fit:" << ( focusRefineCurveFit->isChecked() ?
"yes" :
"no" )
1226 <<
" Average Over:" << focusFramesCount->value()
1227 <<
" Num.of Rows:" << focusMultiRowAverage->value()
1228 <<
" Sigma:" << focusGaussianSigma->value()
1229 <<
" Threshold:" << focusThreshold->value()
1230 <<
" Kernel size:" << focusGaussianKernelSize->value()
1231 <<
" Tolerance:" << focusTolerance->value();
1232 qCInfo(KSTARS_EKOS_FOCUS) <<
"Mechanics Tab."
1233 <<
" Initial Step Size:" << focusTicks->value()
1234 <<
" Out Step Multiple:" << focusOutSteps->value()
1235 <<
" Number Steps:" << focusNumSteps->value()
1236 <<
" Max Travel:" << focusMaxTravel->value()
1237 <<
" Max Step Size:" << focusMaxSingleStep->value()
1238 <<
" Driver Backlash:" << focusBacklash->value()
1239 <<
" AF Overscan:" << focusAFOverscan->value()
1240 <<
" Focuser Settle:" << focusSettleTime->value()
1241 <<
" Walk:" << focusWalk->currentText()
1242 <<
" Capture Timeout:" << focusCaptureTimeout->value()
1243 <<
" Motion Timeout:" << focusMotionTimeout->value();
1244 qCInfo(KSTARS_EKOS_FOCUS) <<
"CFZ Tab."
1245 <<
" Algorithm:" << focusCFZAlgorithm->currentText()
1246 <<
" Tolerance:" << focusCFZTolerance->value()
1247 <<
" Tolerance (τ):" << focusCFZTau->value()
1248 <<
" Display:" << ( focusCFZDisplayVCurve->isChecked() ?
"yes" :
"no" )
1249 <<
" Wavelength (λ):" << focusCFZWavelength->value()
1250 <<
" Aperture (A):" << focusCFZAperture->value()
1251 <<
" Focal Ratio (f):" << focusCFZFNumber->value()
1252 <<
" Step Size:" << focusCFZStepSize->value()
1253 <<
" FWHM (θ):" << focusCFZSeeing->value();
1255 if (currentTemperatureSourceElement)
1256 emit autofocusStarting(currentTemperatureSourceElement->value, filter());
1259 emit autofocusStarting(INVALID_VALUE, filter());
1261 if (focusAutoStarEnabled->isChecked())
1263 else if (!inAutoFocus)
1269 if (m_GuidingSuspended ==
false && focusSuspendGuiding->isChecked())
1271 m_GuidingSuspended =
true;
1272 emit suspendGuiding();
1276 state = Ekos::FOCUS_PROGRESS;
1277 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
1278 emit newStatus(state);
1280 KSNotification::event(
QLatin1String(
"FocusStarted"),
i18n(
"Autofocus operation started"), KSNotification::Focus);
1283 if (m_FocusAlgorithm == FOCUS_LINEAR || m_FocusAlgorithm == FOCUS_LINEAR1PASS)
1286 const int position = adaptStartPosition(currentPosition, &AFfilter);
1288 curveFitting.reset(
new CurveFitting());
1290 FocusAlgorithmInterface::FocusParams params(curveFitting.get(),
1291 focusMaxTravel->value(), focusTicks->value(), position, absMotionMin, absMotionMax,
1292 MAXIMUM_ABS_ITERATIONS, focusTolerance->value() / 100.0, AFfilter,
1293 currentTemperatureSourceElement ? currentTemperatureSourceElement->value : INVALID_VALUE,
1294 focusOutSteps->value(), focusNumSteps->value(),
1295 m_FocusAlgorithm, focusBacklash->value(), m_CurveFit, focusUseWeights->isChecked(),
1296 m_StarMeasure, m_StarPSF, focusRefineCurveFit->isChecked(), m_FocusWalk, m_OptDir, m_ScaleCalc);
1298 if (m_FocusAlgorithm == FOCUS_LINEAR1PASS)
1301 starFitting.reset(
new CurveFitting());
1302 focusFWHM.reset(
new FocusFWHM(m_ScaleCalc));
1303 focusFourierPower.reset(
new FocusFourierPower(m_ScaleCalc));
1307 initialFocuserAbsPosition = position;
1308 linearFocuser.reset(MakeLinearFocuser(params));
1309 linearRequestedPosition = linearFocuser->initialPosition();
1310 if (!changeFocus(linearRequestedPosition - currentPosition))
1311 completeFocusProcedure(Ekos::FOCUS_ABORTED);
1323 int Focus::adaptStartPosition(
int position,
QString *AFfilter)
1329 *AFfilter = filter();
1331 if (!m_FilterManager)
1334 QString lockFilter = m_FilterManager->getFilterLock(*AFfilter);
1335 if (inBuildOffsets || lockFilter ==
"--" || lockFilter == *AFfilter)
1336 filterText = *AFfilter;
1339 filterText = *AFfilter +
" locked to " + lockFilter;
1340 *AFfilter = lockFilter;
1343 if (m_FocusAlgorithm != FOCUS_LINEAR1PASS)
1346 if (!focusAdaptStart->isChecked())
1352 double lastTemp, lastAlt;
1353 if(!m_FilterManager->getFilterAbsoluteFocusDetails(*AFfilter, lastPos, lastTemp, lastAlt))
1362 int minTravelLimit = qMax(0.0, currentPosition - focusMaxTravel->value());
1363 int maxTravelLimit = qMin(absMotionMax, currentPosition + focusMaxTravel->value());
1364 if (lastPos < minTravelLimit || lastPos > maxTravelLimit)
1367 appendLogText(
i18n(
"Adaptive start point, last AF solution outside Max Travel, ignoring"));
1372 double ticksTemp = 0.0;
1373 double tempDelta = 0.0;
1374 if (!currentTemperatureSourceElement)
1376 else if (lastTemp == INVALID_VALUE)
1377 appendLogText(
i18n(
"Adaptive start point, no temperature for last AF solution"));
1380 double currentTemp = currentTemperatureSourceElement->value;
1381 tempDelta = currentTemp - lastTemp;
1382 if (abs(tempDelta) > 30)
1384 appendLogText(
i18n(
"Adaptive start point, very large temperature delta, ignoring"));
1386 ticksTemp = tempDelta * m_FilterManager->getFilterTicksPerTemp(*AFfilter);
1390 double ticksAlt = 0.0;
1391 double currentAlt = mountAlt;
1392 double altDelta = currentAlt - lastAlt;
1395 if (lastAlt == INVALID_VALUE)
1396 appendLogText(
i18n(
"Adaptive start point, no alt recorded for last AF solution"));
1397 else if (abs(altDelta) > 90.0)
1398 appendLogText(
i18n(
"Adaptive start point, very large altitude delta, ignoring"));
1400 ticksAlt = altDelta * m_FilterManager->getFilterTicksPerAlt(*AFfilter);
1403 const int ticksTotal =
static_cast<int> (round(ticksTemp + ticksAlt));
1404 int targetPos = lastPos + ticksTotal;
1405 if (targetPos < minTravelLimit || targetPos > maxTravelLimit)
1408 appendLogText(
i18n(
"Adaptive start point, target position is outside Max Travel, ignoring"));
1412 if (abs(targetPos - position) > focusAdaptiveMaxMove->value())
1416 appendLogText(
i18n(
"Adaptive start point [%1] excessive move disallowed", filterText));
1417 qCDebug(KSTARS_EKOS_FOCUS) <<
"Adaptive start point: " << filterText
1418 <<
" startPosition: " << position
1419 <<
" Last filter position: " << lastPos
1420 <<
" Temp delta: " << tempDelta <<
" Temp ticks: " << ticksTemp
1421 <<
" Alt delta: " << altDelta <<
" Alt ticks: " << ticksAlt
1422 <<
" Target position: " << targetPos
1423 <<
" Exceeds max allowed move: " << focusAdaptiveMaxMove->value()
1424 <<
" Using startPosition.";
1430 appendLogText(
i18n(
"Adapting start point [%1] from %2 to %3", filterText, currentPosition, targetPos));
1431 qCDebug(KSTARS_EKOS_FOCUS) <<
"Adaptive start point: " << filterText
1432 <<
" startPosition: " << position
1433 <<
" Last filter position: " << lastPos
1434 <<
" Temp delta: " << tempDelta <<
" Temp ticks: " << ticksTemp
1435 <<
" Alt delta: " << altDelta <<
" Alt ticks: " << ticksAlt
1436 <<
" Target position: " << targetPos;
1441 int Focus::adjustLinearPosition(
int position,
int newPosition,
int overscan)
1443 if (overscan > 0 && newPosition > position)
1446 int adjustment = overscan;
1447 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Linear: extending outward movement by overscan %1").
arg(adjustment);
1449 if (newPosition + adjustment > absMotionMax)
1450 adjustment =
static_cast<int>(absMotionMax) - newPosition;
1452 focuserAdditionalMovement = adjustment;
1454 return newPosition + adjustment;
1463 resetFocusIteration = MAXIMUM_RESET_ITERATIONS + 1;
1465 if (captureInProgress && inAutoFocus ==
false && inFocusLoop ==
false)
1467 captureB->setEnabled(
true);
1468 stopFocusB->setEnabled(
false);
1475 stopFocusB->setEnabled(
false);
1484 completeFocusProcedure(
abort ? Ekos::FOCUS_ABORTED : Ekos::FOCUS_FAILED);
1491 if (state == FOCUS_IDLE || state == FOCUS_COMPLETE || state == FOCUS_FAILED || state == FOCUS_ABORTED)
1495 int old = resetFocusIteration;
1501 resetFocusIteration = old;
1507 if (state <= FOCUS_ABORTED)
1514 void Focus::stop(Ekos::FocusState completionState)
1516 qCDebug(KSTARS_EKOS_FOCUS) <<
"Stopping Focus";
1518 captureTimeout.
stop();
1519 m_FocusMotionTimer.
stop();
1520 m_FocusMotionTimerCounter = 0;
1521 m_FocuserReconnectCounter = 0;
1523 opticalTrainCombo->setEnabled(
true);
1524 inAutoFocus =
false;
1525 inAdjustFocus =
false;
1526 inAdaptiveFocus =
false;
1527 inBuildOffsets =
false;
1528 focuserAdditionalMovement = 0;
1529 inFocusLoop =
false;
1530 captureInProgress =
false;
1531 isVShapeSolution =
false;
1532 captureFailureCounter = 0;
1533 minimumRequiredHFR = INVALID_STAR_MEASURE;
1535 starMeasureFrames.
clear();
1541 disconnect(m_Camera, &ISD::Camera::error,
this, &Ekos::Focus::processCaptureError);
1543 if (rememberUploadMode != m_Camera->getUploadMode())
1544 m_Camera->setUploadMode(rememberUploadMode);
1547 if (m_RememberCameraFastExposure)
1549 m_RememberCameraFastExposure =
false;
1550 m_Camera->setFastExposureEnabled(
true);
1553 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
1554 targetChip->abortExposure();
1563 if (m_GuidingSuspended)
1565 emit resumeGuiding();
1566 m_GuidingSuspended =
false;
1569 if (completionState == Ekos::FOCUS_ABORTED || completionState == Ekos::FOCUS_FAILED)
1571 state = completionState;
1572 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
1573 emit newStatus(state);
1581 if (settleTime > 0 && captureInProgress ==
false)
1583 captureTimer.
start(
static_cast<int>(settleTime * 1000));
1587 if (captureInProgress)
1589 qCWarning(KSTARS_EKOS_FOCUS) <<
"Capture called while already in progress. Capture is ignored.";
1593 if (m_Camera ==
nullptr)
1600 if (m_Camera->isConnected() ==
false)
1608 captureTimeout.
stop();
1610 waitStarSelectTimer.
stop();
1612 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
1614 if (m_Camera->isBLOBEnabled() ==
false)
1616 m_Camera->setBLOBEnabled(
true);
1619 if (focusFilter->currentIndex() != -1)
1621 if (m_FilterWheel ==
nullptr)
1627 if (m_FilterWheel->isConnected() ==
false)
1637 int targetPosition = focusFilter->currentIndex() + 1;
1638 if (!inBuildOffsets)
1640 QString lockedFilter = m_FilterManager->getFilterLock(filter());
1645 if (lockedFilter !=
"--" && lockedFilter != filter())
1647 int lockedFilterIndex = focusFilter->findText(lockedFilter);
1648 if (lockedFilterIndex >= 0)
1651 fallbackFilterPending =
true;
1652 fallbackFilterPosition = targetPosition;
1653 targetPosition = lockedFilterIndex + 1;
1658 filterPositionPending = (targetPosition != currentFilterPosition);
1659 if (filterPositionPending)
1663 m_FilterManager->setFilterPosition(targetPosition,
1664 static_cast<FilterManager::FilterPolicy
>(FilterManager::CHANGE_POLICY));
1667 else if (targetPosition != focusFilter->currentIndex() + 1)
1668 focusFilter->setCurrentIndex(targetPosition - 1);
1671 m_FocusView->setProperty(
"suspended", useFocusDarkFrame->isChecked());
1672 prepareCapture(targetChip);
1675 connect(m_Camera, &ISD::Camera::error,
this, &Ekos::Focus::processCaptureError);
1677 if (frameSettings.
contains(targetChip))
1679 QVariantMap settings = frameSettings[targetChip];
1680 targetChip->setFrame(settings[
"x"].toInt(), settings[
"y"].toInt(), settings[
"w"].toInt(),
1681 settings[
"h"].toInt());
1682 settings[
"binx"] = (focusBinning->currentIndex() + 1);
1683 settings[
"biny"] = (focusBinning->currentIndex() + 1);
1684 frameSettings[targetChip] = settings;
1687 captureInProgress =
true;
1688 if (state != FOCUS_PROGRESS)
1690 state = FOCUS_PROGRESS;
1691 emit newStatus(state);
1694 m_FocusView->setBaseSize(focusingWidget->size());
1696 if (targetChip->capture(focusExposure->value()))
1700 captureTimeout.
start(focusCaptureTimeout->value() * 1000);
1702 if (inFocusLoop ==
false)
1707 else if (inAutoFocus)
1709 completeFocusProcedure(Ekos::FOCUS_ABORTED);
1715 if (m_Camera->getUploadMode() == ISD::Camera::UPLOAD_LOCAL)
1717 rememberUploadMode = ISD::Camera::UPLOAD_LOCAL;
1718 m_Camera->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
1722 if (m_Camera->isFastExposureEnabled())
1724 m_RememberCameraFastExposure =
true;
1725 m_Camera->setFastExposureEnabled(
false);
1728 m_Camera->setEncodingFormat(
"FITS");
1729 targetChip->setBatchMode(
false);
1730 targetChip->setBinning((focusBinning->currentIndex() + 1), (focusBinning->currentIndex() + 1));
1731 targetChip->setCaptureMode(FITS_FOCUS);
1732 targetChip->setFrameType(FRAME_LIGHT);
1733 targetChip->setCaptureFilter(FITS_NONE);
1735 if (isFocusISOEnabled() && focusISO->currentIndex() != -1 &&
1736 targetChip->getISOIndex() != focusISO->currentIndex())
1737 targetChip->setISOIndex(focusISO->currentIndex());
1739 if (isFocusGainEnabled() && focusGain->value() != GainSpinSpecialValue)
1740 m_Camera->setGain(focusGain->value());
1746 ms = focusTicks->value();
1747 return changeFocus(-ms);
1753 ms = focusTicks->value();
1754 return changeFocus(ms);
1759 bool Focus::changeFocus(
int amount)
1763 if (inAutoFocus && abs(amount) <= 1)
1765 capture(focusSettleTime->value());
1769 if (m_Focuser ==
nullptr)
1776 if (m_Focuser->isConnected() ==
false)
1783 const int newPosition = adjustLinearPosition(currentPosition, currentPosition + amount, focusAFOverscan->value());
1784 if (newPosition == currentPosition)
1787 const int newAmount = newPosition - currentPosition;
1788 const int absNewAmount = abs(newAmount);
1789 const bool focusingOut = newAmount > 0;
1790 const QString dirStr = focusingOut ?
i18n(
"outward") :
i18n(
"inward");
1793 m_Focuser->focusOut();
1795 m_Focuser->focusIn();
1798 m_FocusMotionTimer.
start();
1802 m_LastFocusSteps = newPosition;
1803 m_Focuser->moveAbs(newPosition);
1806 else if (canRelMove)
1808 m_LastFocusSteps = absNewAmount;
1809 m_Focuser->moveRel(absNewAmount);
1810 appendLogText(
i18np(
"Focusing %2 by %1 step...",
"Focusing %2 by %1 steps...", absNewAmount, dirStr));
1814 m_LastFocusSteps = absNewAmount;
1815 m_Focuser->moveByTimer(absNewAmount);
1825 void Focus::handleFocusMotionTimeout()
1845 qCDebug(KSTARS_EKOS_FOCUS) <<
"handleFocusMotionTimeout() called while not in AutoFocus";
1849 m_FocusMotionTimerCounter++;
1851 if (m_FocusMotionTimerCounter > 4)
1855 stop(Ekos::FOCUS_ABORTED);
1858 else if (m_FocusMotionTimerCounter > 2)
1860 QString focuser = m_Focuser->getDeviceName();
1861 appendLogText(
i18n(
"Focus motion timed out (%1). Restarting focus driver %2", m_FocusMotionTimerCounter, focuser));
1871 if (!changeFocus(m_LastFocusSteps - currentPosition))
1872 appendLogText(
i18n(
"Focus motion timed out (%1). Focusing to %2 steps...", m_FocusMotionTimerCounter, m_LastFocusSteps));
1877 const bool useFullField = focusUseFullField->isChecked();
1879 focusRingMaskRB->setEnabled(useFullField);
1880 focusMosaicMaskRB->setEnabled(useFullField);
1882 focusFullFieldInnerRadius->setEnabled(useFullField && newMaskType == FOCUS_MASK_RING);
1883 focusFullFieldOuterRadius->setEnabled(useFullField && newMaskType == FOCUS_MASK_RING);
1885 focusMosaicTileWidth->setEnabled(useFullField && newMaskType == FOCUS_MASK_MOSAIC);
1886 focusSpacerLabel->setEnabled(useFullField && newMaskType == FOCUS_MASK_MOSAIC);
1887 focusMosaicSpace->setEnabled(useFullField && newMaskType == FOCUS_MASK_MOSAIC);
1890 if (newMaskType == FOCUS_MASK_RING)
1891 m_FocusView->setImageMask(
new ImageRingMask(Options::focusFullFieldInnerRadius() / 100.0,
1892 Options::focusFullFieldOuterRadius() / 100.0));
1893 else if (newMaskType == FOCUS_MASK_MOSAIC)
1894 m_FocusView->setImageMask(
new ImageMosaicMask(Options::focusMosaicTileWidth(), Options::focusMosaicSpace()));
1896 m_FocusView->setImageMask(
nullptr);
1898 checkMosaicMaskLimits();
1899 m_currentImageMask = newMaskType;
1902 void Focus::syncImageMaskSelection()
1908 ImageMaskType
mask = FOCUS_MASK_NONE;
1910 if (name ==
"focusRingMaskRB")
1911 mask = FOCUS_MASK_RING;
1912 else if (name ==
"focusMosaicMaskRB")
1913 mask = FOCUS_MASK_MOSAIC;
1915 Options::setFocusMaskType(
mask);
1924 m_FocuserReconnectCounter++;
1926 if (m_Focuser && m_Focuser->getDeviceName() == focuser)
1929 refreshOpticalTrain();
1930 completeFocusProcedure(Ekos::FOCUS_ABORTED);
1934 if (m_FocuserReconnectCounter > 12)
1938 stop(Ekos::FOCUS_ABORTED);
1951 if (data->property(
"chip").toInt() == ISD::CameraChip::GUIDE_CCD)
1956 m_FocusView->loadData(data);
1960 m_ImageData.
reset();
1962 captureTimeout.
stop();
1963 captureTimeoutCounter = 0;
1965 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
1967 disconnect(m_Camera, &ISD::Camera::error,
this, &Ekos::Focus::processCaptureError);
1969 if (m_ImageData && useFocusDarkFrame->isChecked())
1971 QVariantMap settings = frameSettings[targetChip];
1972 uint16_t offsetX = settings[
"x"].toInt() / settings[
"binx"].toInt();
1973 uint16_t offsetY = settings[
"y"].toInt() / settings[
"biny"].toInt();
1975 m_DarkProcessor->denoise(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()),
1976 targetChip, m_ImageData, focusExposure->value(), offsetX, offsetY);
1980 setCaptureComplete();
1984 void Focus::starDetectionFinished()
1989 double hfr = INVALID_STAR_MEASURE;
1991 if (m_StarFinderWatcher.
result() ==
false)
1993 qCWarning(KSTARS_EKOS_FOCUS) <<
"Failed to extract any stars.";
1997 if (focusUseFullField->isChecked())
1999 m_FocusView->filterStars();
2002 hfr = m_ImageData->getHFR(m_StarMeasure == FOCUS_STAR_HFR_ADJ ? HFR_ADJ_AVERAGE : HFR_AVERAGE);
2006 m_FocusView->setTrackingBoxEnabled(
true);
2011 if (starCenter.
isNull() ==
false)
2012 hfr = m_ImageData->getHFR(starCenter.
x(), starCenter.
y());
2016 hfr = m_ImageData->getHFR(m_FocusDetection == ALGORITHM_SEP ? HFR_HIGH : HFR_MAX);
2020 hfrInProgress =
false;
2022 currentNumStars = m_ImageData->getDetectedStars();
2026 currentMeasure = currentHFR;
2029 if (m_StarMeasure == FOCUS_STAR_NUM_STARS)
2031 currentMeasure = currentNumStars;
2032 currentWeight = 1.0;
2034 else if (m_StarMeasure == FOCUS_STAR_FWHM)
2036 getFWHM(¤tFWHM, ¤tWeight);
2037 currentMeasure = currentFWHM;
2039 else if (m_StarMeasure == FOCUS_STAR_FOURIER_POWER)
2041 getFourierPower(¤tFourierPower, ¤tWeight);
2042 currentMeasure = currentFourierPower;
2046 currentMeasure = currentHFR;
2048 std::vector<double> hfrs(stars.
size());
2053 currentWeight = calculateStarWeight(focusUseWeights->isChecked(), hfrs);
2056 setCurrentMeasure();
2060 void Focus::getFWHM(
double *FWHM,
double *weight)
2062 *FWHM = INVALID_STAR_MEASURE;
2065 auto imageBuffer = m_ImageData->getImageBuffer();
2067 switch (m_ImageData->getStatistics().dataType)
2070 focusFWHM->processFWHM(
reinterpret_cast<uint8_t
const *
>(imageBuffer), m_ImageData, starFitting, FWHM, weight);
2074 focusFWHM->processFWHM(
reinterpret_cast<short const *
>(imageBuffer), m_ImageData, starFitting, FWHM, weight);
2078 focusFWHM->processFWHM(
reinterpret_cast<unsigned short const *
>(imageBuffer), m_ImageData, starFitting, FWHM, weight);
2082 focusFWHM->processFWHM(
reinterpret_cast<long const *
>(imageBuffer), m_ImageData, starFitting, FWHM, weight);
2086 focusFWHM->processFWHM(
reinterpret_cast<unsigned long const *
>(imageBuffer), m_ImageData, starFitting, FWHM, weight);
2090 focusFWHM->processFWHM(
reinterpret_cast<float const *
>(imageBuffer), m_ImageData, starFitting, FWHM, weight);
2094 focusFWHM->processFWHM(
reinterpret_cast<long long const *
>(imageBuffer), m_ImageData, starFitting, FWHM, weight);
2098 focusFWHM->processFWHM(
reinterpret_cast<double const *
>(imageBuffer), m_ImageData, starFitting, FWHM, weight);
2102 qCDebug(KSTARS_EKOS_FOCUS) <<
"Unknown image buffer datatype " << m_ImageData->getStatistics().dataType <<
2103 " Cannot calc FWHM";
2109 void Focus::getFourierPower(
double *fourierPower,
double *weight)
2111 *fourierPower = INVALID_STAR_MEASURE;
2114 auto imageBuffer = m_ImageData->getImageBuffer();
2116 switch (m_ImageData->getStatistics().dataType)
2119 focusFourierPower->processFourierPower(
reinterpret_cast<uint8_t
const *
>(imageBuffer), m_ImageData,
2120 m_FocusView->imageMask(),
2121 fourierPower, weight);
2125 focusFourierPower->processFourierPower(
reinterpret_cast<short const *
>(imageBuffer), m_ImageData, m_FocusView->imageMask(),
2126 fourierPower, weight);
2130 focusFourierPower->processFourierPower(
reinterpret_cast<unsigned short const *
>(imageBuffer), m_ImageData,
2131 m_FocusView->imageMask(), fourierPower, weight);
2135 focusFourierPower->processFourierPower(
reinterpret_cast<long const *
>(imageBuffer), m_ImageData, m_FocusView->imageMask(),
2136 fourierPower, weight);
2140 focusFourierPower->processFourierPower(
reinterpret_cast<unsigned long const *
>(imageBuffer), m_ImageData,
2141 m_FocusView->imageMask(), fourierPower, weight);
2145 focusFourierPower->processFourierPower(
reinterpret_cast<float const *
>(imageBuffer), m_ImageData, m_FocusView->imageMask(),
2146 fourierPower, weight);
2150 focusFourierPower->processFourierPower(
reinterpret_cast<long long const *
>(imageBuffer), m_ImageData,
2151 m_FocusView->imageMask(), fourierPower, weight);
2155 focusFourierPower->processFourierPower(
reinterpret_cast<double const *
>(imageBuffer), m_ImageData, m_FocusView->imageMask(),
2156 fourierPower, weight);
2160 qCDebug(KSTARS_EKOS_FOCUS) <<
"Unknown image buffer datatype " << m_ImageData->getStatistics().dataType <<
2161 " Cannot calc Fourier Power";
2166 double Focus::calculateStarWeight(
const bool useWeights,
const std::vector<double> values)
2168 if (!useWeights || values.size() <= 0)
2173 return Mathematics::RobustStatistics::ComputeWeight(m_ScaleCalc, values);
2176 void Focus::analyzeSources()
2179 hfrInProgress =
true;
2181 QVariantMap extractionSettings;
2182 extractionSettings[
"optionsProfileIndex"] = Options::focusOptionsProfile();
2183 extractionSettings[
"optionsProfileGroup"] =
static_cast<int>(Ekos::FocusProfiles);
2184 m_ImageData->setSourceExtractorSettings(extractionSettings);
2188 if (focusUseFullField->isChecked())
2190 m_FocusView->setTrackingBoxEnabled(
false);
2192 if (m_FocusDetection != ALGORITHM_CENTROID && m_FocusDetection != ALGORITHM_SEP)
2193 m_StarFinderWatcher.
setFuture(m_ImageData->findStars(ALGORITHM_CENTROID));
2195 m_StarFinderWatcher.
setFuture(m_ImageData->findStars(m_FocusDetection));
2199 QRect searchBox = m_FocusView->isTrackingBoxEnabled() ? m_FocusView->getTrackingBox() :
QRect();
2203 m_StarFinderWatcher.
setFuture(m_ImageData->findStars(m_FocusDetection, searchBox));
2208 m_FocusView->setTrackingBoxEnabled(
false);
2212 if (m_FocusDetection != ALGORITHM_CENTROID && m_FocusDetection != ALGORITHM_SEP)
2213 m_StarFinderWatcher.
setFuture(m_ImageData->findStars(ALGORITHM_CENTROID));
2216 m_StarFinderWatcher.
setFuture(m_ImageData->findStars(m_FocusDetection, searchBox));
2221 bool Focus::appendMeasure(
double newMeasure)
2224 starMeasureFrames.
append(newMeasure);
2228 samples.erase(std::remove_if(samples.begin(), samples.end(), [](
const double measure)
2230 return measure == INVALID_STAR_MEASURE;
2234 if (!samples.isEmpty())
2236 currentMeasure = Mathematics::RobustStatistics::ComputeLocation(
2237 Mathematics::RobustStatistics::LOCATION_SIGMACLIPPING, std::vector<double>(samples.begin(), samples.end()));
2239 switch(m_StarMeasure)
2241 case FOCUS_STAR_HFR:
2242 case FOCUS_STAR_HFR_ADJ:
2243 currentHFR = currentMeasure;
2245 case FOCUS_STAR_FWHM:
2246 currentFWHM = currentMeasure;
2248 case FOCUS_STAR_NUM_STARS:
2249 currentNumStars = currentMeasure;
2251 case FOCUS_STAR_FOURIER_POWER:
2252 currentFourierPower = currentMeasure;
2260 return starMeasureFrames.
count() < focusFramesCount->value();
2263 void Focus::settle(
const FocusState completionState,
const bool autoFocusUsed,
const bool buildOffsetsUsed)
2265 state = completionState;
2266 if (completionState == Ekos::FOCUS_COMPLETE)
2268 if (autoFocusUsed && fallbackFilterPending)
2273 m_FilterManager->setFilterAbsoluteFocusDetails(focusFilter->currentIndex(), currentPosition,
2274 m_LastSourceAutofocusTemperature, m_LastSourceAutofocusAlt);
2280 const int size = plot_position.
size();
2281 QString analysis_results =
"";
2283 for (
int i = 0; i <
size; ++i)
2286 .arg(i == 0 ?
"" :
"|" )
2291 KSNotification::event(
QLatin1String(
"FocusSuccessful"),
i18n(
"Autofocus operation completed successfully"),
2292 KSNotification::Focus);
2293 if (m_FocusAlgorithm == FOCUS_LINEAR1PASS && curveFitting !=
nullptr)
2294 emit autofocusComplete(filter(), analysis_results, curveFitting->serialize(), linearFocuser->getTextStatus(R2));
2296 emit autofocusComplete(filter(), analysis_results);
2303 KSNotification::event(
QLatin1String(
"FocusFailed"),
i18n(
"Autofocus operation failed"),
2304 KSNotification::Focus, KSNotification::Alert);
2305 emit autofocusAborted(filter(),
"");
2309 qCDebug(KSTARS_EKOS_FOCUS) <<
"Settled. State:" << Ekos::getFocusStatusString(state);
2312 if (fallbackFilterPending)
2314 m_FilterManager->setFilterPosition(fallbackFilterPosition,
2315 static_cast<FilterManager::FilterPolicy
>(FilterManager::CHANGE_POLICY | FilterManager::OFFSET_POLICY));
2318 emit newStatus(state);
2320 if (autoFocusUsed && buildOffsetsUsed)
2322 m_FilterManager->autoFocusComplete(state, currentPosition);
2327 void Focus::completeFocusProcedure(FocusState completionState,
bool plot)
2331 if (completionState == Ekos::FOCUS_COMPLETE)
2334 emit
redrawHFRPlot(polynomialFit.get(), currentPosition, currentHFR);
2336 "Focus procedure completed after %1 iterations.", plot_position.
count()));
2338 setLastFocusTemperature();
2340 setAdaptiveFocusCounters();
2344 qCInfo(KSTARS_EKOS_FOCUS) <<
"Autofocus values: position," << currentPosition <<
", temperature,"
2345 << m_LastSourceAutofocusTemperature <<
", filter," << filter()
2346 <<
", HFR," << currentHFR <<
", altitude," << m_LastSourceAutofocusAlt;
2348 if (m_FocusAlgorithm == FOCUS_POLYNOMIAL)
2351 plot_position.
append(currentPosition);
2352 plot_value.
append(currentHFR);
2355 appendFocusLogText(
QString(
"%1, %2, %3, %4, %5\n")
2363 absTicksSpin->setValue(currentPosition);
2366 else if (canAbsMove && initialFocuserAbsPosition >= 0 && resetFocusIteration <= MAXIMUM_RESET_ITERATIONS
2367 && m_RestartState != RESTART_ABORT)
2370 bool const retry_focusing = m_RestartState == RESTART_NONE && ++resetFocusIteration < MAXIMUM_RESET_ITERATIONS;
2375 m_RestartState = RESTART_NOW;
2384 emit autofocusAborted(filter(),
"");
2398 m_RestartState = RESTART_ABORT;
2404 resetFocusIteration = 0;
2407 const bool autoFocusUsed = inAutoFocus;
2408 const bool inBuildOffsetsUsed = inBuildOffsets;
2411 if (m_FocusAlgorithm == FOCUS_POLYNOMIAL && plot)
2412 emit
drawPolynomial(polynomialFit.get(), isVShapeSolution,
true);
2415 stop(completionState);
2418 int const settleTime = m_GuidingSuspended ? guideSettleTime->value() : 0;
2423 QTimer::singleShot(settleTime * 1000,
this, [ &, settleTime, completionState, autoFocusUsed, inBuildOffsetsUsed]()
2425 settle(completionState, autoFocusUsed, inBuildOffsetsUsed);
2435 if (m_Focuser && m_Focuser->isConnected() && initialFocuserAbsPosition >= 0)
2438 if (currentPosition == initialFocuserAbsPosition)
2441 appendLogText(
i18n(
"Autofocus failed, moving back to initial focus position %1.", initialFocuserAbsPosition));
2442 changeFocus(initialFocuserAbsPosition - currentPosition);
2447 void Focus::setCurrentMeasure()
2450 qCDebug(KSTARS_EKOS_FOCUS) <<
"Focus newFITS #" << starMeasureFrames.
count() + 1 <<
": Current HFR " << currentHFR <<
2452 << (starSelected ? 1 : currentNumStars);
2455 if (appendMeasure(currentMeasure))
2460 else starMeasureFrames.
clear();
2465 emit newHFR(currentHFR, currentPosition);
2467 emit newHFR(currentHFR, -1);
2470 HFROut->setText(
QString(
"%1").arg(currentHFR * getStarUnits(m_StarMeasure, m_StarUnits), 0,
'f', 2));
2471 if (m_StarMeasure == FOCUS_STAR_FWHM)
2472 FWHMOut->setText(
QString(
"%1").arg(currentFWHM * getStarUnits(m_StarMeasure, m_StarUnits), 0,
'f', 2));
2473 starsOut->setText(
QString(
"%1").arg(m_ImageData->getDetectedStars()));
2474 iterOut->setText(
QString(
"%1").arg(absIterations + 1));
2477 if (lastHFR == INVALID_STAR_MEASURE)
2484 if (m_FocusAlgorithm == FOCUS_POLYNOMIAL && isVShapeSolution)
2486 completeFocusProcedure(Ekos::FOCUS_COMPLETE);
2490 Edge selectedHFRStarHFR = m_ImageData->getSelectedHFRStar();
2497 if (starCenter.
isNull() ==
false && (inAutoFocus || minimumRequiredHFR >= 0))
2500 starSelected =
true;
2501 starCenter.
setX(qMax(0,
static_cast<int>(selectedHFRStarHFR.x)));
2502 starCenter.
setY(qMax(0,
static_cast<int>(selectedHFRStarHFR.y)));
2504 syncTrackingBoxPosition();
2508 oneStar.
setZ(currentHFR);
2509 starsHFR.
append(oneStar);
2514 QVector3D oneStar(starCenter.
x(), starCenter.
y(), currentHFR);
2515 starsHFR.
append(oneStar);
2518 if (currentHFR > maxHFR)
2519 maxHFR = currentHFR;
2527 if (inFocusLoop || (inAutoFocus && ! isPositionBased()))
2529 int pos = plot_position.
empty() ? 1 : plot_position.
last() + 1;
2530 addPlotPosition(
pos, currentHFR);
2536 QVector3D oneStar(starCenter.
x(), starCenter.
y(), INVALID_STAR_MEASURE);
2537 starsHFR.
append(oneStar);
2542 m_FocusView->updateFrame();
2547 void Focus::setCaptureComplete()
2549 DarkLibrary::Instance()->disconnect(
this);
2552 syncTrackingBoxPosition();
2555 if (inFocusLoop ==
false)
2558 if (captureInProgress && inFocusLoop ==
false && inAutoFocus ==
false)
2559 m_Camera->setUploadMode(rememberUploadMode);
2561 if (m_RememberCameraFastExposure && inFocusLoop ==
false && inAutoFocus ==
false)
2563 m_RememberCameraFastExposure =
false;
2564 m_Camera->setFastExposureEnabled(
true);
2567 captureInProgress =
false;
2569 checkMosaicMaskLimits();
2572 emit newImage(m_FocusView);
2574 emit newStarPixmap(m_FocusView->getTrackingBoxPixmap(10));
2580 if (inFocusLoop ==
false || (inFocusLoop && (m_FocusView->isTrackingBoxEnabled() || focusUseFullField->isChecked())))
2586 void Focus::setHFRComplete()
2596 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
2599 int subBinX = 1, subBinY = 1;
2600 if (!targetChip->getBinning(&subBinX, &subBinY))
2601 qCDebug(KSTARS_EKOS_FOCUS) <<
"Warning: target chip is reporting no binning property, using 1x1.";
2608 if (focusUseFullField->isChecked() ==
false && starCenter.
isNull())
2610 int x = 0,
y = 0, w = 0, h = 0;
2613 if (frameSettings.
contains(targetChip))
2615 QVariantMap settings = frameSettings[targetChip];
2616 x = settings[
"x"].toInt();
2617 y = settings[
"y"].toInt();
2618 w = settings[
"w"].toInt();
2619 h = settings[
"h"].toInt();
2623 targetChip->getFrame(&
x, &
y, &w, &h);
2626 if (focusAutoStarEnabled->isChecked())
2629 const Edge selectedHFRStar = m_ImageData->getSelectedHFRStar();
2631 if (selectedHFRStar.x == -1)
2633 appendLogText(
i18n(
"Failed to automatically select a star. Please select a star manually."));
2636 m_FocusView->setTrackingBox(
QRect(w - focusBoxSize->value() / (subBinX * 2),
2637 h - focusBoxSize->value() / (subBinY * 2),
2638 focusBoxSize->value() / subBinX, focusBoxSize->value() / subBinY));
2639 m_FocusView->setTrackingBoxEnabled(
true);
2642 state = Ekos::FOCUS_WAITING;
2643 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
2644 emit newStatus(state);
2647 waitStarSelectTimer.
start();
2653 starCenter.
setX(selectedHFRStar.x);
2654 starCenter.
setY(selectedHFRStar.y);
2655 starCenter.
setZ(subBinX);
2656 starSelected =
true;
2657 syncTrackingBoxPosition();
2660 if (subFramed ==
false && isFocusSubFrameEnabled() && focusSubFrame->isChecked())
2662 int offset = (
static_cast<double>(focusBoxSize->value()) / subBinX) * 1.5;
2663 int subX = (selectedHFRStar.x - offset) * subBinX;
2664 int subY = (selectedHFRStar.y - offset) * subBinY;
2665 int subW = offset * 2 * subBinX;
2666 int subH = offset * 2 * subBinY;
2668 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
2669 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
2676 if ((subW + subX) > maxW)
2678 if ((subH + subY) > maxH)
2683 QVariantMap settings = frameSettings[targetChip];
2684 settings[
"x"] = subX;
2685 settings[
"y"] = subY;
2686 settings[
"w"] = subW;
2687 settings[
"h"] = subH;
2688 settings[
"binx"] = subBinX;
2689 settings[
"biny"] = subBinY;
2691 qCDebug(KSTARS_EKOS_FOCUS) <<
"Frame is subframed. X:" << subX <<
"Y:" << subY <<
"W:" << subW <<
"H:" << subH <<
"binX:" <<
2692 subBinX <<
"binY:" << subBinY;
2696 frameSettings[targetChip] = settings;
2699 starCenter.
setX(subW / (2 * subBinX));
2700 starCenter.
setY(subH / (2 * subBinY));
2701 starCenter.
setZ(subBinX);
2705 m_FocusView->setFirstLoad(
true);
2714 starCenter.
setX(selectedHFRStar.x);
2715 starCenter.
setY(selectedHFRStar.y);
2716 starCenter.
setZ(subBinX);
2731 starSelected =
false;
2735 int subBinX = 1, subBinY = 1;
2736 targetChip->getBinning(&subBinX, &subBinY);
2738 m_FocusView->setTrackingBox(
QRect((w - focusBoxSize->value()) / (subBinX * 2),
2739 (h - focusBoxSize->value()) / (2 * subBinY),
2740 focusBoxSize->value() / subBinX, focusBoxSize->value() / subBinY));
2741 m_FocusView->setTrackingBoxEnabled(
true);
2744 state = Ekos::FOCUS_WAITING;
2745 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
2746 emit newStatus(state);
2749 waitStarSelectTimer.
start();
2755 if (minimumRequiredHFR >= 0)
2758 if (currentHFR == INVALID_STAR_MEASURE)
2760 if (noStarCount++ < MAX_RECAPTURE_RETRIES)
2764 if (noStarCount == MAX_RECAPTURE_RETRIES)
2773 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2778 else if (currentHFR > minimumRequiredHFR)
2780 qCDebug(KSTARS_EKOS_FOCUS) <<
"Current HFR:" << currentHFR <<
"is above required minimum HFR:" << minimumRequiredHFR <<
2781 ". Starting AutoFocus...";
2782 minimumRequiredHFR = INVALID_STAR_MEASURE;
2788 qCDebug(KSTARS_EKOS_FOCUS) <<
"Current HFR:" << currentHFR <<
"is below required minimum HFR:" << minimumRequiredHFR <<
2789 ". Autofocus successful.";
2790 completeFocusProcedure(Ekos::FOCUS_COMPLETE,
false);
2798 if (Options::focusLogging() && Options::saveFocusImages())
2809 m_ImageData->saveImage(filename);
2813 if (inAutoFocus ==
false)
2817 if (state != Ekos::FOCUS_IDLE)
2819 state = Ekos::FOCUS_IDLE;
2820 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
2821 emit newStatus(state);
2829 if (state != Ekos::FOCUS_PROGRESS)
2831 state = Ekos::FOCUS_PROGRESS;
2832 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
2833 emit newStatus(state);
2838 if (m_FocusAlgorithm == FOCUS_LINEAR || m_FocusAlgorithm == FOCUS_LINEAR1PASS)
2840 else if (canAbsMove || canRelMove)
2848 QString Focus::getyAxisLabel(StarMeasure starMeasure)
2851 m_StarUnits == FOCUS_UNITS_ARCSEC ? str +=
" (\")" : str +=
" (pix)";
2855 switch (starMeasure)
2857 case FOCUS_STAR_HFR:
2859 case FOCUS_STAR_HFR_ADJ:
2861 m_StarUnits == FOCUS_UNITS_ARCSEC ? str +=
" (\")" : str +=
" (pix)";
2863 case FOCUS_STAR_FWHM:
2865 m_StarUnits == FOCUS_UNITS_ARCSEC ? str +=
" (\")" : str +=
" (pix)";
2867 case FOCUS_STAR_NUM_STARS:
2870 case FOCUS_STAR_FOURIER_POWER:
2871 str =
"Fourier Power";
2883 polynomialFit.reset();
2884 plot_position.
clear();
2886 isVShapeSolution =
false;
2888 emit
initHFRPlot(getyAxisLabel(m_StarMeasure), getStarUnits(m_StarMeasure, m_StarUnits),
2889 m_OptDir == CurveFitting::OPTIMISATION_MINIMISE, focusUseWeights->isChecked(),
2890 inFocusLoop ==
false && isPositionBased());
2893 bool Focus::autoFocusChecks()
2895 if (++absIterations > MAXIMUM_ABS_ITERATIONS)
2897 appendLogText(
i18n(
"Autofocus failed to reach proper focus. Try increasing tolerance value."));
2898 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2903 if (currentHFR == INVALID_STAR_MEASURE)
2905 if (noStarCount < MAX_RECAPTURE_RETRIES)
2912 else if (m_FocusAlgorithm == FOCUS_LINEAR)
2914 appendLogText(
i18n(
"Failed to detect any stars at position %1. Continuing...", currentPosition));
2920 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2930 void Focus::plotLinearFocus()
2939 linearFocuser->getMeasurements(&positions, &values, &weights);
2940 const FocusAlgorithmInterface::FocusParams ¶ms = linearFocuser->getParams();
2947 bool incrementalChange =
false;
2948 if (positions.
size() > 1 && positions.
size() == lastPositions.
size() + 1)
2951 for (
int i = 0; i < positions.
size() - 1; ++i)
2952 if (positions[i] != lastPositions[i] || values[i] != lastValues[i])
2957 incrementalChange =
ok;
2959 lastPositions = positions;
2960 lastValues = values;
2962 const bool outlier =
false;
2963 if (incrementalChange)
2965 outlier, params.initialStepSize, plt);
2968 emit
initHFRPlot(getyAxisLabel(m_StarMeasure), getStarUnits(m_StarMeasure, m_StarUnits),
2969 m_OptDir == CurveFitting::OPTIMISATION_MINIMISE, params.useWeights, plt);
2970 for (
int i = 0; i < positions.
size(); ++i)
2972 outlier, params.initialStepSize, plt);
2976 if (values.
size() > 3)
2982 double minPosition, minValue;
2983 double searchMin = std::max(params.minPositionAllowed, params.startPosition - params.maxTravel);
2984 double searchMax = std::min(params.maxPositionAllowed, params.startPosition + params.maxTravel);
2986 linearFocuser->getPass1Measurements(&pass1Positions, &pass1Values, &pass1Weights, &pass1Outliers);
2987 if (m_FocusAlgorithm == FOCUS_LINEAR || m_CurveFit == CurveFitting::FOCUS_QUADRATIC)
2991 polynomialFit.reset(
new PolynomialFit(2, pass1Positions, pass1Values));
2993 if (polynomialFit->findMinimum(params.startPosition, searchMin, searchMax, &minPosition, &minValue))
2999 if (linearFocuser->isDone())
3014 if (curveFitting->findMinMax(params.startPosition, searchMin, searchMax, &minPosition, &minValue, params.curveFit,
3015 params.optimisationDirection))
3017 R2 = curveFitting->calculateR2(
static_cast<CurveFitting::CurveFit
>(params.curveFit));
3018 emit
drawCurve(curveFitting.get(),
true,
true, plt);
3026 emit
drawCurve(curveFitting.get(),
false,
false, plt);
3033 HFROut->setText(
QString(
"%1").arg(currentHFR * getStarUnits(m_StarMeasure, m_StarUnits), 0,
'f', 2));
3035 emit
setTitle(linearFocuser->getTextStatus(R2));
3037 if (!plt) HFRPlot->replot();
3041 CurveFitting::FittingGoal Focus::getGoal(
int numSteps)
3044 if (m_FocusWalk == FOCUS_WALK_CLASSIC)
3045 return CurveFitting::FittingGoal::STANDARD;
3048 return (numSteps >= focusNumSteps->value()) ? CurveFitting::FittingGoal::BEST : CurveFitting::FittingGoal::STANDARD;
3054 void Focus::plotLinearFinalUpdates()
3057 if (!focusRefineCurveFit->isChecked())
3060 emit
drawCFZ(linearFocuser->solution(), linearFocuser->solutionValue(), m_cfzSteps, focusCFZDisplayVCurve->isChecked());
3062 emit
finalUpdates(linearFocuser->getTextStatus(R2), plt);
3072 linearFocuser->getPass1Measurements(&pass1Positions, &pass1Values, &pass1Weights, &pass1Outliers);
3073 const FocusAlgorithmInterface::FocusParams ¶ms = linearFocuser->getParams();
3075 emit
initHFRPlot(getyAxisLabel(m_StarMeasure), getStarUnits(m_StarMeasure, m_StarUnits),
3076 m_OptDir == CurveFitting::OPTIMISATION_MINIMISE, focusUseWeights->isChecked(), plt);
3078 for (
int i = 0; i < pass1Positions.
size(); ++i)
3079 emit
newHFRPlotPosition(
static_cast<double>(pass1Positions[i]), pass1Values[i], (pow(pass1Weights[i], -0.5)),
3080 pass1Outliers[i], params.initialStepSize, plt);
3082 R2 = curveFitting->calculateR2(
static_cast<CurveFitting::CurveFit
>(params.curveFit));
3083 emit
drawCurve(curveFitting.get(),
true,
true,
false);
3086 emit
minimumFound(linearFocuser->solution(), linearFocuser->solutionValue(), plt);
3088 emit
drawCFZ(linearFocuser->solution(), linearFocuser->solutionValue(), m_cfzSteps, focusCFZDisplayVCurve->isChecked());
3090 emit
setTitle(linearFocuser->getTextStatus(R2), plt);
3094 void Focus::autoFocusLinear()
3096 if (!autoFocusChecks())
3099 if (!canAbsMove && !canRelMove && canTimerMove)
3102 if (linearRequestedPosition != currentPosition)
3105 qCDebug(KSTARS_EKOS_FOCUS) <<
"Linear: warning, changing position " << currentPosition <<
" to "
3106 << linearRequestedPosition;
3108 currentPosition = linearRequestedPosition;
3112 addPlotPosition(currentPosition, currentMeasure,
false);
3115 bool useFocusStarsHFR = focusUseFullField->isChecked() && focusFramesCount->value() == 1;
3116 auto focusStars = useFocusStarsHFR || (m_FocusAlgorithm == FOCUS_LINEAR1PASS) ? &(m_ImageData->getStarCenters()) :
nullptr;
3118 linearRequestedPosition = linearFocuser->newMeasurement(currentPosition, currentMeasure, currentWeight, focusStars);
3119 if (m_FocusAlgorithm == FOCUS_LINEAR1PASS && linearFocuser->isDone() && linearFocuser->solution() != -1)
3121 plotLinearFinalUpdates();
3126 if (linearFocuser->isDone())
3128 if (linearFocuser->solution() != -1)
3132 if (m_CurveFit == CurveFitting::FOCUS_QUADRATIC)
3134 completeFocusProcedure(Ekos::FOCUS_COMPLETE,
false);
3135 else if (R2 >= focusR2Limit->value())
3137 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Linear Curve Fit check passed R2=%1 focusR2Limit=%2").
arg(R2).
arg(
3138 focusR2Limit->value());
3139 completeFocusProcedure(Ekos::FOCUS_COMPLETE,
false);
3142 else if (R2Retries == 0)
3145 appendLogText(
i18n(
"Curve Fit check failed R2=%1 focusR2Limit=%2 retrying...", R2, focusR2Limit->value()));
3146 completeFocusProcedure(Ekos::FOCUS_ABORTED,
false);
3152 appendLogText(
i18n(
"Curve Fit check failed again R2=%1 focusR2Limit=%2 but continuing...", R2, focusR2Limit->value()));
3153 completeFocusProcedure(Ekos::FOCUS_COMPLETE,
false);
3159 qCDebug(KSTARS_EKOS_FOCUS) << linearFocuser->doneReason();
3161 completeFocusProcedure(Ekos::FOCUS_ABORTED,
false);
3167 const int delta = linearRequestedPosition - currentPosition;
3169 if (!changeFocus(delta))
3170 completeFocusProcedure(Ekos::FOCUS_ABORTED,
false);
3176 void Focus::autoFocusAbs()
3180 static int minHFRPos = 0, focusOutLimit = 0, focusInLimit = 0, lastHFRPos = 0, fluctuations = 0;
3181 static double minHFR = 0, lastDelta = 0;
3182 double targetPosition = 0;
3183 bool ignoreLimitedDelta =
false;
3185 QString deltaTxt =
QString(
"%1").
arg(fabs(currentHFR - minHFR) * 100.0, 0,
'g', 3);
3188 qCDebug(KSTARS_EKOS_FOCUS) <<
"========================================";
3189 qCDebug(KSTARS_EKOS_FOCUS) <<
"Current HFR: " << currentHFR <<
" Current Position: " << currentPosition;
3190 qCDebug(KSTARS_EKOS_FOCUS) <<
"Last minHFR: " << minHFR <<
" Last MinHFR Pos: " << minHFRPos;
3191 qCDebug(KSTARS_EKOS_FOCUS) <<
"Delta: " << deltaTxt <<
"%";
3192 qCDebug(KSTARS_EKOS_FOCUS) <<
"========================================";
3195 appendLogText(
i18n(
"FITS received. HFR %1 @ %2. Delta (%3%)", HFRText, currentPosition, deltaTxt));
3199 if (!autoFocusChecks())
3202 addPlotPosition(currentPosition, currentHFR);
3204 switch (m_LastFocusDirection)
3207 lastHFR = currentHFR;
3208 initialFocuserAbsPosition = currentPosition;
3209 minHFR = currentHFR;
3210 minHFRPos = currentPosition;
3220 if (absMotionMax < currentPosition + pulseDuration)
3222 if (currentPosition < absMotionMax)
3224 pulseDuration = absMotionMax - currentPosition;
3229 m_LastFocusDirection = FOCUS_IN;
3232 else if (currentPosition + pulseDuration < absMotionMin)
3234 if (absMotionMin < currentPosition)
3236 pulseDuration = currentPosition - absMotionMin;
3241 m_LastFocusDirection = FOCUS_OUT;
3245 m_LastFocusDirection = (pulseDuration > 0) ? FOCUS_OUT : FOCUS_IN;
3246 if (!changeFocus(pulseDuration))
3247 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3253 if (reverseDir && focusInLimit && focusOutLimit &&
3254 fabs(currentHFR - minHFR) < (focusTolerance->value() / 100.0) && HFRInc == 0)
3256 if (absIterations <= 2)
3258 QString message =
i18n(
"Change in HFR is too small. Try increasing the step size or decreasing the tolerance.");
3260 KSNotification::event(
QLatin1String(
"FocusFailed"),
message, KSNotification::Focus, KSNotification::Alert);
3261 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3263 else if (noStarCount > 0)
3265 QString message =
i18n(
"Failed to detect focus star in frame. Capture and select a focus star.");
3267 KSNotification::event(
QLatin1String(
"FocusFailed"),
message, KSNotification::Focus, KSNotification::Alert);
3268 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3272 completeFocusProcedure(Ekos::FOCUS_COMPLETE);
3276 else if (currentHFR < lastHFR)
3279 if (HFRInc >= 1 && m_LastFocusDirection == FOCUS_OUT && lastHFRPos < focusInLimit && fabs(currentHFR - lastHFR) > 0.1)
3281 focusInLimit = lastHFRPos;
3282 qCDebug(KSTARS_EKOS_FOCUS) <<
"New FocusInLimit " << focusInLimit;
3284 else if (HFRInc >= 1 && m_LastFocusDirection == FOCUS_IN && lastHFRPos > focusOutLimit &&
3285 fabs(currentHFR - lastHFR) > 0.1)
3287 focusOutLimit = lastHFRPos;
3288 qCDebug(KSTARS_EKOS_FOCUS) <<
"New FocusOutLimit " << focusOutLimit;
3291 double factor = std::max(1.0, HFRDec / 2.0);
3292 if (m_LastFocusDirection == FOCUS_IN)
3293 targetPosition = currentPosition - (pulseDuration * factor);
3295 targetPosition = currentPosition + (pulseDuration * factor);
3297 qCDebug(KSTARS_EKOS_FOCUS) <<
"current Position" << currentPosition <<
" targetPosition " << targetPosition;
3299 lastHFR = currentHFR;
3302 if (lastHFR < minHFR)
3305 minHFRPos = currentPosition;
3306 qCDebug(KSTARS_EKOS_FOCUS) <<
"new minHFR " << minHFR <<
" @ position " << minHFRPos;
3309 lastHFRPos = currentPosition;
3316 if (plot_position.
count() >= 2)
3333 lastHFR = currentHFR;
3334 lastHFRPos = currentPosition;
3343 qCDebug(KSTARS_EKOS_FOCUS) <<
"Focus is moving away from optimal HFR.";
3346 if (m_LastFocusDirection == FOCUS_IN)
3348 focusInLimit = currentPosition;
3349 qCDebug(KSTARS_EKOS_FOCUS) <<
"Setting focus IN limit to " << focusInLimit;
3353 focusOutLimit = currentPosition;
3354 qCDebug(KSTARS_EKOS_FOCUS) <<
"Setting focus OUT limit to " << focusOutLimit;
3357 if (m_FocusAlgorithm == FOCUS_POLYNOMIAL && plot_position.
count() > 4)
3359 polynomialFit.reset(
new PolynomialFit(2, 5, plot_position, plot_value));
3362 double min_position = 0, min_hfr = 0;
3363 isVShapeSolution = polynomialFit->findMinimum(minHFRPos, a, b, &min_position, &min_hfr);
3364 qCDebug(KSTARS_EKOS_FOCUS) <<
"Found Minimum?" << (isVShapeSolution ?
"Yes" :
"No");
3365 if (isVShapeSolution)
3367 ignoreLimitedDelta =
true;
3368 qCDebug(KSTARS_EKOS_FOCUS) <<
"Minimum Solution:" << min_hfr <<
"@" << min_position;
3369 targetPosition = round(min_position);
3372 emit
drawPolynomial(polynomialFit.get(), isVShapeSolution,
true);
3377 emit
drawPolynomial(polynomialFit.get(), isVShapeSolution,
false);
3386 if (std::abs(lastDelta) > 0)
3387 targetPosition = currentPosition + lastDelta;
3389 targetPosition = currentPosition + pulseDuration;
3391 else if (isVShapeSolution ==
false)
3393 ignoreLimitedDelta =
true;
3395 if (m_LastFocusDirection == FOCUS_OUT)
3396 targetPosition = minHFRPos - pulseDuration / 2;
3398 targetPosition = minHFRPos + pulseDuration / 2;
3401 qCDebug(KSTARS_EKOS_FOCUS) <<
"new targetPosition " << targetPosition;
3405 if (focusInLimit != 0 && m_LastFocusDirection == FOCUS_IN && targetPosition < focusInLimit)
3407 targetPosition = focusInLimit;
3408 qCDebug(KSTARS_EKOS_FOCUS) <<
"Limiting target pulse to focus in limit " << targetPosition;
3410 else if (focusOutLimit != 0 && m_LastFocusDirection == FOCUS_OUT && targetPosition > focusOutLimit)
3412 targetPosition = focusOutLimit;
3413 qCDebug(KSTARS_EKOS_FOCUS) <<
"Limiting target pulse to focus out limit " << targetPosition;
3417 if (targetPosition < absMotionMin)
3418 targetPosition = absMotionMin;
3419 else if (targetPosition > absMotionMax)
3420 targetPosition = absMotionMax;
3423 if (targetPosition == currentPosition)
3427 if (targetPosition == minHFRPos || isVShapeSolution)
3429 appendLogText(
"Stopping at minimum recorded HFR position.");
3430 completeFocusProcedure(Ekos::FOCUS_COMPLETE);
3434 QString message =
i18n(
"Focuser cannot move further, device limits reached. Autofocus aborted.");
3436 KSNotification::event(
QLatin1String(
"FocusFailed"),
message, KSNotification::Focus, KSNotification::Alert);
3437 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3443 if (fluctuations >= MAXIMUM_FLUCTUATIONS)
3445 QString message =
i18n(
"Unstable fluctuations. Try increasing initial step size or exposure time.");
3447 KSNotification::event(
QLatin1String(
"FocusFailed"),
message, KSNotification::Focus, KSNotification::Alert);
3448 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3453 if (focusOutLimit && focusOutLimit == focusInLimit)
3455 QString message =
i18n(
"Deadlock reached. Please try again with different settings.");
3457 KSNotification::event(
QLatin1String(
"FocusFailed"),
message, KSNotification::Focus, KSNotification::Alert);
3458 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3463 if (fabs(targetPosition - initialFocuserAbsPosition) > focusMaxTravel->value())
3465 int minTravelLimit = qMax(0.0, initialFocuserAbsPosition - focusMaxTravel->value());
3466 int maxTravelLimit = qMin(absMotionMax, initialFocuserAbsPosition + focusMaxTravel->value());
3470 if (fabs(currentPosition - minTravelLimit) > 10 && targetPosition < minTravelLimit)
3472 targetPosition = minTravelLimit;
3475 else if (fabs(currentPosition - maxTravelLimit) > 10 && targetPosition > maxTravelLimit)
3477 targetPosition = maxTravelLimit;
3481 qCDebug(KSTARS_EKOS_FOCUS) <<
"targetPosition (" << targetPosition <<
") - initHFRAbsPos ("
3482 << initialFocuserAbsPosition <<
") exceeds maxTravel distance of " << focusMaxTravel->value();
3486 KSNotification::event(
QLatin1String(
"FocusFailed"),
message, KSNotification::Focus, KSNotification::Alert);
3487 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3493 lastDelta = (targetPosition - currentPosition);
3495 qCDebug(KSTARS_EKOS_FOCUS) <<
"delta (targetPosition - currentPosition) " << lastDelta;
3498 if (ignoreLimitedDelta ==
false)
3500 double limitedDelta = qMax(-1.0 * focusMaxSingleStep->value(), qMin(1.0 * focusMaxSingleStep->value(), lastDelta));
3501 if (std::fabs(limitedDelta - lastDelta) > 0)
3503 qCDebug(KSTARS_EKOS_FOCUS) <<
"Limited delta to maximum permitted single step " << focusMaxSingleStep->value();
3504 lastDelta = limitedDelta;
3508 m_LastFocusDirection = (lastDelta > 0) ? FOCUS_OUT : FOCUS_IN;
3509 if (!changeFocus(lastDelta))
3510 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3516 void Focus::addPlotPosition(
int pos,
double value,
bool plot)
3519 plot_value.
append(value);
3524 void Focus::autoFocusRel()
3526 static int noStarCount = 0;
3527 static double minHFR = 1e6;
3528 QString deltaTxt =
QString(
"%1").
arg(fabs(currentHFR - minHFR) * 100.0, 0,
'g', 2);
3532 appendLogText(
i18n(
"FITS received. HFR %1. Delta (%2%) Min HFR (%3)", HFRText, deltaTxt, minHFRText));
3534 if (pulseDuration <= MINIMUM_PULSE_TIMER)
3536 appendLogText(
i18n(
"Autofocus failed to reach proper focus. Try adjusting the tolerance value."));
3537 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3542 if (currentHFR == INVALID_STAR_MEASURE)
3544 if (noStarCount < MAX_RECAPTURE_RETRIES)
3551 else if (m_FocusAlgorithm == FOCUS_LINEAR || m_FocusAlgorithm == FOCUS_LINEAR1PASS)
3553 appendLogText(
i18n(
"Failed to detect any stars at position %1. Continuing...", currentPosition));
3559 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3566 switch (m_LastFocusDirection)
3569 lastHFR = currentHFR;
3571 m_LastFocusDirection = FOCUS_IN;
3572 changeFocus(-pulseDuration);
3577 if (fabs(currentHFR - minHFR) < (focusTolerance->value() / 100.0) && HFRInc == 0)
3579 completeFocusProcedure(Ekos::FOCUS_COMPLETE);
3581 else if (currentHFR < lastHFR)
3583 if (currentHFR < minHFR)
3584 minHFR = currentHFR;
3586 lastHFR = currentHFR;
3587 changeFocus(m_LastFocusDirection == FOCUS_IN ? -pulseDuration : pulseDuration);
3594 lastHFR = currentHFR;
3598 pulseDuration *= 0.75;
3600 if (!changeFocus(m_LastFocusDirection == FOCUS_IN ? pulseDuration : -pulseDuration))
3601 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3604 m_LastFocusDirection = (m_LastFocusDirection == FOCUS_IN) ? FOCUS_OUT : FOCUS_IN;
3610 void Focus::autoFocusProcessPositionChange(IPState state)
3612 if (state == IPS_OK && captureInProgress ==
false)
3618 if (focuserAdditionalMovement > 0)
3620 int temp = focuserAdditionalMovement;
3621 focuserAdditionalMovement = 0;
3622 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Undoing overscan extension. Moving back in by %1").
arg(temp);
3627 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3630 else if (inAutoFocus)
3632 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Focus position reached at %1, starting capture in %2 seconds.").
arg(
3633 currentPosition).
arg(focusSettleTime->value());
3634 capture(focusSettleTime->value());
3637 else if (state == IPS_ALERT)
3640 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3646 if (m_Focuser ==
nullptr || prop.getType() != INDI_NUMBER || prop.getDeviceName() != m_Focuser->getDeviceName())
3649 auto nvp = prop.getNumber();
3655 if (nvp->isNameMatch(
"FOCUS_BACKLASH_STEPS"))
3657 focusBacklash->setValue(nvp->np[0].value);
3661 if (nvp->isNameMatch(
"ABS_FOCUS_POSITION"))
3666 if (m_DebugFocuserCounter++ >= 10 && m_DebugFocuserCounter <= 14)
3668 if (m_DebugFocuserCounter == 14)
3669 m_DebugFocuserCounter = 0;
3675 m_FocusMotionTimer.
stop();
3676 INumber *
pos = IUFindNumber(nvp,
"FOCUS_ABSOLUTE_POSITION");
3681 int newPosition =
static_cast<int>(
pos->value);
3686 if (currentPosition == newPosition && currentPositionState == nvp->s)
3689 currentPositionState = nvp->s;
3691 if (currentPosition != newPosition)
3693 currentPosition = newPosition;
3694 qCDebug(KSTARS_EKOS_FOCUS) <<
"Abs Focuser position changed to " << currentPosition <<
"State:" << pstateStr(
3695 currentPositionState);
3697 emit absolutePositionChanged(currentPosition);
3701 if (nvp->s != IPS_OK)
3703 if (inAutoFocus || inAdjustFocus || inAdaptiveFocus)
3707 qCDebug(KSTARS_EKOS_FOCUS) <<
"Restarting focus motion timer...";
3708 m_FocusMotionTimer.
start();
3718 if (focuserAdditionalMovement == 0)
3720 inAdjustFocus =
false;
3721 emit focusPositionAdjusted();
3726 if (inAdaptiveFocus)
3728 if (focuserAdditionalMovement == 0)
3730 inAdaptiveFocus =
false;
3732 emit adaptiveFocusComplete(filter(), m_LastAdaptiveFocusTemperature, m_LastAdaptiveFocusTempTicks, m_LastAdaptiveFocusAlt,
3733 m_LastAdaptiveFocusAltTicks, m_LastAdaptiveFocusTotalTicks, m_LastAdaptiveFocusPosition);
3737 emit focusAdaptiveComplete(true);
3743 if (m_RestartState == RESTART_NOW && status() != Ekos::FOCUS_ABORTED)
3745 if (focuserAdditionalMovement == 0)
3747 m_RestartState = RESTART_NONE;
3748 inAutoFocus = inAdjustFocus = inAdaptiveFocus =
false;
3753 else if (m_RestartState == RESTART_ABORT)
3759 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3760 m_RestartState = RESTART_NONE;
3761 inAutoFocus = inAdjustFocus = inAdaptiveFocus =
false;
3766 autoFocusProcessPositionChange(nvp->s);
3767 else if (nvp->s == IPS_ALERT)
3775 if (nvp->isNameMatch(
"manualfocusdrive"))
3780 if (m_DebugFocuserCounter++ >= 10 && m_DebugFocuserCounter <= 14)
3782 if (m_DebugFocuserCounter == 14)
3783 m_DebugFocuserCounter = 0;
3789 m_FocusMotionTimer.
stop();
3791 INumber *
pos = IUFindNumber(nvp,
"manualfocusdrive");
3792 if (
pos && nvp->s == IPS_OK)
3794 currentPosition +=
pos->value;
3795 absTicksLabel->setText(
QString::number(
static_cast<int>(currentPosition)));
3796 emit absolutePositionChanged(currentPosition);
3799 if (inAdjustFocus && nvp->s == IPS_OK)
3801 if (focuserAdditionalMovement == 0)
3803 inAdjustFocus =
false;
3804 emit focusPositionAdjusted();
3809 if (inAdaptiveFocus && nvp->s == IPS_OK)
3811 if (focuserAdditionalMovement == 0)
3813 inAdaptiveFocus =
false;
3816 emit focusAdaptiveComplete(true);
3823 if (m_RestartState == RESTART_NOW && nvp->s == IPS_OK && status() != Ekos::FOCUS_ABORTED)
3825 if (focuserAdditionalMovement == 0)
3827 m_RestartState = RESTART_NONE;
3828 inAutoFocus = inAdjustFocus = inAdaptiveFocus =
false;
3833 else if (m_RestartState == RESTART_ABORT && nvp->s == IPS_OK)
3836 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3837 m_RestartState = RESTART_NONE;
3838 inAutoFocus = inAdjustFocus = inAdaptiveFocus =
false;
3842 autoFocusProcessPositionChange(nvp->s);
3843 else if (nvp->s == IPS_ALERT)
3849 if (nvp->isNameMatch(
"REL_FOCUS_POSITION"))
3851 m_FocusMotionTimer.
stop();
3853 INumber *
pos = IUFindNumber(nvp,
"FOCUS_RELATIVE_POSITION");
3854 if (
pos && nvp->s == IPS_OK)
3856 currentPosition +=
pos->value * (m_LastFocusDirection == FOCUS_IN ? -1 : 1);
3857 qCDebug(KSTARS_EKOS_FOCUS)
3858 <<
QString(
"Rel Focuser position changed by %1 to %2")
3860 absTicksLabel->setText(
QString::number(
static_cast<int>(currentPosition)));
3861 emit absolutePositionChanged(currentPosition);
3864 if (inAdjustFocus && nvp->s == IPS_OK)
3866 if (focuserAdditionalMovement == 0)
3868 inAdjustFocus =
false;
3869 emit focusPositionAdjusted();
3874 if (inAdaptiveFocus && nvp->s == IPS_OK)
3876 if (focuserAdditionalMovement == 0)
3878 inAdaptiveFocus =
false;
3881 emit focusAdaptiveComplete(true);
3888 if (m_RestartState == RESTART_NOW && nvp->s == IPS_OK && status() != Ekos::FOCUS_ABORTED)
3890 if (focuserAdditionalMovement == 0)
3892 m_RestartState = RESTART_NONE;
3893 inAutoFocus = inAdjustFocus = inAdaptiveFocus =
false;
3898 else if (m_RestartState == RESTART_ABORT && nvp->s == IPS_OK)
3901 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3902 m_RestartState = RESTART_NONE;
3903 inAutoFocus = inAdjustFocus = inAdaptiveFocus =
false;
3907 autoFocusProcessPositionChange(nvp->s);
3908 else if (nvp->s == IPS_ALERT)
3917 if (nvp->isNameMatch(
"FOCUS_TIMER"))
3919 m_FocusMotionTimer.
stop();
3921 if (m_RestartState == RESTART_NOW && nvp->s == IPS_OK && status() != Ekos::FOCUS_ABORTED)
3923 if (focuserAdditionalMovement == 0)
3925 m_RestartState = RESTART_NONE;
3926 inAutoFocus = inAdjustFocus = inAdaptiveFocus =
false;
3931 else if (m_RestartState == RESTART_ABORT && nvp->s == IPS_OK)
3934 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3935 m_RestartState = RESTART_NONE;
3936 inAutoFocus = inAdjustFocus = inAdaptiveFocus =
false;
3939 if (canAbsMove ==
false && canRelMove ==
false)
3942 INumber *
pos = IUFindNumber(nvp,
"FOCUS_TIMER_VALUE");
3945 currentPosition +=
pos->value * (m_LastFocusDirection == FOCUS_IN ? -1 : 1);
3946 qCDebug(KSTARS_EKOS_FOCUS)
3947 <<
QString(
"Timer Focuser position changed by %1 to %2")
3950 autoFocusProcessPositionChange(nvp->s);
3952 else if (nvp->s == IPS_ALERT)
3961 m_LogText.
insert(0,
i18nc(
"log entry; %1 is the date, %2 is the text",
"%1 %2",
3962 KStarsData::Instance()->lt().toString(
"yyyy-MM-ddThh:mm:ss"), text));
3964 qCInfo(KSTARS_EKOS_FOCUS) << text;
3969 void Focus::clearLog()
3975 void Focus::appendFocusLogText(
const QString &lines)
3977 if (Options::focusLogging())
3980 if (!m_FocusLogFile.
exists())
3984 dir.mkpath(
"focuslogs");
3986 if (m_FocusLogEnabled)
3989 header <<
"date, time, position, temperature, filter, HFR, altitude\n";
3993 qCWarning(KSTARS_EKOS_FOCUS) <<
"Failed to open focus log file: " << m_FocusLogFileName;
3996 if (m_FocusLogEnabled)
4007 if (m_Camera ==
nullptr)
4013 waitStarSelectTimer.
stop();
4016 starMeasureFrames.
clear();
4021 state = Ekos::FOCUS_FRAMING;
4022 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
4023 emit newStatus(state);
4032 void Focus::resetButtons()
4036 startFocusB->setEnabled(
false);
4037 startLoopB->setEnabled(
false);
4038 stopFocusB->setEnabled(
true);
4039 captureB->setEnabled(
false);
4040 opticalTrainCombo->setEnabled(
false);
4041 trainB->setEnabled(
false);
4055 if (disabledWidgets.
empty())
4057 AFDisable(trainLabel,
false);
4058 AFDisable(opticalTrainCombo,
false);
4059 AFDisable(trainB,
false);
4060 AFDisable(focuserGroup,
true);
4061 AFDisable(clearDataB,
false);
4064 m_FocusGainAFEnabled = focusGain->isEnabled();
4065 m_FocusISOAFEnabled = focusISO->isEnabled();
4066 AFDisable(ccdGroup,
false);
4069 m_FocusSubFrameAFEnabled = focusSubFrame->isEnabled();
4070 AFDisable(tabWidget,
false);
4073 stopFocusB->setEnabled(
true);
4079 for(
int i = 0 ; i < disabledWidgets.
size() ; i++)
4081 disabledWidgets.
clear();
4083 auto enableCaptureButtons = (captureInProgress ==
false && hfrInProgress ==
false);
4085 captureB->setEnabled(enableCaptureButtons);
4086 resetFrameB->setEnabled(enableCaptureButtons);
4087 startLoopB->setEnabled(enableCaptureButtons);
4088 focusAutoStarEnabled->setEnabled(enableCaptureButtons && focusUseFullField->isChecked() ==
false);
4090 if (m_Focuser && m_Focuser->isConnected())
4092 focusOutB->setEnabled(
true);
4093 focusInB->setEnabled(
true);
4095 startFocusB->setEnabled(m_FocusType == FOCUS_AUTO);
4096 stopFocusB->setEnabled(!enableCaptureButtons);
4097 startGotoB->setEnabled(canAbsMove);
4098 stopGotoB->setEnabled(
true);
4102 focusOutB->setEnabled(
false);
4103 focusInB->setEnabled(
false);
4105 startFocusB->setEnabled(
false);
4106 stopFocusB->setEnabled(
false);
4107 startGotoB->setEnabled(
false);
4108 stopGotoB->setEnabled(
false);
4113 void Focus::AFDisable(
QWidget * widget,
const bool children)
4120 if (wid->isEnabled())
4122 wid->setEnabled(
false);
4136 bool Focus::isFocusGainEnabled()
4138 return (inAutoFocus) ? m_FocusGainAFEnabled : focusGain->isEnabled();
4141 bool Focus::isFocusISOEnabled()
4143 return (inAutoFocus) ? m_FocusISOAFEnabled : focusISO->isEnabled();
4146 bool Focus::isFocusSubFrameEnabled()
4148 return (inAutoFocus) ? m_FocusSubFrameAFEnabled : focusSubFrame->isEnabled();
4151 void Focus::updateBoxSize(
int value)
4153 if (m_Camera ==
nullptr)
4156 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
4158 if (targetChip ==
nullptr)
4161 int subBinX, subBinY;
4162 targetChip->getBinning(&subBinX, &subBinY);
4164 QRect trackBox = m_FocusView->getTrackingBox();
4168 QRect(
center.x() - value / (2 * subBinX),
center.y() - value / (2 * subBinY), value / subBinX, value / subBinY);
4170 m_FocusView->setTrackingBox(trackBox);
4175 if (m_ImageData.
isNull())
4182 emit newImage(m_FocusView);
4188 if (state == Ekos::FOCUS_PROGRESS)
4191 if (subFramed ==
false)
4193 rememberStarCenter.
setX(
x);
4194 rememberStarCenter.
setY(
y);
4197 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
4199 int subBinX, subBinY;
4200 targetChip->getBinning(&subBinX, &subBinY);
4203 if (subBinX != (focusBinning->currentIndex() + 1))
4209 int offset = (
static_cast<double>(focusBoxSize->value()) / subBinX) * 1.5;
4213 bool squareMovedOutside =
false;
4215 if (subFramed ==
false && focusSubFrame->isChecked() && targetChip->canSubframe())
4217 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
4219 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
4222 x = (
x - offset) * subBinX;
4223 y = (
y - offset) * subBinY;
4224 int w = offset * 2 * subBinX;
4225 int h = offset * 2 * subBinY;
4244 QVariantMap settings = frameSettings[targetChip];
4249 settings[
"binx"] = subBinX;
4250 settings[
"biny"] = subBinY;
4252 frameSettings[targetChip] = settings;
4256 qCDebug(KSTARS_EKOS_FOCUS) <<
"Frame is subframed. X:" <<
x <<
"Y:" <<
y <<
"W:" << w <<
"H:" << h <<
"binX:" << subBinX <<
4259 m_FocusView->setFirstLoad(
true);
4264 starCenter.
setX(w / (2 * subBinX));
4265 starCenter.
setY(h / (2 * subBinY));
4270 double dist = sqrt((starCenter.
x() -
x) * (starCenter.
x() -
x) + (starCenter.
y() -
y) * (starCenter.
y() -
y));
4272 squareMovedOutside = (dist > (
static_cast<double>(focusBoxSize->value()) / subBinX));
4276 starRect =
QRect(starCenter.
x() - focusBoxSize->value() / (2 * subBinX),
4277 starCenter.
y() - focusBoxSize->value() / (2 * subBinY), focusBoxSize->value() / subBinX,
4278 focusBoxSize->value() / subBinY);
4279 m_FocusView->setTrackingBox(starRect);
4284 starCenter.
setZ(subBinX);
4286 if (squareMovedOutside && inAutoFocus ==
false && focusAutoStarEnabled->isChecked())
4288 focusAutoStarEnabled->blockSignals(
true);
4289 focusAutoStarEnabled->setChecked(
false);
4290 focusAutoStarEnabled->blockSignals(
false);
4291 appendLogText(
i18n(
"Disabling Auto Star Selection as star selection box was moved manually."));
4292 starSelected =
false;
4294 else if (starSelected ==
false)
4297 starSelected =
true;
4301 waitStarSelectTimer.
stop();
4302 FocusState nextState = inAutoFocus ? FOCUS_PROGRESS : FOCUS_IDLE;
4303 if (nextState != state)
4306 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
4307 emit newStatus(state);
4313 if (inAutoFocus || inFocusLoop || inAdjustFocus || inAdaptiveFocus || inBuildOffsets)
4315 qCDebug(KSTARS_EKOS_FOCUS) <<
"Check Focus rejected, focus procedure is already running.";
4319 qCDebug(KSTARS_EKOS_FOCUS) <<
"Check Focus requested with minimum required HFR" << requiredHFR;
4320 minimumRequiredHFR = requiredHFR;
4330 if (inAutoFocus || inFocusLoop || inAdjustFocus || inAdaptiveFocus)
4331 qCDebug(KSTARS_EKOS_FOCUS) <<
"runAutoFocus rejected, focus procedure is already running.";
4335 inBuildOffsets = buildOffsets;
4340 void Focus::toggleSubframe(
bool enable)
4342 if (enable ==
false)
4345 starSelected =
false;
4351 focusAutoStarEnabled->setEnabled(
true);
4353 focusNoMaskRB->setChecked(
true);
4358 focusAutoStarEnabled->setChecked(
false);
4359 focusAutoStarEnabled->setEnabled(
false);
4364 focusRingMaskRB->setEnabled(!enable);
4365 focusMosaicMaskRB->setEnabled(!enable);
4374 void Focus::setUseWeights()
4376 if (m_CurveFit == CurveFitting::FOCUS_QUADRATIC || !focusUseFullField->isChecked() || m_StarMeasure == FOCUS_STAR_NUM_STARS
4377 || m_StarMeasure == FOCUS_STAR_FOURIER_POWER)
4379 focusUseWeights->setEnabled(
false);
4380 focusUseWeights->setChecked(
false);
4383 focusUseWeights->setEnabled(
true);
4389 focusExposure->setValue(value);
4394 INDI_UNUSED(subBinY);
4395 focusBinning->setCurrentIndex(subBinX - 1);
4400 focusAutoStarEnabled->setChecked(enable);
4405 focusSubFrame->setChecked(enable);
4410 focusBoxSize->setValue(boxSize);
4411 focusTicks->setValue(stepSize);
4412 focusMaxTravel->setValue(maxTravel);
4413 focusTolerance->setValue(tolerance);
4416 void Focus::checkAutoStarTimeout()
4419 if (starCenter.
isNull() && (inAutoFocus || minimumRequiredHFR > 0))
4423 if (rememberStarCenter.
isNull() ==
false)
4431 initialFocuserAbsPosition = -1;
4433 completeFocusProcedure(Ekos::FOCUS_ABORTED);
4435 else if (state == FOCUS_WAITING)
4438 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
4439 emit newStatus(state);
4443 void Focus::setAbsoluteFocusTicks()
4445 if (!changeFocus(absTicksSpin->value() - currentPosition))
4446 qCDebug(KSTARS_EKOS_FOCUS) <<
"setAbsoluteFocusTicks unable to move focuser.";
4449 void Focus::syncTrackingBoxPosition()
4451 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
4452 Q_ASSERT(targetChip);
4454 int subBinX = 1, subBinY = 1;
4455 targetChip->getBinning(&subBinX, &subBinY);
4457 if (starCenter.
isNull() ==
false)
4459 double boxSize = focusBoxSize->value();
4461 targetChip->getFrame(&
x, &
y, &w, &h);
4463 if (boxSize / subBinX >= w || boxSize / subBinY >= h)
4465 focusBoxSize->setValue((boxSize / subBinX >= w) ? w : h);
4470 if (subBinX != starCenter.
z())
4472 if (starCenter.
z() > 0)
4474 starCenter.
setX(starCenter.
x() * (starCenter.
z() / subBinX));
4475 starCenter.
setY(starCenter.
y() * (starCenter.
z() / subBinY));
4478 starCenter.
setZ(subBinX);
4481 QRect starRect =
QRect(starCenter.
x() - boxSize / (2 * subBinX), starCenter.
y() - boxSize / (2 * subBinY),
4482 boxSize / subBinX, boxSize / subBinY);
4483 m_FocusView->setTrackingBoxEnabled(
true);
4484 m_FocusView->setTrackingBox(starRect);
4488 void Focus::showFITSViewer()
4490 static int lastFVTabID = -1;
4497 fv->loadData(m_ImageData, url, &lastFVTabID);
4499 else if (fv->updateData(m_ImageData, url, lastFVTabID, &lastFVTabID) ==
false)
4500 fv->loadData(m_ImageData, url, &lastFVTabID);
4506 void Focus::adjustFocusOffset(
int value,
bool useAbsoluteOffset)
4510 qCDebug(KSTARS_EKOS_FOCUS) <<
"adjustFocusOffset called whilst inAdjustFocus in progress. Ignoring...";
4516 qCDebug(KSTARS_EKOS_FOCUS) <<
"adjustFocusOffset called whilst inFocusLoop. Ignoring...";
4521 if (inAdaptiveFocus)
4523 qCDebug(KSTARS_EKOS_FOCUS) <<
"adjustFocusOffset called whilst inAdaptiveFocus. Ignoring...";
4527 inAdjustFocus =
true;
4530 int newPosition = (useAbsoluteOffset) ? value : value + currentPosition;
4532 if (!changeFocus(newPosition - currentPosition))
4533 qCDebug(KSTARS_EKOS_FOCUS) <<
"adjustFocusOffset unable to move focuser";
4536 void Focus::toggleFocusingWidgetFullScreen()
4538 if (focusingWidget->parent() ==
nullptr)
4540 focusingWidget->setParent(
this);
4541 rightLayout->insertWidget(0, focusingWidget);
4542 focusingWidget->showNormal();
4546 focusingWidget->setParent(
nullptr);
4547 focusingWidget->setWindowTitle(
i18nc(
"@title:window",
"Focus Frame"));
4549 focusingWidget->showMaximized();
4550 focusingWidget->show();
4554 void Focus::setMountStatus(ISD::Mount::Status newState)
4558 case ISD::Mount::MOUNT_PARKING:
4559 case ISD::Mount::MOUNT_SLEWING:
4560 case ISD::Mount::MOUNT_MOVING:
4561 captureB->setEnabled(
false);
4562 startFocusB->setEnabled(
false);
4563 startLoopB->setEnabled(
false);
4578 void Focus::setMountCoords(
const SkyPoint &position, ISD::Mount::PierSide pierSide,
const dms &ha)
4587 auto name = deviceRemoved->getDeviceName();
4591 if (m_Focuser && m_Focuser->getDeviceName() == name)
4594 m_Focuser =
nullptr;
4603 for (
auto &oneSource : m_TemperatureSources)
4605 if (oneSource->getDeviceName() == name)
4607 m_TemperatureSources.removeAll(oneSource);
4610 defaultFocusTemperatureSource->removeItem(defaultFocusTemperatureSource->findText(name));
4617 if (m_Camera && m_Camera->getDeviceName() == name)
4630 if (m_FilterWheel && m_FilterWheel->getDeviceName() == name)
4632 m_FilterWheel->disconnect(
this);
4633 m_FilterWheel =
nullptr;
4646 if (m_FilterManager)
4647 m_FilterManager->disconnect(
this);
4650 Ekos::Manager::Instance()->createFilterManager(m_FilterWheel);
4653 Ekos::Manager::Instance()->getFilterManager(m_FilterWheel->getDeviceName(), m_FilterManager);
4660 connect(
this, &Focus::absolutePositionChanged, m_FilterManager.
get(), &FilterManager::setFocusAbsolutePosition);
4663 connect(
this, &Focus::newStatus,
this, [
this](Ekos::FocusState state)
4665 if (m_FilterManager)
4667 m_FilterManager->setFocusStatus(state);
4668 if (focusFilter->currentIndex() != -1 && canAbsMove && state == Ekos::FOCUS_COMPLETE)
4670 m_FilterManager->setFilterAbsoluteFocusDetails(focusFilter->currentIndex(), currentPosition,
4671 m_LastSourceAutofocusTemperature, m_LastSourceAutofocusAlt);
4681 connect(m_FilterManager.
get(), &FilterManager::newStatus,
this, [
this](Ekos::FilterState filterState)
4685 if (filterState == FILTER_OFFSET && state != Ekos::FOCUS_PROGRESS)
4687 if (m_GuidingSuspended == false && focusSuspendGuiding->isChecked())
4689 m_GuidingSuspended = true;
4690 emit suspendGuiding();
4696 connect(m_FilterManager.get(), &FilterManager::ready,
this, [
this]()
4699 if (focusFilter->currentIndex() != currentFilterPosition - 1)
4700 focusFilter->setCurrentIndex(currentFilterPosition - 1);
4702 if (filterPositionPending)
4704 filterPositionPending = false;
4707 else if (fallbackFilterPending)
4709 fallbackFilterPending =
false;
4710 emit newStatus(state);
4715 connect(m_FilterManager.get(), &FilterManager::failed,
this, [
this]()
4717 appendLogText(i18n(
"Filter operation failed."));
4718 completeFocusProcedure(Ekos::FOCUS_ABORTED);
4722 connect(m_FilterManager.get(), &FilterManager::checkFocus,
this, &Focus::checkFocus);
4725 connect(m_FilterManager.get(), &FilterManager::runAutoFocus,
this, &Focus::runAutoFocus);
4728 connect(m_FilterManager.get(), &FilterManager::abortAutoFocus,
this, &Focus::abort);
4731 connect(m_FilterManager.get(), &FilterManager::newFocusOffset,
this, &Focus::adjustFocusOffset);
4734 connect(m_FilterManager.get(), &FilterManager::labelsChanged,
this, [
this]()
4736 focusFilter->clear();
4737 focusFilter->addItems(m_FilterManager->getFilterLabels());
4738 currentFilterPosition = m_FilterManager->getFilterPosition();
4739 focusFilter->setCurrentIndex(currentFilterPosition - 1);
4743 connect(m_FilterManager.get(), &FilterManager::positionChanged,
this, [
this]()
4745 currentFilterPosition = m_FilterManager->getFilterPosition();
4746 focusFilter->setCurrentIndex(currentFilterPosition - 1);
4750 connect(m_FilterManager.get(), &FilterManager::exposureChanged,
this, [
this]()
4752 focusExposure->setValue(m_FilterManager->getFilterExposure());
4756 connect(m_FilterManager.get(), &FilterManager::wavelengthChanged,
this, [
this]()
4758 wavelengthChanged();
4762 void Focus::connectFilterManager()
4767 if (m_FilterManager)
4769 m_FilterManager->refreshFilterModel();
4770 m_FilterManager->show();
4771 m_FilterManager->raise();
4776 connect(
this, &Focus::focusPositionAdjusted,
this, [
this]()
4778 if (m_FilterManager)
4779 m_FilterManager->setFocusOffsetComplete();
4780 if (m_GuidingSuspended && state != Ekos::FOCUS_PROGRESS)
4784 m_GuidingSuspended = false;
4785 emit resumeGuiding();
4793 if (m_FilterManager)
4794 m_FilterManager->setFilterExposure(focusFilter->currentIndex(), focusExposure->value());
4800 if (m_FilterManager)
4802 focusExposure->setValue(m_FilterManager->getFilterExposure(text));
4810 void Focus::toggleVideo(
bool enabled)
4812 if (m_Camera ==
nullptr)
4815 if (m_Camera->isBLOBEnabled() ==
false)
4818 if (Options::guiderType() != Ekos::Guide::GUIDE_INTERNAL)
4819 m_Camera->setBLOBEnabled(
true);
4826 m_Camera->setVideoStreamEnabled(enabled);
4828 KSMessageBox::Instance()->questionYesNo(
i18n(
"Image transfer is disabled for this camera. Would you like to enable it?"));
4832 m_Camera->setVideoStreamEnabled(enabled);
4848 void Focus::setVideoStreamEnabled(
bool enabled)
4852 liveVideoB->setChecked(
true);
4857 liveVideoB->setChecked(
false);
4862 void Focus::processCaptureTimeout()
4864 captureTimeoutCounter++;
4866 if (captureTimeoutCounter >= 3)
4868 captureTimeoutCounter = 0;
4869 captureTimeout.stop();
4870 appendLogText(
i18n(
"Exposure timeout. Aborting..."));
4871 completeFocusProcedure(Ekos::FOCUS_ABORTED);
4875 appendLogText(
i18n(
"Exposure timeout. Restarting exposure..."));
4876 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
4877 targetChip->abortExposure();
4879 prepareCapture(targetChip);
4881 if (targetChip->capture(focusExposure->value()))
4885 captureTimeout.start(focusCaptureTimeout->value() * 1000);
4887 if (inFocusLoop ==
false)
4888 appendLogText(
i18n(
"Capturing image again..."));
4892 else if (inAutoFocus)
4894 completeFocusProcedure(Ekos::FOCUS_ABORTED);
4903 appendLogText(
i18n(
"Failed to save image. Aborting..."));
4904 completeFocusProcedure(Ekos::FOCUS_ABORTED);
4908 captureFailureCounter++;
4910 if (captureFailureCounter >= 3)
4912 captureFailureCounter = 0;
4913 appendLogText(
i18n(
"Exposure failure. Aborting..."));
4914 completeFocusProcedure(Ekos::FOCUS_ABORTED);
4918 appendLogText(
i18n(
"Exposure failure. Restarting exposure..."));
4919 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
4920 targetChip->abortExposure();
4921 targetChip->capture(focusExposure->value());
4924 void Focus::syncSettings()
4936 if ( (dsb = qobject_cast<QDoubleSpinBox*>(sender())))
4939 value = dsb->
value();
4942 else if ( (sb = qobject_cast<QSpinBox*>(sender())))
4945 value = sb->
value();
4947 else if ( (cb = qobject_cast<QCheckBox*>(sender())))
4952 else if ( (rb = qobject_cast<QRadioButton*>(sender())))
4957 else if ( (cbox = qobject_cast<QComboBox*>(sender())))
4962 else if ( (s = qobject_cast<QSplitter*>(sender())))
4970 Options::self()->setProperty(key.
toLatin1(), value);
4971 Options::self()->save();
4973 m_Settings[key] = value;
4974 m_GlobalSettings[key] = value;
4976 emit settingsUpdated(getAllSettings());
4979 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
4980 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::Focus, m_Settings);
4983 ImageRingMask *ringmask =
dynamic_cast<ImageRingMask *
>(m_FocusView->imageMask().get());
4984 ImageMosaicMask *mosaicmask =
dynamic_cast<ImageMosaicMask *
>(m_FocusView->imageMask().get());
4985 if (ringmask !=
nullptr)
4987 ringmask->setInnerRadius(focusFullFieldInnerRadius->value() / 100.0);
4988 ringmask->setOuterRadius(focusFullFieldOuterRadius->value() / 100.0);
4990 else if (mosaicmask !=
nullptr)
4992 mosaicmask->setTileWidth(focusMosaicTileWidth->value());
4993 mosaicmask->setSpace(focusMosaicSpace->value());
4997 void Focus::loadGlobalSettings()
5002 QVariantMap settings;
5004 for (
auto &oneWidget : findChildren<QComboBox*>())
5006 if (oneWidget->objectName() ==
"opticalTrainCombo")
5009 key = oneWidget->objectName();
5010 value = Options::self()->property(key.
toLatin1());
5013 oneWidget->setCurrentText(value.
toString());
5014 settings[key] = value;
5017 qCDebug(KSTARS_EKOS_FOCUS) <<
"Option" << key <<
"not found!";
5021 for (
auto &oneWidget : findChildren<QDoubleSpinBox*>())
5023 key = oneWidget->objectName();
5024 value = Options::self()->property(key.
toLatin1());
5028 settings[key] = value;
5031 qCDebug(KSTARS_EKOS_FOCUS) <<
"Option" << key <<
"not found!";
5035 for (
auto &oneWidget : findChildren<QSpinBox*>())
5037 key = oneWidget->objectName();
5038 value = Options::self()->property(key.
toLatin1());
5042 settings[key] = value;
5045 qCDebug(KSTARS_EKOS_FOCUS) <<
"Option" << key <<
"not found!";
5049 for (
auto &oneWidget : findChildren<QCheckBox*>())
5051 key = oneWidget->objectName();
5052 value = Options::self()->property(key.
toLatin1());
5055 oneWidget->setChecked(value.
toBool());
5056 settings[key] = value;
5059 qCDebug(KSTARS_EKOS_FOCUS) <<
"Option" << key <<
"not found!";
5063 for (
auto &oneWidget : findChildren<QSplitter*>())
5065 key = oneWidget->objectName();
5066 value = Options::self()->property(key.
toLatin1());
5071 oneWidget->restoreState(valueBA);
5072 settings[key] = valueBA;
5075 qCDebug(KSTARS_EKOS_FOCUS) <<
"Option" << key <<
"not found!";
5078 for (
auto &oneWidget : findChildren<QRadioButton*>())
5080 key = oneWidget->objectName();
5081 value = Options::self()->property(key.
toLatin1());
5084 oneWidget->setChecked(value.
toBool());
5085 settings[key] = value;
5089 ImageMaskType masktype =
static_cast<ImageMaskType
>(Options::focusMaskType());
5090 selectImageMask(masktype);
5091 if (masktype == FOCUS_MASK_NONE)
5092 focusNoMaskRB->setChecked(
true);
5093 else if (masktype == FOCUS_MASK_RING)
5094 focusRingMaskRB->setChecked(
true);
5096 focusMosaicMaskRB->setChecked(
true);
5098 m_GlobalSettings = m_Settings = settings;
5101 void Focus::checkMosaicMaskLimits()
5103 if (m_Camera ==
nullptr || m_Camera->isConnected() ==
false)
5105 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
5106 if (targetChip ==
nullptr || frameSettings.contains(targetChip) ==
false)
5108 QVariantMap settings = frameSettings[targetChip];
5110 int min = std::min(settings[
"w"].toInt(), settings[
"h"].toInt());
5112 focusMosaicTileWidth->setMaximum(100 * min / (3 * settings[
"w"].toInt()));
5115 void Focus::connectSettings()
5118 for (
auto &oneWidget : findChildren<QComboBox*>())
5119 connect(oneWidget, QOverload<int>::of(&
QComboBox::activated),
this, &Ekos::Focus::syncSettings);
5122 for (
auto &oneWidget : findChildren<QDoubleSpinBox*>())
5126 for (
auto &oneWidget : findChildren<QSpinBox*>())
5130 for (
auto &oneWidget : findChildren<QCheckBox*>())
5134 for (
auto &oneWidget : findChildren<QSplitter*>())
5142 disconnect(opticalTrainCombo, QOverload<int>::of(&
QComboBox::activated),
this, &Ekos::Focus::syncSettings);
5145 void Focus::disconnectSettings()
5148 for (
auto &oneWidget : findChildren<QComboBox*>())
5149 disconnect(oneWidget, QOverload<int>::of(&
QComboBox::activated),
this, &Ekos::Focus::syncSettings);
5152 for (
auto &oneWidget : findChildren<QDoubleSpinBox*>())
5156 for (
auto &oneWidget : findChildren<QSpinBox*>())
5160 for (
auto &oneWidget : findChildren<QCheckBox*>())
5164 for (
auto &oneWidget : findChildren<QSplitter*>())
5174 void Focus::initPlots()
5178 profileDialog =
new QDialog(
this);
5181 profileDialog->setWindowTitle(
i18nc(
"@title:window",
"Relative Profile"));
5182 profilePlot =
new FocusProfilePlot(profileDialog);
5185 profileDialog->setLayout(profileLayout);
5186 profileDialog->resize(400, 300);
5189 connect(
this, &Ekos::Focus::newHFR, [
this](
double currentHFR,
int pos)
5191 Q_UNUSED(pos) profilePlot->drawProfilePlot(currentHFR);
5195 void Focus::initConnections()
5198 waitStarSelectTimer.setInterval(AUTO_STAR_TIMEOUT);
5199 connect(&waitStarSelectTimer, &
QTimer::timeout,
this, &Ekos::Focus::checkAutoStarTimeout);
5211 connect(toggleFullScreenB, &
QPushButton::clicked,
this, &Ekos::Focus::toggleFocusingWidgetFullScreen);
5214 captureTimer.setSingleShot(
true);
5221 captureTimeout.setSingleShot(
true);
5222 connect(&captureTimeout, &
QTimer::timeout,
this, &Ekos::Focus::processCaptureTimeout);
5242 connect(focusBinning, QOverload<int>::of(&
QComboBox::activated),
this, &Ekos::Focus::checkMosaicMaskLimits);
5260 setFocusDetection(
static_cast<StarAlgorithm
>(index));
5266 setFocusAlgorithm(
static_cast<Algorithm
>(index));
5273 setCurveFit(
static_cast<CurveFitting::CurveFit
>(index));
5279 setStarMeasure(
static_cast<StarMeasure
>(index));
5285 setStarPSF(
static_cast<StarPSF
>(index));
5291 setStarUnits(
static_cast<StarUnits
>(index));
5297 setWalk(
static_cast<FocusWalk
>(index));
5303 Options::setFocusAdaptive(enabled);
5312 starSelected =
false;
5313 m_FocusView->setTrackingBox(
QRect());
5321 &Ekos::Focus::calcCFZ);
5324 &Ekos::Focus::calcCFZ);
5370 focusAdvSteps->setValue(m_cfzSteps);
5374 void Focus::setFocusDetection(StarAlgorithm starAlgorithm)
5376 static bool first =
true;
5377 if (!first && m_FocusDetection == starAlgorithm)
5382 m_FocusDetection = starAlgorithm;
5385 setFocusAlgorithm(m_FocusAlgorithm);
5387 if (m_FocusDetection == ALGORITHM_BAHTINOV)
5390 focusAutoStarEnabled->setChecked(
false);
5391 focusBoxSize->setMaximum(512);
5396 if (focusBoxSize->value() > 256)
5399 focusBoxSize->setValue(focusBoxSize->value());
5401 focusBoxSize->setMaximum(256);
5403 focusAutoStarEnabled->setEnabled(m_FocusDetection != ALGORITHM_BAHTINOV);
5406 void Focus::setFocusAlgorithm(Algorithm algorithm)
5408 m_FocusAlgorithm = algorithm;
5411 case FOCUS_ITERATIVE:
5413 gridLayoutProcess->removeWidget(focusMultiRowAverageLabel);
5414 focusMultiRowAverageLabel->hide();
5415 gridLayoutProcess->removeWidget(focusMultiRowAverage);
5416 focusMultiRowAverage->hide();
5418 gridLayoutProcess->removeWidget(focusGaussianSigmaLabel);
5419 focusGaussianSigmaLabel->hide();
5420 gridLayoutProcess->removeWidget(focusGaussianSigma);
5421 focusGaussianSigma->hide();
5423 gridLayoutProcess->removeWidget(focusGaussianKernelSizeLabel);
5424 focusGaussianKernelSizeLabel->hide();
5425 gridLayoutProcess->removeWidget(focusGaussianKernelSize);
5426 focusGaussianKernelSize->hide();
5428 gridLayoutProcess->removeWidget(focusStarMeasureLabel);
5429 focusStarMeasureLabel->hide();
5430 gridLayoutProcess->removeWidget(focusStarMeasure);
5431 focusStarMeasure->hide();
5433 gridLayoutProcess->removeWidget(focusStarPSFLabel);
5434 focusStarPSFLabel->hide();
5435 gridLayoutProcess->removeWidget(focusStarPSF);
5436 focusStarPSF->hide();
5438 gridLayoutProcess->removeWidget(focusUseWeights);
5439 focusUseWeights->hide();
5441 gridLayoutProcess->removeWidget(focusR2LimitLabel);
5442 focusR2LimitLabel->hide();
5443 gridLayoutProcess->removeWidget(focusR2Limit);
5444 focusR2Limit->hide();
5446 gridLayoutProcess->removeWidget(focusRefineCurveFit);
5447 focusRefineCurveFit->hide();
5448 focusRefineCurveFit->setChecked(
false);
5450 gridLayoutProcess->removeWidget(focusToleranceLabel);
5451 focusToleranceLabel->hide();
5452 gridLayoutProcess->removeWidget(focusTolerance);
5453 focusTolerance->hide();
5455 gridLayoutProcess->removeWidget(focusThresholdLabel);
5456 focusThresholdLabel->hide();
5457 gridLayoutProcess->removeWidget(focusThreshold);
5458 focusThreshold->hide();
5460 gridLayoutProcess->removeWidget(focusCurveFitLabel);
5461 focusCurveFitLabel->hide();
5462 gridLayoutProcess->removeWidget(focusCurveFit);
5463 focusCurveFit->hide();
5465 focusCurveFit->setCurrentIndex(CurveFitting::FOCUS_QUADRATIC);
5468 if (focusStarMeasure->count() != 1)
5470 focusStarMeasure->clear();
5471 focusStarMeasure->addItem(m_StarMeasureText.at(FOCUS_STAR_HFR));
5472 focusStarMeasure->setCurrentIndex(FOCUS_STAR_HFR);
5476 gridLayoutProcess->addWidget(focusToleranceLabel, 3, 0);
5477 focusToleranceLabel->show();
5478 gridLayoutProcess->addWidget(focusTolerance, 3, 1);
5479 focusTolerance->show();
5481 gridLayoutProcess->addWidget(focusFramesCountLabel, 3, 2);
5482 focusFramesCountLabel->show();
5483 gridLayoutProcess->addWidget(focusFramesCount, 3, 3);
5484 focusFramesCount->show();
5486 if (m_FocusDetection == ALGORITHM_THRESHOLD)
5488 gridLayoutProcess->addWidget(focusThresholdLabel, 4, 0);
5489 focusThresholdLabel->show();
5490 gridLayoutProcess->addWidget(focusThreshold, 4, 1);
5491 focusThreshold->show();
5493 else if (m_FocusDetection == ALGORITHM_BAHTINOV)
5495 gridLayoutProcess->addWidget(focusMultiRowAverageLabel, 4, 0);
5496 focusMultiRowAverageLabel->show();
5497 gridLayoutProcess->addWidget(focusMultiRowAverage, 4, 1);
5498 focusMultiRowAverage->show();
5500 gridLayoutProcess->addWidget(focusGaussianSigmaLabel, 4, 2);
5501 focusGaussianSigmaLabel->show();
5502 gridLayoutProcess->addWidget(focusGaussianSigma, 4, 3);
5503 focusGaussianSigma->show();
5505 gridLayoutProcess->addWidget(focusGaussianKernelSizeLabel, 5, 0);
5506 focusGaussianKernelSizeLabel->show();
5507 gridLayoutProcess->addWidget(focusGaussianKernelSize, 5, 1);
5508 focusGaussianKernelSize->show();
5513 focusAdaptive->setChecked(
false);
5514 focusAdaptStart->setChecked(
false);
5515 adaptiveFocusGroup->setEnabled(
false);
5518 focusMaxSingleStep->setEnabled(
true);
5519 focusOutSteps->setEnabled(
false);
5522 if (focusWalk->count() != 1)
5525 focusWalk->addItem(m_FocusWalkText.at(FOCUS_WALK_CLASSIC));
5526 focusWalk->setCurrentIndex(FOCUS_WALK_CLASSIC);
5530 case FOCUS_POLYNOMIAL:
5532 gridLayoutProcess->removeWidget(focusMultiRowAverageLabel);
5533 focusMultiRowAverageLabel->hide();
5534 gridLayoutProcess->removeWidget(focusMultiRowAverage);
5535 focusMultiRowAverage->hide();
5537 gridLayoutProcess->removeWidget(focusGaussianSigmaLabel);
5538 focusGaussianSigmaLabel->hide();
5539 gridLayoutProcess->removeWidget(focusGaussianSigma);
5540 focusGaussianSigma->hide();
5542 gridLayoutProcess->removeWidget(focusGaussianKernelSizeLabel);
5543 focusGaussianKernelSizeLabel->hide();
5544 gridLayoutProcess->removeWidget(focusGaussianKernelSize);
5545 focusGaussianKernelSize->hide();
5547 gridLayoutProcess->removeWidget(focusStarPSFLabel);
5548 focusStarPSFLabel->hide();
5549 gridLayoutProcess->removeWidget(focusStarPSF);
5550 focusStarPSF->hide();
5552 gridLayoutProcess->removeWidget(focusUseWeights);
5553 focusUseWeights->hide();
5555 gridLayoutProcess->removeWidget(focusR2LimitLabel);
5556 focusR2LimitLabel->hide();
5557 gridLayoutProcess->removeWidget(focusR2Limit);
5558 focusR2Limit->hide();
5560 gridLayoutProcess->removeWidget(focusRefineCurveFit);
5561 focusRefineCurveFit->hide();
5562 focusRefineCurveFit->setChecked(
false);
5564 gridLayoutProcess->removeWidget(focusToleranceLabel);
5565 focusToleranceLabel->hide();
5566 gridLayoutProcess->removeWidget(focusTolerance);
5567 focusTolerance->hide();
5569 gridLayoutProcess->removeWidget(focusThresholdLabel);
5570 focusThresholdLabel->hide();
5571 gridLayoutProcess->removeWidget(focusThreshold);
5572 focusThreshold->hide();
5575 if (focusStarMeasure->count() != 1)
5577 focusStarMeasure->clear();
5578 focusStarMeasure->addItem(m_StarMeasureText.at(FOCUS_STAR_HFR));
5579 focusStarMeasure->setCurrentIndex(FOCUS_STAR_HFR);
5584 gridLayoutProcess->addWidget(focusCurveFitLabel, 1, 2);
5585 focusCurveFitLabel->show();
5586 gridLayoutProcess->addWidget(focusCurveFit, 1, 3);
5587 focusCurveFit->show();
5588 if (focusCurveFit->count() != 1)
5590 focusCurveFit->clear();
5591 focusCurveFit->addItem(m_CurveFitText.at(CurveFitting::FOCUS_QUADRATIC));
5592 focusCurveFit->setCurrentIndex(CurveFitting::FOCUS_QUADRATIC);
5595 gridLayoutProcess->addWidget(focusToleranceLabel, 3, 0);
5596 focusToleranceLabel->show();
5597 gridLayoutProcess->addWidget(focusTolerance, 3, 1);
5598 focusTolerance->show();
5600 gridLayoutProcess->addWidget(focusFramesCountLabel, 3, 2);
5601 focusFramesCountLabel->show();
5602 gridLayoutProcess->addWidget(focusFramesCount, 3, 3);
5603 focusFramesCount->show();
5605 if (m_FocusDetection == ALGORITHM_THRESHOLD)
5607 gridLayoutProcess->addWidget(focusThresholdLabel, 4, 0);
5608 focusThresholdLabel->show();
5609 gridLayoutProcess->addWidget(focusThreshold, 4, 1);
5610 focusThreshold->show();
5612 else if (m_FocusDetection == ALGORITHM_BAHTINOV)
5614 gridLayoutProcess->addWidget(focusMultiRowAverageLabel, 4, 0);
5615 focusMultiRowAverageLabel->show();
5616 gridLayoutProcess->addWidget(focusMultiRowAverage, 4, 1);
5617 focusMultiRowAverage->show();
5619 gridLayoutProcess->addWidget(focusGaussianSigmaLabel, 4, 2);
5620 focusGaussianSigmaLabel->show();
5621 gridLayoutProcess->addWidget(focusGaussianSigma, 4, 3);
5622 focusGaussianSigma->show();
5624 gridLayoutProcess->addWidget(focusGaussianKernelSizeLabel, 5, 0);
5625 focusGaussianKernelSizeLabel->show();
5626 gridLayoutProcess->addWidget(focusGaussianKernelSize, 5, 1);
5627 focusGaussianKernelSize->show();
5632 focusAdaptive->setChecked(
false);
5633 focusAdaptStart->setChecked(
false);
5634 adaptiveFocusGroup->setEnabled(
false);
5637 focusMaxSingleStep->setEnabled(
true);
5638 focusOutSteps->setEnabled(
false);
5641 if (focusWalk->count() != 1)
5644 focusWalk->addItem(m_FocusWalkText.at(FOCUS_WALK_CLASSIC));
5645 focusWalk->setCurrentIndex(FOCUS_WALK_CLASSIC);
5651 gridLayoutProcess->removeWidget(focusMultiRowAverageLabel);
5652 focusMultiRowAverageLabel->hide();
5653 gridLayoutProcess->removeWidget(focusMultiRowAverage);
5654 focusMultiRowAverage->hide();
5656 gridLayoutProcess->removeWidget(focusGaussianSigmaLabel);
5657 focusGaussianSigmaLabel->hide();
5658 gridLayoutProcess->removeWidget(focusGaussianSigma);
5659 focusGaussianSigma->hide();
5661 gridLayoutProcess->removeWidget(focusGaussianKernelSizeLabel);
5662 focusGaussianKernelSizeLabel->hide();
5663 gridLayoutProcess->removeWidget(focusGaussianKernelSize);
5664 focusGaussianKernelSize->hide();
5666 gridLayoutProcess->removeWidget(focusThresholdLabel);
5667 focusThresholdLabel->hide();
5668 gridLayoutProcess->removeWidget(focusThreshold);
5669 focusThreshold->hide();
5671 gridLayoutProcess->removeWidget(focusStarPSFLabel);
5672 focusStarPSFLabel->hide();
5673 gridLayoutProcess->removeWidget(focusStarPSF);
5674 focusStarPSF->hide();
5676 gridLayoutProcess->removeWidget(focusUseWeights);
5677 focusUseWeights->hide();
5679 gridLayoutProcess->removeWidget(focusR2LimitLabel);
5680 focusR2LimitLabel->hide();
5681 gridLayoutProcess->removeWidget(focusR2Limit);
5682 focusR2Limit->hide();
5684 gridLayoutProcess->removeWidget(focusRefineCurveFit);
5685 focusRefineCurveFit->hide();
5686 focusRefineCurveFit->setChecked(
false);
5689 if (focusStarMeasure->count() != 1)
5691 focusStarMeasure->clear();
5692 focusStarMeasure->addItem(m_StarMeasureText.at(FOCUS_STAR_HFR));
5693 focusStarMeasure->setCurrentIndex(FOCUS_STAR_HFR);
5698 gridLayoutProcess->addWidget(focusCurveFitLabel, 1, 2);
5699 focusCurveFitLabel->show();
5700 gridLayoutProcess->addWidget(focusCurveFit, 1, 3);
5701 focusCurveFit->show();
5702 if (focusCurveFit->count() != 1)
5704 focusCurveFit->clear();
5705 focusCurveFit->addItem(m_CurveFitText.at(CurveFitting::FOCUS_QUADRATIC));
5706 focusCurveFit->setCurrentIndex(CurveFitting::FOCUS_QUADRATIC);
5709 gridLayoutProcess->addWidget(focusToleranceLabel, 3, 0);
5710 focusToleranceLabel->show();
5711 gridLayoutProcess->addWidget(focusTolerance, 3, 1);
5712 focusTolerance->show();
5714 gridLayoutProcess->addWidget(focusFramesCountLabel, 3, 2);
5715 focusFramesCountLabel->show();
5716 gridLayoutProcess->addWidget(focusFramesCount, 3, 3);
5717 focusFramesCount->show();
5719 if (m_FocusDetection == ALGORITHM_THRESHOLD)
5721 gridLayoutProcess->addWidget(focusThresholdLabel, 4, 0);
5722 focusThresholdLabel->show();
5723 gridLayoutProcess->addWidget(focusThreshold, 4, 1);
5724 focusThreshold->show();
5726 else if (m_FocusDetection == ALGORITHM_BAHTINOV)
5728 gridLayoutProcess->addWidget(focusMultiRowAverageLabel, 4, 0);
5729 focusMultiRowAverageLabel->show();
5730 gridLayoutProcess->addWidget(focusMultiRowAverage, 4, 1);
5731 focusMultiRowAverage->show();
5733 gridLayoutProcess->addWidget(focusGaussianSigmaLabel, 4, 2);
5734 focusGaussianSigmaLabel->show();
5735 gridLayoutProcess->addWidget(focusGaussianSigma, 4, 3);
5736 focusGaussianSigma->show();
5738 gridLayoutProcess->addWidget(focusGaussianKernelSizeLabel, 5, 0);
5739 focusGaussianKernelSizeLabel->show();
5740 gridLayoutProcess->addWidget(focusGaussianKernelSize, 5, 1);
5741 focusGaussianKernelSize->show();
5746 focusAdaptive->setChecked(
false);
5747 focusAdaptStart->setChecked(
false);
5748 adaptiveFocusGroup->setEnabled(
false);
5751 focusMaxSingleStep->setEnabled(
false);
5752 focusOutSteps->setEnabled(
true);
5755 if (focusWalk->count() != 1)
5758 focusWalk->addItem(m_FocusWalkText.at(FOCUS_WALK_CLASSIC));
5759 focusWalk->setCurrentIndex(FOCUS_WALK_CLASSIC);
5763 case FOCUS_LINEAR1PASS:
5765 gridLayoutProcess->removeWidget(focusMultiRowAverageLabel);
5766 focusMultiRowAverageLabel->hide();
5767 gridLayoutProcess->removeWidget(focusMultiRowAverage);
5768 focusMultiRowAverage->hide();
5770 gridLayoutProcess->removeWidget(focusGaussianSigmaLabel);
5771 focusGaussianSigmaLabel->hide();
5772 gridLayoutProcess->removeWidget(focusGaussianSigma);
5773 focusGaussianSigma->hide();
5775 gridLayoutProcess->removeWidget(focusGaussianKernelSizeLabel);
5776 focusGaussianKernelSizeLabel->hide();
5777 gridLayoutProcess->removeWidget(focusGaussianKernelSize);
5778 focusGaussianKernelSize->hide();
5780 gridLayoutProcess->removeWidget(focusThresholdLabel);
5781 focusThresholdLabel->hide();
5782 gridLayoutProcess->removeWidget(focusThreshold);
5783 focusThreshold->hide();
5785 gridLayoutProcess->removeWidget(focusToleranceLabel);
5786 focusToleranceLabel->hide();
5787 gridLayoutProcess->removeWidget(focusTolerance);
5788 focusTolerance->hide();
5792 if (m_FocusDetection == ALGORITHM_SEP && m_CurveFit != CurveFitting::FOCUS_QUADRATIC)
5794 if (focusStarMeasure->count() != m_StarMeasureText.count())
5796 focusStarMeasure->clear();
5797 focusStarMeasure->addItems(m_StarMeasureText);
5798 focusStarMeasure->setCurrentIndex(FOCUS_STAR_HFR);
5801 else if (m_FocusDetection != ALGORITHM_SEP || m_CurveFit == CurveFitting::FOCUS_QUADRATIC)
5803 if (focusStarMeasure->count() != 1)
5805 focusStarMeasure->clear();
5806 focusStarMeasure->addItem(m_StarMeasureText.at(FOCUS_STAR_HFR));
5807 focusStarMeasure->setCurrentIndex(FOCUS_STAR_HFR);
5813 gridLayoutProcess->addWidget(focusCurveFitLabel, 1, 2);
5814 focusCurveFitLabel->show();
5815 gridLayoutProcess->addWidget(focusCurveFit, 1, 3);
5816 focusCurveFit->show();
5817 if (focusCurveFit->count() != m_CurveFitText.count())
5819 focusCurveFit->clear();
5820 focusCurveFit->addItems(m_CurveFitText);
5821 focusCurveFit->setCurrentIndex(CurveFitting::FOCUS_HYPERBOLA);
5824 gridLayoutProcess->addWidget(focusUseWeights, 3, 0, 1, 2);
5825 focusUseWeights->show();
5827 gridLayoutProcess->addWidget(focusR2LimitLabel, 3, 2);
5828 focusR2LimitLabel->show();
5829 gridLayoutProcess->addWidget(focusR2Limit, 3, 3);
5830 focusR2Limit->show();
5832 gridLayoutProcess->addWidget(focusRefineCurveFit, 4, 0, 1, 2);
5833 focusRefineCurveFit->show();
5835 gridLayoutProcess->addWidget(focusFramesCountLabel, 4, 2);
5836 focusFramesCountLabel->show();
5837 gridLayoutProcess->addWidget(focusFramesCount, 4, 3);
5838 focusFramesCount->show();
5840 if (m_FocusDetection == ALGORITHM_THRESHOLD)
5842 gridLayoutProcess->addWidget(focusThresholdLabel, 5, 0);
5843 focusThresholdLabel->show();
5844 gridLayoutProcess->addWidget(focusThreshold, 5, 1);
5845 focusThreshold->show();
5847 else if (m_FocusDetection == ALGORITHM_BAHTINOV)
5849 gridLayoutProcess->addWidget(focusMultiRowAverageLabel, 5, 0);
5850 focusMultiRowAverageLabel->show();
5851 gridLayoutProcess->addWidget(focusMultiRowAverage, 5, 1);
5852 focusMultiRowAverage->show();
5854 gridLayoutProcess->addWidget(focusGaussianSigmaLabel, 5, 2);
5855 focusGaussianSigmaLabel->show();
5856 gridLayoutProcess->addWidget(focusGaussianSigma, 5, 3);
5857 focusGaussianSigma->show();
5859 gridLayoutProcess->addWidget(focusGaussianKernelSizeLabel, 6, 0);
5860 focusGaussianKernelSizeLabel->show();
5861 gridLayoutProcess->addWidget(focusGaussianKernelSize, 6, 1);
5862 focusGaussianKernelSize->show();
5867 adaptiveFocusGroup->setEnabled(
true);
5871 focusMaxSingleStep->setEnabled(
false);
5872 focusOutSteps->setEnabled(
true);
5875 if (m_CurveFit == CurveFitting::FOCUS_QUADRATIC)
5877 if (focusWalk->count() != 1)
5880 focusWalk->addItem(m_FocusWalkText.at(FOCUS_WALK_CLASSIC));
5881 focusWalk->setCurrentIndex(FOCUS_WALK_CLASSIC);
5886 if (focusWalk->count() != m_FocusWalkText.count())
5889 focusWalk->addItems(m_FocusWalkText);
5890 focusWalk->setCurrentIndex(FOCUS_WALK_CLASSIC);
5897 void Focus::setCurveFit(CurveFitting::CurveFit curve)
5899 if (focusCurveFit->currentIndex() == -1)
5902 static bool first =
true;
5903 if (!first && m_CurveFit == curve)
5909 setFocusAlgorithm(
static_cast<Algorithm
> (focusAlgorithm->currentIndex()));
5914 case CurveFitting::FOCUS_QUADRATIC:
5915 focusR2Limit->setEnabled(
false);
5916 focusRefineCurveFit->setChecked(
false);
5917 focusRefineCurveFit->setEnabled(
false);
5920 case CurveFitting::FOCUS_HYPERBOLA:
5921 focusR2Limit->setEnabled(
true);
5922 focusRefineCurveFit->setEnabled(
true);
5925 case CurveFitting::FOCUS_PARABOLA:
5926 focusR2Limit->setEnabled(
true);
5927 focusRefineCurveFit->setEnabled(
true);
5935 void Focus::setStarMeasure(StarMeasure starMeasure)
5937 if (focusStarMeasure->currentIndex() == -1)
5940 static bool first =
true;
5941 if (!first && m_StarMeasure == starMeasure)
5946 m_StarMeasure = starMeasure;
5947 setFocusAlgorithm(
static_cast<Algorithm
> (focusAlgorithm->currentIndex()));
5954 switch(m_StarMeasure)
5956 case FOCUS_STAR_HFR:
5957 m_OptDir = CurveFitting::OPTIMISATION_MINIMISE;
5958 m_ScaleCalc = Mathematics::RobustStatistics::ScaleCalculation::SCALE_SESTIMATOR;
5959 m_FocusView->setStarsHFREnabled(
true);
5962 gridLayoutProcess->removeWidget(focusStarPSFLabel);
5963 focusStarPSFLabel->hide();
5964 gridLayoutProcess->removeWidget(focusStarPSF);
5965 focusStarPSF->hide();
5968 case FOCUS_STAR_HFR_ADJ:
5969 m_OptDir = CurveFitting::OPTIMISATION_MINIMISE;
5970 m_ScaleCalc = Mathematics::RobustStatistics::ScaleCalculation::SCALE_SESTIMATOR;
5971 m_FocusView->setStarsHFREnabled(
false);
5974 gridLayoutProcess->removeWidget(focusStarPSFLabel);
5975 focusStarPSFLabel->hide();
5976 gridLayoutProcess->removeWidget(focusStarPSF);
5977 focusStarPSF->hide();
5980 case FOCUS_STAR_FWHM:
5981 m_OptDir = CurveFitting::OPTIMISATION_MINIMISE;
5982 m_ScaleCalc = Mathematics::RobustStatistics::ScaleCalculation::SCALE_SESTIMATOR;
5984 m_FocusView->setStarsHFREnabled(
false);
5987 gridLayoutProcess->addWidget(focusStarPSFLabel, 2, 2);
5988 focusStarPSFLabel->show();
5989 gridLayoutProcess->addWidget(focusStarPSF, 2, 3);
5990 focusStarPSF->show();
5993 case FOCUS_STAR_NUM_STARS:
5994 m_OptDir = CurveFitting::OPTIMISATION_MAXIMISE;
5995 m_ScaleCalc = Mathematics::RobustStatistics::ScaleCalculation::SCALE_SESTIMATOR;
5996 m_FocusView->setStarsHFREnabled(
true);
5999 gridLayoutProcess->removeWidget(focusStarPSFLabel);
6000 focusStarPSFLabel->hide();
6001 gridLayoutProcess->removeWidget(focusStarPSF);
6002 focusStarPSF->hide();
6005 case FOCUS_STAR_FOURIER_POWER:
6006 m_OptDir = CurveFitting::OPTIMISATION_MAXIMISE;
6007 m_ScaleCalc = Mathematics::RobustStatistics::ScaleCalculation::SCALE_SESTIMATOR;
6008 m_FocusView->setStarsHFREnabled(
true);
6011 gridLayoutProcess->removeWidget(focusStarPSFLabel);
6012 focusStarPSFLabel->hide();
6013 gridLayoutProcess->removeWidget(focusStarPSF);
6014 focusStarPSF->hide();
6022 void Focus::setStarPSF(StarPSF starPSF)
6024 m_StarPSF = starPSF;
6027 void Focus::setStarUnits(StarUnits starUnits)
6029 m_StarUnits = starUnits;
6032 void Focus::setWalk(FocusWalk walk)
6034 if (focusWalk->currentIndex() == -1)
6037 static bool first =
true;
6038 if (!first && m_FocusWalk == walk)
6047 case FOCUS_WALK_CLASSIC:
6048 gridLayoutMechanics->replaceWidget(focusNumStepsLabel, focusOutStepsLabel);
6049 focusNumStepsLabel->hide();
6050 focusOutStepsLabel->show();
6051 gridLayoutMechanics->replaceWidget(focusNumSteps, focusOutSteps);
6052 focusNumSteps->hide();
6053 focusOutSteps->show();
6056 case FOCUS_WALK_FIXED_STEPS:
6057 case FOCUS_WALK_CFZ_SHUFFLE:
6058 gridLayoutMechanics->replaceWidget(focusOutStepsLabel, focusNumStepsLabel);
6059 focusOutStepsLabel->hide();
6060 focusNumStepsLabel->show();
6061 gridLayoutMechanics->replaceWidget(focusOutSteps, focusNumSteps);
6062 focusOutSteps->hide();
6063 focusNumSteps->show();
6071 double Focus::getStarUnits(
const StarMeasure starMeasure,
const StarUnits starUnits)
6073 if (starUnits == FOCUS_UNITS_PIXEL || starMeasure == FOCUS_STAR_NUM_STARS || starMeasure == FOCUS_STAR_FOURIER_POWER)
6075 if (m_CcdPixelSizeX <= 0.0 || m_FocalLength <= 0.0)
6079 return m_CcdPixelSizeX / m_FocalLength * 206.265;
6082 void Focus::calcCFZ()
6084 double cfzMicrons, cfzSteps;
6085 double cfzCameraSteps = calcCameraCFZ() / focusCFZStepSize->value();
6087 switch(
static_cast<Focus::CFZAlgorithm
> (focusCFZAlgorithm->currentIndex()))
6089 case Focus::FOCUS_CFZ_CLASSIC:
6091 cfzMicrons = 4.88f * focusCFZTolerance->value() * focusCFZWavelength->value() / 1000.0f *
6092 pow(focusCFZFNumber->value(), 2.0f);
6093 cfzSteps = cfzMicrons / focusCFZStepSize->value();
6094 m_cfzSteps = std::round(std::max(cfzSteps, cfzCameraSteps));
6095 focusCFZFormula->setText(
"CFZ = 4.88 t λ f²");
6096 focusCFZ->setText(
QString(
"%1 μm").arg(cfzMicrons, 0,
'f', 0));
6097 focusCFZSteps->setText(
QString(
"%1 steps").arg(cfzSteps, 0,
'f', 0));
6098 FocusCFZCameraSteps->setText(
QString(
"%1 steps").arg(cfzCameraSteps, 0,
'f', 0));
6099 FocusCFZFinal->setText(
QString(
"%1 steps").arg(m_cfzSteps, 0,
'f', 0));
6102 gridLayoutCFZ->removeWidget(focusCFZTauLabel);
6103 focusCFZTauLabel->hide();
6104 gridLayoutCFZ->removeWidget(focusCFZTau);
6105 focusCFZTau->hide();
6106 gridLayoutCFZ->removeWidget(focusCFZSeeingLabel);
6107 focusCFZSeeingLabel->hide();
6108 gridLayoutCFZ->removeWidget(focusCFZSeeing);
6109 focusCFZSeeing->hide();
6112 gridLayoutCFZ->addWidget(focusCFZToleranceLabel, 1, 0);
6113 focusCFZToleranceLabel->show();
6114 gridLayoutCFZ->addWidget(focusCFZTolerance, 1, 1);
6115 focusCFZTolerance->show();
6116 gridLayoutCFZ->addWidget(focusCFZWavelengthLabel, 2, 0);
6117 focusCFZWavelengthLabel->show();
6118 gridLayoutCFZ->addWidget(focusCFZWavelength, 2, 1);
6119 focusCFZWavelength->show();
6122 case Focus::FOCUS_CFZ_WAVEFRONT:
6124 cfzMicrons = 4.0f * focusCFZTolerance->value() * focusCFZWavelength->value() / 1000.0f * pow(focusCFZFNumber->value(),
6126 cfzSteps = cfzMicrons / focusCFZStepSize->value();
6127 m_cfzSteps = std::round(std::max(cfzSteps, cfzCameraSteps));
6128 focusCFZFormula->setText(
"CFZ = 4 t λ f²");
6129 focusCFZ->setText(
QString(
"%1 μm").arg(cfzMicrons, 0,
'f', 0));
6130 focusCFZSteps->setText(
QString(
"%1 steps").arg(cfzSteps, 0,
'f', 0));
6131 FocusCFZCameraSteps->setText(
QString(
"%1 steps").arg(cfzCameraSteps, 0,
'f', 0));
6132 FocusCFZFinal->setText(
QString(
"%1 steps").arg(m_cfzSteps, 0,
'f', 0));
6135 gridLayoutCFZ->removeWidget(focusCFZTauLabel);
6136 focusCFZTauLabel->hide();
6137 gridLayoutCFZ->removeWidget(focusCFZTau);
6138 focusCFZTau->hide();
6139 gridLayoutCFZ->removeWidget(focusCFZSeeingLabel);
6140 focusCFZSeeingLabel->hide();
6141 gridLayoutCFZ->removeWidget(focusCFZSeeing);
6142 focusCFZSeeing->hide();
6145 gridLayoutCFZ->addWidget(focusCFZToleranceLabel, 1, 0);
6146 focusCFZToleranceLabel->show();
6147 gridLayoutCFZ->addWidget(focusCFZTolerance, 1, 1);
6148 focusCFZTolerance->show();
6149 gridLayoutCFZ->addWidget(focusCFZWavelengthLabel, 2, 0);
6150 focusCFZWavelengthLabel->show();
6151 gridLayoutCFZ->addWidget(focusCFZWavelength, 2, 1);
6152 focusCFZWavelength->show();
6155 case Focus::FOCUS_CFZ_GOLD:
6157 cfzMicrons = 0.00225f * pow(focusCFZTau->value(), 0.5f) * focusCFZSeeing->value()
6158 * pow(focusCFZFNumber->value(), 2.0f) * focusCFZAperture->value();
6159 cfzSteps = cfzMicrons / focusCFZStepSize->value();
6160 m_cfzSteps = std::round(std::max(cfzSteps, cfzCameraSteps));
6161 focusCFZFormula->setText(
"CFZ = 0.00225 √τ θ f² A");
6162 focusCFZ->setText(
QString(
"%1 μm").arg(cfzMicrons, 0,
'f', 0));
6163 focusCFZSteps->setText(
QString(
"%1 steps").arg(cfzSteps, 0,
'f', 0));
6164 FocusCFZCameraSteps->setText(
QString(
"%1 steps").arg(cfzCameraSteps, 0,
'f', 0));
6165 FocusCFZFinal->setText(
QString(
"%1 steps").arg(m_cfzSteps, 0,
'f', 0));
6168 gridLayoutCFZ->removeWidget(focusCFZToleranceLabel);
6169 focusCFZToleranceLabel->hide();
6170 gridLayoutCFZ->removeWidget(focusCFZTolerance);
6171 focusCFZTolerance->hide();
6172 gridLayoutCFZ->removeWidget(focusCFZWavelengthLabel);
6173 focusCFZWavelengthLabel->hide();
6174 gridLayoutCFZ->removeWidget(focusCFZWavelength);
6175 focusCFZWavelength->hide();
6178 gridLayoutCFZ->addWidget(focusCFZTauLabel, 1, 0);
6179 focusCFZTauLabel->show();
6180 gridLayoutCFZ->addWidget(focusCFZTau, 1, 1);
6181 focusCFZTau->show();
6182 gridLayoutCFZ->addWidget(focusCFZSeeingLabel, 2, 0);
6183 focusCFZSeeingLabel->show();
6184 gridLayoutCFZ->addWidget(focusCFZSeeing, 2, 1);
6185 focusCFZSeeing->show();
6188 if (linearFocuser !=
nullptr && linearFocuser->isDone())
6189 emit drawCFZ(linearFocuser->solution(), linearFocuser->solutionValue(), m_cfzSteps, focusCFZDisplayVCurve->isChecked());
6195 double Focus::calcCameraCFZ()
6197 return m_CcdPixelSizeX * pow(focusCFZFNumber->value(), 2.0) * focusCFZAperture->value() / 1000.0;
6200 void Focus::wavelengthChanged()
6203 if (m_FilterManager)
6205 focusCFZWavelength->setValue(m_FilterManager->getFilterWavelength(
filter()));
6210 void Focus::resetCFZToOT()
6213 focusCFZFNumber->setValue(m_FocalRatio);
6214 focusCFZAperture->setValue(m_Aperture);
6217 if (m_FilterManager)
6218 focusCFZWavelength->setValue(m_FilterManager->getFilterWavelength(
filter()));
6223 void Focus::focusAdvisorSetup()
6225 bool longFL = m_FocalLength > 1500;
6226 double imageScale = getStarUnits(FOCUS_STAR_HFR, FOCUS_UNITS_ARCSEC);
6228 bool centralObstruction = scopeHasObstruction(m_ScopeType);
6231 focusAdvLabel->setText(
QString(
"Recommendations: %1 FL=%2 ImageScale=%3")
6232 .arg(m_ScopeType).arg(m_FocalLength).arg(imageScale, 0,
'f', 2));
6235 focusAdvSteps->setValue(m_cfzSteps);
6238 focusAdvOutStepMult->setValue(5);
6239 if (centralObstruction)
6240 str =
"A good figure to start with is 5. You have a scope with a central obstruction that turns stars to donuts when\n"
6241 "they are out of focus. When this happens the system will struggle to identify stars correctly. To avoid this reduce\n"
6242 "either the step size or the number of steps.\n\n"
6243 "To check this situation, start at focus and move away by 'step size' * 'number of steps' steps. Take a focus frame\n"
6244 "and zoom in on the fitsviewer to see whether stars appear as stars or donuts.";
6246 str =
"A good figure to start with is 5.";
6247 focusAdvOutStepMult->setToolTip(str);
6248 focusAdvOutStepMultLabel->setToolTip(str);
6251 str =
"Camera & Filter Wheel Parameters:\n";
6264 if (focusBinning->isEnabled())
6267 QString binTarget = (imageScale < 1.0) ?
"2x2" :
"1x1";
6269 for (
int i = 0; i < focusBinning->count(); i++)
6271 if (focusBinning->itemText(i) == binTarget)
6273 FABinning = binTarget;
6280 str.
append(
"Gain ***Set Manually to Unity Gain***\n");
6281 str.
append(
"Filter ***Set Manually***");
6282 focusAdvCameraLabel->setToolTip(str);
6285 str =
"Settings Tab Parameters:\n";
6286 FAAutoSelectStar =
true;
6287 str.
append(
"Auto Select Star=on\n");
6289 FADarkFrame =
false;
6290 str.
append(
"Dark Frame=off\n");
6292 FAFullFieldInnerRadius = 0.0;
6293 FAFullFieldOuterRadius = 80.0;
6294 str.
append(
"Ring Mask 0%-80%\n");
6298 FAAdaptiveFocus =
false;
6299 str.
append(
"Adaptive Focus=off\n");
6301 FAAdaptStartPos =
false;
6302 str.
append(
"Adapt Start Pos=off");
6304 focusAdvSettingsLabel->setToolTip(str);
6307 str =
"Process Tab Parameters:\n";
6308 FAFocusDetection = ALGORITHM_SEP;
6309 str.
append(
"Detection=SEP\n");
6311 FAFocusSEPProfile =
"";
6312 for (
int i = 0; i < focusSEPProfile->count(); i++)
6314 if (focusSEPProfile->itemText(i) ==
"1-Focus-Default")
6316 FAFocusSEPProfile =
"1-Focus-Default";
6322 FAFocusAlgorithm = FOCUS_LINEAR1PASS;
6323 str.
append(
"Algorithm=Linear 1 Pass\n");
6325 FACurveFit = CurveFitting::FOCUS_HYPERBOLA;
6326 str.
append(
"Curve Fit=Hyperbola\n");
6328 FAStarMeasure = FOCUS_STAR_HFR;
6329 str.
append(
"Measure=HFR\n");
6331 FAUseWeights =
true;
6332 str.
append(
"Use Weights=on\n");
6334 FAFocusR2Limit = 0.8;
6335 str.
append(
"R² Limit=0.8\n");
6337 FAFocusRefineCurveFit =
false;
6338 str.
append(
"Refine Curve Fit=off\n");
6340 FAFocusFramesCount = 1;
6341 str.
append(
"Average Over=1");
6343 focusAdvProcessLabel->setToolTip(str);
6346 str =
"Mechanics Tab Parameters:\n";
6347 FAFocusWalk = FOCUS_WALK_CLASSIC;
6348 str.
append(
"Walk=Classic\n");
6350 FAFocusSettleTime = 1.0;
6351 str.
append(
"Focuser Settle=1\n");
6354 FAFocusMaxTravel = focusMaxTravel->maximum();
6358 str.
append(
"Backlash ***Set Manually***\n");
6359 str.
append(
"AF Overscan ***Set Manually***\n");
6361 FAFocusCaptureTimeout = 30;
6364 FAFocusMotionTimeout = 30;
6367 focusAdvMechanicsLabel->setToolTip(str);
6371 void Focus::focusAdvisorHelp()
6373 QString str =
i18n(
"Focus Advisor (FA) is designed to help you with focus parameters.\n"
6374 "It will not necessarily give you the perfect combination of parameters, you will "
6375 "need to experiment yourself, but it will give you a basic set of parameters to "
6376 "achieve focus.\n\n"
6377 "FA will recommend values for the majority of parameters. A few, however, will need "
6378 "extra work from you to setup. These are identified below along with a basic explanation "
6379 "of how to set them.\n\n"
6380 "The first step is to set backlash. Your focuser manual will likely explain how to do "
6381 "this. Once you have a value for backlash for your system, set either the Backlash field "
6382 "to have the driver perform backlash compensation or the AF Overscan field to have Autofocus "
6383 "perform backlash compensation. Set only one field and set the other to 0.\n\n"
6384 "The second step is to set Step Size. This can be defaulted from the Critical Focus Zone (CFZ) "
6385 "for your equipment - so configure this now in the CFZ tab.\n\n"
6386 "The third step is to set the Out Step Multiple. Start with the suggested default.");
6388 if (scopeHasObstruction(m_ScopeType))
6389 str.
append(
i18n(
" You have a scope with a central obstruction so be careful not to move too far away from "
6390 "focus as stars will appear as donuts and will not be detected properly. Experiment by "
6391 "finding focus and moving Step Size * Out Step Multiple ticks away from focus and take a "
6392 "focus frame. Zoom in to observe star detection. If it is poor then move the focuser back "
6393 "towards focus until star detection is acceptable. Adjust Out Step Multiple to correspond to "
6394 "this range of focuser motion."));
6396 str.
append(
i18n(
"\n\nThe fourth step is to set the remaining focus parameters to sensible values. Focus Advisor "
6397 "will suggest values for 4 categories of parameters. Check the associated Update box to "
6398 "accept these recommendations and press Update Params.\n"
6399 "1. Camera Properties - Note you need to ensure Gain is set appropriately, e.g. unity gain.\n"
6400 "2. Settings Tab: These all have recommendations.\n"
6401 "3. Process Tab: These all have recommendations.\n"
6402 "4. Mechanics Tab: Note Step Size and Out Step Multiple are dealt with above.\n\n"
6403 "Now move the focuser to approximate focus and select a broadband filter, e.g. Luminance\n"
6404 "You are now ready to start an Autofocus run."));
6410 void Focus::focusAdvisorAction()
6412 if (focusAdvStepSize->isChecked())
6413 focusTicks->setValue(focusAdvSteps->value());
6415 if (focusAdvOutStepMultiple->isChecked())
6416 focusOutSteps->setValue(focusAdvOutStepMult->value());