7#include "adaptivefocus.h"
8#include "focusadvisor.h"
9#include "focusadaptor.h"
10#include "focusalgorithms.h"
13#include "kstarsdata.h"
15#include "stellarsolver.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/darkprocessor.h"
28#include "ekos/auxiliary/profilesettings.h"
29#include "ekos/auxiliary/opticaltrainmanager.h"
30#include "ekos/auxiliary/opticaltrainsettings.h"
31#include "ekos/auxiliary/filtermanager.h"
32#include "ekos/auxiliary/stellarsolverprofileeditor.h"
35#include "fitsviewer/fitsdata.h"
36#include "fitsviewer/fitsview.h"
37#include "fitsviewer/fitsviewer.h"
40#include "indi/indifilterwheel.h"
41#include "ksnotification.h"
42#include "kconfigdialog.h"
44#include <basedevice.h>
45#include <gsl/gsl_fit.h>
46#include <gsl/gsl_vector.h>
47#include <gsl/gsl_min.h>
49#include <ekos_focus_debug.h>
50#include <config-kstars.h>
54#ifdef HAVE_DATAVISUALIZATION
55#include "aberrationinspector.h"
56#include "aberrationinspectorutils.h"
59#define MAXIMUM_ABS_ITERATIONS 51
60#define MAXIMUM_RESET_ITERATIONS 3
61#define MAXIMUM_RESTART_ITERATIONS 3
62#define AUTO_STAR_TIMEOUT 45000
63#define MINIMUM_PULSE_TIMER 32
64#define MAX_RECAPTURE_RETRIES 3
65#define MINIMUM_POLY_SOLUTIONS 2
78 qRegisterMetaType<Ekos::FocusState>(
"Ekos::FocusState");
79 qDBusRegisterMetaType<Ekos::FocusState>();
80 new FocusAdaptor(
this);
99 connectSyncSettings();
102 adaptFocus.reset(
new AdaptiveFocus(
this));
105 focusAdvisor.reset(
new FocusAdvisor(
this));
107 connect(focusAdvisor.get(), &FocusAdvisor::newStage,
this, &Focus::newFocusAdvisorStage);
108 connect(focusAdvisor.get(), &FocusAdvisor::newMessage,
this, &Focus::newFocusAdvisorMessage);
115 for (
auto &button : qButtons)
116 button->setAutoDefault(false);
118 appendLogText(
i18n(
"Idle."));
121 m_FocusMotionTimer.setInterval(m_OpsFocusMechanics->focusMotionTimeout->value() * 1000);
122 m_FocusMotionTimer.setSingleShot(
true);
128 m_FocusLogFile.setFileName(m_FocusLogFileName);
130 m_OpsFocusProcess->editFocusProfile->setIcon(
QIcon::fromTheme(
"document-edit"));
135 KConfigDialog *optionsEditor = new KConfigDialog(this,
"OptionsProfileEditor", Options::self());
136 optionsProfileEditor = new StellarSolverProfileEditor(this, Ekos::FocusProfiles, optionsEditor);
138 optionsEditor->setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
140 KPageWidgetItem *mainPage = optionsEditor->addPage(optionsProfileEditor, i18n(
"Focus Options Profile Editor"));
141 mainPage->setIcon(QIcon::fromTheme(
"configure"));
142 connect(optionsProfileEditor, &StellarSolverProfileEditor::optionsProfilesUpdated, this, &Focus::loadStellarSolverProfiles);
143 optionsProfileEditor->loadProfile(m_OpsFocusProcess->focusSEPProfile->currentText());
144 optionsEditor->show();
147 loadStellarSolverProfiles();
161 m_DarkProcessor =
new DarkProcessor(
this);
163 connect(m_DarkProcessor, &DarkProcessor::darkFrameCompleted,
this, [
this](
bool completed)
165 m_OpsFocusSettings->useFocusDarkFrame->setChecked(completed);
166 m_FocusView->setProperty(
"suspended",
false);
169 m_FocusView->rescale(ZOOM_KEEP_LEVEL);
170 m_FocusView->updateFrame();
172 setCaptureComplete();
176 setupOpticalTrainManager();
178 connectFilterManager();
182void Focus::prepareGUI()
192 m_OpsFocusSettings =
new OpsFocusSettings();
200 m_OpsFocusProcess =
new OpsFocusProcess();
201 page = dialog->
addPage(m_OpsFocusProcess,
i18n(
"Process"),
nullptr,
i18n(
"Focus Process"),
false);
204 m_OpsFocusMechanics =
new OpsFocusMechanics();
205 page = dialog->
addPage(m_OpsFocusMechanics,
i18n(
"Mechanics"),
nullptr,
i18n(
"Focus Mechanics"),
false);
209 m_CFZDialog =
new QDialog(
this);
210 m_CFZUI.reset(
new Ui::focusCFZDialog());
211 m_CFZUI->setupUi(m_CFZDialog);
217 m_OpsFocusProcess->gridLayoutProcessBucket->removeWidget(m_OpsFocusProcess->focusMultiRowAverageLabel);
218 m_OpsFocusProcess->gridLayoutProcessBucket->removeWidget(m_OpsFocusProcess->focusMultiRowAverage);
219 m_OpsFocusProcess->gridLayoutProcessBucket->removeWidget(m_OpsFocusProcess->focusGaussianSigmaLabel);
220 m_OpsFocusProcess->gridLayoutProcessBucket->removeWidget(m_OpsFocusProcess->focusGaussianSigma);
221 m_OpsFocusProcess->gridLayoutProcessBucket->removeWidget(m_OpsFocusProcess->focusThresholdLabel);
222 m_OpsFocusProcess->gridLayoutProcessBucket->removeWidget(m_OpsFocusProcess->focusThreshold);
223 m_OpsFocusProcess->gridLayoutProcessBucket->removeWidget(m_OpsFocusProcess->focusGaussianKernelSizeLabel);
224 m_OpsFocusProcess->gridLayoutProcessBucket->removeWidget(m_OpsFocusProcess->focusGaussianKernelSize);
225 m_OpsFocusProcess->gridLayoutProcessBucket->removeWidget(m_OpsFocusProcess->focusToleranceLabel);
226 m_OpsFocusProcess->gridLayoutProcessBucket->removeWidget(m_OpsFocusProcess->focusTolerance);
227 delete m_OpsFocusProcess->gridLayoutProcessBucket;
230 m_OpsFocusMechanics->gridLayoutMechanics->replaceWidget(m_OpsFocusMechanics->focusOutStepsLabel,
231 m_OpsFocusMechanics->focusNumStepsLabel);
232 m_OpsFocusMechanics->gridLayoutMechanics->replaceWidget(m_OpsFocusMechanics->focusOutSteps,
233 m_OpsFocusMechanics->focusNumSteps);
237 for (
int i = 0; i < m_OpsFocusProcess->focusStarMeasure->count(); i++)
238 m_StarMeasureText.append(m_OpsFocusProcess->focusStarMeasure->itemText(i));
239 for (
int i = 0; i < m_OpsFocusProcess->focusCurveFit->count(); i++)
240 m_CurveFitText.append(m_OpsFocusProcess->focusCurveFit->itemText(i));
241 for (
int i = 0; i < m_OpsFocusMechanics->focusWalk->count(); i++)
242 m_FocusWalkText.append(m_OpsFocusMechanics->focusWalk->itemText(i));
245void Focus::loadStellarSolverProfiles()
247 QString savedOptionsProfiles =
QDir(KSPaths::writableLocation(
251 m_StellarSolverProfiles = StellarSolver::loadSavedOptionsProfiles(savedOptionsProfiles);
252 addMissingStellarSolverProfile(savedOptionsProfiles, FOCUS_DEFAULT_NAME);
253 addMissingStellarSolverProfile(savedOptionsProfiles, FOCUS_DEFAULT_DONUT_NAME);
256 m_StellarSolverProfiles = getDefaultFocusOptionsProfiles();
257 m_OpsFocusProcess->focusSEPProfile->clear();
258 for(
auto ¶m : m_StellarSolverProfiles)
259 m_OpsFocusProcess->focusSEPProfile->addItem(param.listName);
260 auto profile = m_Settings[
"focusSEPProfile"];
261 if (profile.isValid())
262 m_OpsFocusProcess->focusSEPProfile->setCurrentText(profile.toString());
265void Focus::addMissingStellarSolverProfile(
const QString profilePath,
const QString profile)
267 for(
auto params : m_StellarSolverProfiles)
269 if (params.listName == profile)
275 SSolver::Parameters params;
276 if (profile == FOCUS_DEFAULT_DONUT_NAME)
277 params = getFocusOptionsProfileDefaultDonut();
278 else if (profile == FOCUS_DEFAULT_NAME)
279 params = getFocusOptionsProfileDefault();
283 settings.beginGroup(params.listName);
289 settings.setValue(it.key(), it.value());
293 m_StellarSolverProfiles.append(params);
299 for (
auto param : m_StellarSolverProfiles)
300 profiles << param.listName;
307 if (focusingWidget->parent() ==
nullptr)
308 toggleFocusingWidgetFullScreen();
310 m_FocusLogFile.close();
313void Focus::resetFrame()
315 if (m_Camera && m_Camera->isConnected())
317 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
322 targetChip->resetFrame();
325 targetChip->getFrame(&x, &y, &w, &h);
327 qCDebug(KSTARS_EKOS_FOCUS) <<
"Frame is reset. X:" << x <<
"Y:" << y <<
"W:" << w <<
"H:" << h <<
"binX:" << 1 <<
"binY:" <<
330 QVariantMap settings;
335 settings[
"binx"] = 1;
336 settings[
"biny"] = 1;
337 frameSettings[targetChip] = settings;
339 starSelected =
false;
343 m_FocusView->setTrackingBox(
QRect());
344 checkMosaicMaskLimits();
352 return m_Camera->getDeviceName();
357void Focus::checkCamera()
377 case FOCUS_CHANGING_FILTER:
382 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
383 if (targetChip && targetChip->isCapturing())
388 focusBinning->setEnabled(targetChip->canBin());
389 m_OpsFocusSettings->focusSubFrame->setEnabled(targetChip->canSubframe());
390 if (targetChip->canBin())
392 int subBinX = 1, subBinY = 1;
393 focusBinning->clear();
394 targetChip->getMaxBin(&subBinX, &subBinY);
395 for (
int i = 1; i <= subBinX; i++)
396 focusBinning->addItem(
QString(
"%1x%2").arg(i).arg(i));
398 auto binning = m_Settings[
"focusBinning"];
399 if (binning.isValid())
400 focusBinning->setCurrentText(binning.toString());
403 connect(m_Camera, &ISD::Camera::videoStreamToggled,
this, &Ekos::Focus::setVideoStreamEnabled,
Qt::UniqueConnection);
404 liveVideoB->setEnabled(m_Camera->hasVideoStream());
405 if (m_Camera->hasVideoStream())
406 setVideoStreamEnabled(m_Camera->isStreamingEnabled());
416void Focus::syncCCDControls()
418 if (m_Camera ==
nullptr)
421 auto targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
422 if (targetChip ==
nullptr || (targetChip && targetChip->isCapturing()))
425 auto isoList = targetChip->getISOList();
428 if (isoList.isEmpty())
430 focusISO->setEnabled(
false);
431 ISOLabel->setEnabled(
false);
435 focusISO->setEnabled(
true);
436 ISOLabel->setEnabled(
true);
437 focusISO->addItems(isoList);
438 focusISO->setCurrentIndex(targetChip->getISOIndex());
441 bool hasGain = m_Camera->hasGain();
442 gainLabel->setEnabled(hasGain);
443 focusGain->setEnabled(hasGain && m_Camera->getGainPermission() != IP_RO);
446 double gain = 0, min = 0, max = 0, step = 1;
447 m_Camera->getGainMinMaxStep(&min, &max, &step);
448 if (m_Camera->getGain(&gain))
451 GainSpinSpecialValue = min - step;
452 focusGain->setRange(GainSpinSpecialValue, max);
453 focusGain->setSpecialValueText(
i18n(
"--"));
455 focusGain->setSingleStep(step);
457 auto defaultGain = m_Settings[
"focusGain"];
458 if (defaultGain.isValid())
459 focusGain->setValue(defaultGain.toDouble());
461 focusGain->setValue(GainSpinSpecialValue);
468void Focus::syncCameraInfo()
470 if (m_Camera ==
nullptr)
473 auto targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
474 if (targetChip ==
nullptr || (targetChip && targetChip->isCapturing()))
477 m_OpsFocusSettings->focusSubFrame->setEnabled(targetChip->canSubframe());
479 if (frameSettings.contains(targetChip) ==
false)
482 if (targetChip->getFrame(&x, &y, &w, &h))
484 int binx = 1, biny = 1;
485 targetChip->getBinning(&binx, &biny);
488 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
489 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
491 QVariantMap settings;
493 settings[
"x"] = m_OpsFocusSettings->focusSubFrame->isChecked() ? x : minX;
494 settings[
"y"] = m_OpsFocusSettings->focusSubFrame->isChecked() ? y : minY;
495 settings[
"w"] = m_OpsFocusSettings->focusSubFrame->isChecked() ? w : maxW;
496 settings[
"h"] = m_OpsFocusSettings->focusSubFrame->isChecked() ? h : maxH;
497 settings[
"binx"] = binx;
498 settings[
"biny"] = biny;
500 frameSettings[targetChip] = settings;
506bool Focus::setFilterWheel(ISD::FilterWheel *device)
508 if (m_FilterWheel && m_FilterWheel == device)
515 m_FilterWheel->disconnect(
this);
517 m_FilterWheel = device;
521 connect(m_FilterWheel, &ISD::ConcreteDevice::Connected,
this, [
this]()
523 FilterPosLabel->setEnabled(
true);
524 focusFilter->setEnabled(
true);
525 filterManagerB->setEnabled(
true);
527 connect(m_FilterWheel, &ISD::ConcreteDevice::Disconnected,
this, [
this]()
529 FilterPosLabel->setEnabled(
false);
530 focusFilter->setEnabled(
false);
531 filterManagerB->setEnabled(
false);
535 auto isConnected = m_FilterWheel && m_FilterWheel->isConnected();
536 FilterPosLabel->setEnabled(isConnected);
537 focusFilter->setEnabled(isConnected);
538 filterManagerB->setEnabled(isConnected);
540 FilterPosLabel->setEnabled(
true);
541 focusFilter->setEnabled(
true);
552 for (
auto &oneSource : m_TemperatureSources)
554 if (oneSource->getDeviceName() == device->getDeviceName())
558 m_TemperatureSources.append(device);
559 defaultFocusTemperatureSource->addItem(device->getDeviceName());
561 auto targetSource = m_Settings[
"defaultFocusTemperatureSource"];
562 if (targetSource.isValid())
563 checkTemperatureSource(targetSource.toString());
567void Focus::checkTemperatureSource(
const QString &name )
572 source = defaultFocusTemperatureSource->currentText();
573 if (source.isEmpty())
579 for (
auto &oneSource : m_TemperatureSources)
581 if (oneSource->getDeviceName() == source)
583 currentSource = oneSource;
588 m_LastSourceDeviceAutofocusTemperature = currentSource;
595 for (
const auto &oneSource : m_TemperatureSources)
599 if (findTemperatureElement(currentSource))
601 m_LastSourceAutofocusTemperature = currentTemperatureSourceElement->value;
602 absoluteTemperatureLabel->setText(
QString(
"%1 °C").
arg(currentTemperatureSourceElement->value, 0,
'f', 2));
603 deltaTemperatureLabel->setText(
QString(
"%1 °C").
arg(0.0, 0,
'f', 2));
607 m_LastSourceAutofocusTemperature = INVALID_VALUE;
620 auto temperatureProperty = device->getProperty(
"FOCUS_TEMPERATURE");
621 if (!temperatureProperty)
622 temperatureProperty = device->getProperty(
"CCD_TEMPERATURE");
623 if (temperatureProperty)
625 currentTemperatureSourceElement = temperatureProperty.getNumber()->at(0);
629 temperatureProperty = device->getProperty(
"WEATHER_PARAMETERS");
630 if (temperatureProperty)
632 for (
int i = 0; i < temperatureProperty.getNumber()->count(); i++)
634 if (strstr(temperatureProperty.getNumber()->at(i)->getName(),
"_TEMPERATURE"))
636 currentTemperatureSourceElement = temperatureProperty.getNumber()->at(i);
648 return m_FilterWheel->getDeviceName();
658 focusFilter->setCurrentText(filter);
667 return focusFilter->currentText();
670void Focus::checkFilter()
672 focusFilter->
clear();
676 FilterPosLabel->setEnabled(
false);
677 focusFilter->setEnabled(
false);
678 filterManagerB->setEnabled(
false);
682 m_FilterManager->disconnect(
this);
683 disconnect(m_FilterManager.get());
684 m_FilterManager.reset();
689 FilterPosLabel->setEnabled(
true);
690 focusFilter->setEnabled(
true);
691 filterManagerB->setEnabled(
true);
693 setupFilterManager();
695 focusFilter->addItems(m_FilterManager->getFilterLabels());
697 currentFilterPosition = m_FilterManager->getFilterPosition();
699 focusFilter->setCurrentIndex(currentFilterPosition - 1);
701 focusExposure->setValue(m_FilterManager->getFilterExposure());
706 if (m_Focuser && m_Focuser == device)
713 m_Focuser->disconnect(
this);
719 connect(m_Focuser, &ISD::ConcreteDevice::Connected,
this, [
this]()
723 connect(m_Focuser, &ISD::ConcreteDevice::Disconnected,
this, [
this]()
736 return m_Focuser->getDeviceName();
741void Focus::checkFocuser()
746 m_FilterManager->setFocusReady(
false);
747 canAbsMove = canRelMove = canTimerMove =
false;
749 setFocusAlgorithm(
static_cast<Algorithm
> (m_OpsFocusProcess->focusAlgorithm->currentIndex()));
753 focuserLabel->setText(m_Focuser->getDeviceName());
756 m_FilterManager->setFocusReady(m_Focuser->isConnected());
758 hasDeviation = m_Focuser->hasDeviation();
760 canAbsMove = m_Focuser->canAbsMove();
764 getAbsFocusPosition();
766 absTicksSpin->setEnabled(
true);
767 absTicksLabel->setEnabled(
true);
768 startGotoB->setEnabled(
true);
771 if (absTicksSpin->value() <= 0)
772 absTicksSpin->setValue(currentPosition);
776 absTicksSpin->setEnabled(
false);
777 absTicksLabel->setEnabled(
false);
778 startGotoB->setEnabled(
false);
781 canRelMove = m_Focuser->canRelMove();
786 if (canAbsMove ==
false && canRelMove ==
true)
788 currentPosition = 50000;
789 absMotionMax = 100000;
793 canTimerMove = m_Focuser->canTimerMove();
799 if (!canAbsMove && !canRelMove && canTimerMove)
801 currentPosition = 50000;
802 absMotionMax = 100000;
806 m_FocusType = (canRelMove || canAbsMove || canTimerMove) ? FOCUS_AUTO : FOCUS_MANUAL;
807 profilePlot->setFocusAuto(m_FocusType == FOCUS_AUTO);
809 bool hasBacklash = m_Focuser->hasBacklash();
810 m_OpsFocusMechanics->focusBacklash->setEnabled(hasBacklash);
811 m_OpsFocusMechanics->focusBacklash->disconnect(
this);
814 double min = 0, max = 0, step = 0;
815 m_Focuser->getMinMaxStep(
"FOCUS_BACKLASH_STEPS",
"FOCUS_BACKLASH_VALUE", &min, &max, &step);
816 m_OpsFocusMechanics->focusBacklash->setMinimum(min);
817 m_OpsFocusMechanics->focusBacklash->setMaximum(max);
818 m_OpsFocusMechanics->focusBacklash->setSingleStep(step);
819 m_OpsFocusMechanics->focusBacklash->setValue(m_Focuser->getBacklash());
821 this, [
this](
int value)
825 if (m_Focuser->getBacklash() == value)
831 m_Focuser->setBacklash(value);
836 connect(m_OpsFocusMechanics->focusBacklash, QOverload<int>::of(&
QSpinBox::valueChanged),
this, &Ekos::Focus::syncSettings);
840 m_OpsFocusMechanics->focusBacklash->setValue(0);
846 setFocusAlgorithm(
static_cast<Algorithm
> (m_OpsFocusProcess->focusAlgorithm->currentIndex()));
851 if (m_Camera && m_Camera == device)
857 m_captureInProgress =
false;
860 m_Camera->disconnect(
this);
866 connect(m_Camera, &ISD::ConcreteDevice::Connected,
this, [
this]()
868 focuserGroup->setEnabled(
true);
869 ccdGroup->setEnabled(
true);
870 toolsGroup->setEnabled(
true);
872 connect(m_Camera, &ISD::ConcreteDevice::Disconnected,
this, [
this]()
874 focuserGroup->setEnabled(
false);
875 ccdGroup->setEnabled(
false);
876 toolsGroup->setEnabled(
false);
880 auto isConnected = m_Camera && m_Camera->isConnected();
881 focuserGroup->setEnabled(isConnected);
882 ccdGroup->setEnabled(isConnected);
883 toolsGroup->setEnabled(isConnected);
891 checkMosaicMaskLimits();
895void Focus::getAbsFocusPosition()
900 auto absMove = m_Focuser->getNumber(
"ABS_FOCUS_POSITION");
904 const auto &it = absMove->at(0);
905 currentPosition =
static_cast<int>(it->getValue());
906 absMotionMax = it->getMax();
907 absMotionMin = it->getMin();
909 absTicksSpin->setMinimum(it->getMin());
910 absTicksSpin->setMaximum(it->getMax());
911 absTicksSpin->setSingleStep(it->getStep());
914 double const travel = std::abs(it->getMax() - it->getMin());
915 m_OpsFocusMechanics->focusMaxTravel->setMaximum(travel);;
919 m_OpsFocusMechanics->focusTicks->setMaximum(it->getMax() / 2);
923void Focus::processTemperatureSource(INDI::Property prop)
925 if (m_LastSourceAutofocusTemperature == INVALID_VALUE && m_LastSourceDeviceAutofocusTemperature
926 && !currentTemperatureSourceElement )
928 if( findTemperatureElement( m_LastSourceDeviceAutofocusTemperature ) )
930 appendLogText(
i18n(
"Finally found temperature source %1",
QString(currentTemperatureSourceElement->nvp->name)));
931 m_LastSourceAutofocusTemperature = currentTemperatureSourceElement->value;
936 if (currentTemperatureSourceElement && currentTemperatureSourceElement->nvp->name == prop.getName())
938 if (m_LastSourceAutofocusTemperature != INVALID_VALUE)
940 delta = currentTemperatureSourceElement->value - m_LastSourceAutofocusTemperature;
941 emit newFocusTemperatureDelta(abs(delta), currentTemperatureSourceElement->value);
945 emit newFocusTemperatureDelta(0, currentTemperatureSourceElement->value);
948 absoluteTemperatureLabel->setText(
QString(
"%1 °C").arg(currentTemperatureSourceElement->value, 0,
'f', 2));
949 deltaTemperatureLabel->setText(
QString(
"%1%2 °C").arg((delta > 0.0 ?
"+" :
"")).
arg(delta, 0,
'f', 2));
951 deltaTemperatureLabel->setStyleSheet(
"color: lightgreen");
953 deltaTemperatureLabel->setStyleSheet(
"color: lightcoral");
955 deltaTemperatureLabel->setStyleSheet(
"color: lightblue");
959void Focus::setLastFocusTemperature()
961 m_LastSourceAutofocusTemperature = currentTemperatureSourceElement ? currentTemperatureSourceElement->value : INVALID_VALUE;
964 deltaTemperatureLabel->setText(
QString(
"0 °C"));
965 deltaTemperatureLabel->setStyleSheet(
"color: lightgreen");
967 emit newFocusTemperatureDelta(0, -1e6);
970void Focus::setLastFocusAlt()
972 if (mountAlt < 0.0 || mountAlt > 90.0)
973 m_LastSourceAutofocusAlt = INVALID_VALUE;
975 m_LastSourceAutofocusAlt = mountAlt;
979void Focus::resetAdaptiveFocus(
bool enabled)
982 Options::setFocusAdaptive(enabled);
985 adaptFocus.reset(
new AdaptiveFocus(
this));
986 adaptFocus->resetAdaptiveFocusCounters();
990void Focus::adaptiveFocus()
993 adaptFocus->runAdaptiveFocus(currentPosition, filter());
997void Focus::startAbIns()
999 m_abInsOn = canAbInsStart();
1000 runAutoFocus(AutofocusReason::FOCUS_ABERRATION_INSPECTOR,
"");
1004void Focus::manualStart()
1006 runAutoFocus(AutofocusReason::FOCUS_MANUAL,
"");
1012 runAutoFocus(AutofocusReason::FOCUS_SCHEDULER,
"");
1016void Focus::runAutoFocus(AutofocusReason autofocusReason,
const QString &reasonInfo)
1018 m_AutofocusReason = autofocusReason;
1019 m_AutofocusReasonInfo = reasonInfo;
1020 if (m_Focuser ==
nullptr)
1022 appendLogText(
i18n(
"No Focuser connected."));
1023 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_NO_FOCUSER);
1027 if (m_Camera ==
nullptr)
1029 appendLogText(
i18n(
"No CCD connected."));
1030 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_NO_CAMERA);
1034 if (!canAbsMove && !canRelMove && m_OpsFocusMechanics->focusTicks->value() <= MINIMUM_PULSE_TIMER)
1036 appendLogText(
i18n(
"Starting pulse step is too low. Increase the step size to %1 or higher...",
1037 MINIMUM_PULSE_TIMER * 5));
1038 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_LOW_PULSE);
1047 appendLogText(
i18n(
"Autofocus is already running, discarding start request."));
1054 appendLogText(
i18n(
"Build Offset is already running, Autofocus rejected."));
1055 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_INTERNAL);
1062 appendLogText(
i18n(
"In Focus Loop, Autofocus rejected."));
1063 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_INTERNAL);
1067 if (inAdjustFocus || adaptFocus->inAdaptiveFocus())
1069 QString str = inAdjustFocus ?
i18n(
"Adjust Focus") :
i18n(
"Adaptive Focus");
1070 if (++m_StartRetries < MAXIMUM_RESTART_ITERATIONS)
1072 appendLogText(
i18n(
"Autofocus start request - Waiting 10sec for %1 to complete.", str));
1075 runAutoFocus(m_AutofocusReason, m_AutofocusReasonInfo);
1080 appendLogText(
i18n(
"Discarding Autofocus start request - %1 in progress.", str));
1081 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_INTERNAL);
1085 inBuildOffsets = (autofocusReason == AutofocusReason::FOCUS_FILTER_OFFSETS);
1086 if (autofocusReason == AutofocusReason::FOCUS_USER_REQUEST)
1088 forceInSeqAF->setChecked(
false);
1089 Options::setFocusForceInSeqAF(
false);
1094 m_LastFocusDirection = FOCUS_NONE;
1096 waitStarSelectTimer.stop();
1099 m_FocusMotionTimerCounter = 0;
1100 m_FocusMotionTimer.stop();
1101 m_FocusMotionTimer.setInterval(m_OpsFocusMechanics->focusMotionTimeout->value() * 1000);
1104 m_FocuserReconnectCounter = 0;
1107 m_FocuserReconnectCounter = 0;
1108 m_DebugFocuserCounter = 0;
1115 m_RestartState = RESTART_NONE;
1123 getAbsFocusPosition();
1124 pulseDuration = m_OpsFocusMechanics->focusTicks->value();
1126 else if (canRelMove)
1130 pulseDuration = m_OpsFocusMechanics->focusTicks->value();
1132 absMotionMax = 100000;
1137 pulseDuration = m_OpsFocusMechanics->focusTicks->value();
1139 absMotionMax = 100000;
1143 focuserAdditionalMovement = 0;
1144 starMeasureFrames.clear();
1156 profilePlot->clear();
1157 FWHMOut->setText(
"");
1159 qCInfo(KSTARS_EKOS_FOCUS) <<
"Starting Autofocus " << m_AFRun
1160 <<
" on" << focuserLabel->text()
1161 <<
" Reason: " << AutofocusReasonStr[m_AutofocusReason]
1162 <<
" Reason Info: " << m_AutofocusReasonInfo
1163 <<
" CanAbsMove: " << (canAbsMove ?
"yes" :
"no" )
1164 <<
" CanRelMove: " << (canRelMove ?
"yes" :
"no" )
1165 <<
" CanTimerMove: " << (canTimerMove ?
"yes" :
"no" )
1166 <<
" Position:" << currentPosition
1167 <<
" Filter:" << filter()
1168 <<
" Exp:" << focusExposure->value()
1169 <<
" Bin:" << focusBinning->currentText()
1170 <<
" Gain:" << focusGain->value()
1171 <<
" ISO:" << focusISO->currentText();
1172 qCInfo(KSTARS_EKOS_FOCUS) <<
"Settings Tab."
1173 <<
" Auto Select Star:" << ( m_OpsFocusSettings->focusAutoStarEnabled->isChecked() ?
"yes" :
"no" )
1174 <<
" Dark Frame:" << ( m_OpsFocusSettings->useFocusDarkFrame->isChecked() ?
"yes" :
"no" )
1175 <<
" Sub Frame:" << ( m_OpsFocusSettings->focusSubFrame->isChecked() ?
"yes" :
"no" )
1176 <<
" Box:" << m_OpsFocusSettings->focusBoxSize->value()
1177 <<
" Full frame:" << ( m_OpsFocusSettings->focusUseFullField->isChecked() ?
"yes" :
"no " )
1178 <<
" Focus Mask: " << (m_OpsFocusSettings->focusNoMaskRB->isChecked() ?
"Use all stars" :
1179 (m_OpsFocusSettings->focusRingMaskRB->isChecked() ?
QString(
"Ring Mask: [%1%, %2%]").
1180 arg(m_OpsFocusSettings->focusFullFieldInnerRadius->value()).
arg(m_OpsFocusSettings->focusFullFieldOuterRadius->value()) :
1181 QString(
"Mosaic Mask: [%1%, space=%2px]").
1182 arg(m_OpsFocusSettings->focusMosaicTileWidth->value()).
arg(m_OpsFocusSettings->focusMosaicSpace->value())))
1183 <<
" Suspend Guiding:" << ( m_OpsFocusSettings->focusSuspendGuiding->isChecked() ?
"yes" :
"no " )
1184 <<
" Guide Settle:" << m_OpsFocusSettings->focusGuideSettleTime->value()
1185 <<
" Display Units:" << m_OpsFocusSettings->focusUnits->currentText()
1186 <<
" Adaptive Focus:" << ( m_OpsFocusSettings->focusAdaptive->isChecked() ?
"yes" :
"no" )
1187 <<
" Min Move:" << m_OpsFocusSettings->focusAdaptiveMinMove->value()
1188 <<
" Adapt Start:" << ( m_OpsFocusSettings->focusAdaptStart->isChecked() ?
"yes" :
"no" )
1189 <<
" Max Total Move:" << m_OpsFocusSettings->focusAdaptiveMaxMove->value();
1190 qCInfo(KSTARS_EKOS_FOCUS) <<
"Process Tab."
1191 <<
" Detection:" << m_OpsFocusProcess->focusDetection->currentText()
1192 <<
" SEP Profile:" << m_OpsFocusProcess->focusSEPProfile->currentText()
1193 <<
" Algorithm:" << m_OpsFocusProcess->focusAlgorithm->currentText()
1194 <<
" Curve Fit:" << m_OpsFocusProcess->focusCurveFit->currentText()
1195 <<
" Measure:" << m_OpsFocusProcess->focusStarMeasure->currentText()
1196 <<
" PSF:" << m_OpsFocusProcess->focusStarPSF->currentText()
1197 <<
" Use Weights:" << ( m_OpsFocusProcess->focusUseWeights->isChecked() ?
"yes" :
"no" )
1198 <<
" R2 Limit:" << m_OpsFocusProcess->focusR2Limit->value()
1199 <<
" Refine Curve Fit:" << ( m_OpsFocusProcess->focusRefineCurveFit->isChecked() ?
"yes" :
"no" )
1200 <<
" Average Over:" << m_OpsFocusProcess->focusFramesCount->value()
1201 <<
" Average HFR Check Over:" << m_OpsFocusProcess->focusHFRFramesCount->value()
1202 <<
" Num.of Rows:" << m_OpsFocusProcess->focusMultiRowAverage->value()
1203 <<
" Sigma:" << m_OpsFocusProcess->focusGaussianSigma->value()
1204 <<
" Threshold:" << m_OpsFocusProcess->focusThreshold->value()
1205 <<
" Kernel size:" << m_OpsFocusProcess->focusGaussianKernelSize->value()
1206 <<
" Tolerance:" << m_OpsFocusProcess->focusTolerance->value()
1207 <<
" Donut Buster:" << ( m_OpsFocusProcess->focusDonut->isChecked() ?
"yes" :
"no" )
1208 <<
" Donut Time Dilation:" << m_OpsFocusProcess->focusTimeDilation->value()
1209 <<
" Outlier Rejection:" << m_OpsFocusProcess->focusOutlierRejection->value()
1210 <<
" Scan Start Pos:" << ( m_OpsFocusProcess->focusScanStartPos->isChecked() ?
"yes" :
"no" )
1211 <<
" Scan Always On:" << ( m_OpsFocusProcess->focusScanAlwaysOn->isChecked() ?
"yes" :
"no" )
1212 <<
" Num Datapoints:" << m_OpsFocusProcess->focusScanDatapoints->value()
1213 <<
" Scan Step Factor:" << m_OpsFocusProcess->focusScanStepSizeFactor->value();
1214 qCInfo(KSTARS_EKOS_FOCUS) <<
"Mechanics Tab."
1215 <<
" Initial Step Size:" << m_OpsFocusMechanics->focusTicks->value()
1216 <<
" Out Step Multiple:" << m_OpsFocusMechanics->focusOutSteps->value()
1217 <<
" Number Steps:" << m_OpsFocusMechanics->focusNumSteps->value()
1218 <<
" Max Travel:" << m_OpsFocusMechanics->focusMaxTravel->value()
1219 <<
" Max Step Size:" << m_OpsFocusMechanics->focusMaxSingleStep->value()
1220 <<
" Driver Backlash:" << m_OpsFocusMechanics->focusBacklash->value()
1221 <<
" AF Overscan:" << m_OpsFocusMechanics->focusAFOverscan->value()
1222 <<
" Overscan Delay:" << m_OpsFocusMechanics->focusOverscanDelay->value()
1223 <<
" Focuser Settle:" << m_OpsFocusMechanics->focusSettleTime->value()
1224 <<
" Walk:" << m_OpsFocusMechanics->focusWalk->currentText()
1225 <<
" Capture Timeout:" << m_OpsFocusMechanics->focusCaptureTimeout->value()
1226 <<
" Motion Timeout:" << m_OpsFocusMechanics->focusMotionTimeout->value();
1227 qCInfo(KSTARS_EKOS_FOCUS) <<
"CFZ Tab."
1228 <<
" Algorithm:" << m_CFZUI->focusCFZAlgorithm->currentText()
1229 <<
" Tolerance:" << m_CFZUI->focusCFZTolerance->value()
1230 <<
" Tolerance (Ï„):" << m_CFZUI->focusCFZTau->value()
1231 <<
" Display:" << ( m_CFZUI->focusCFZDisplayVCurve->isChecked() ?
"yes" :
"no" )
1232 <<
" Wavelength (λ):" << m_CFZUI->focusCFZWavelength->value()
1233 <<
" Aperture (A):" << m_CFZUI->focusCFZAperture->value()
1234 <<
" Focal Ratio (f):" << m_CFZUI->focusCFZFNumber->value()
1235 <<
" Step Size:" << m_CFZUI->focusCFZStepSize->value()
1236 <<
" FWHM (θ):" << m_CFZUI->focusCFZSeeing->value();
1238 const double temperature = (currentTemperatureSourceElement) ? currentTemperatureSourceElement->value : INVALID_VALUE;
1239 emit autofocusStarting(temperature, filter(), m_AutofocusReason, m_AutofocusReasonInfo);
1241 if (m_OpsFocusSettings->focusAutoStarEnabled->isChecked())
1242 appendLogText(
i18n(
"Autofocus in progress..."));
1243 else if (!inAutoFocus)
1244 appendLogText(
i18n(
"Please wait until image capture is complete..."));
1249 if (m_GuidingSuspended ==
false && m_OpsFocusSettings->focusSuspendGuiding->isChecked())
1251 m_GuidingSuspended =
true;
1252 emit suspendGuiding();
1256 setState(Ekos::FOCUS_PROGRESS);
1258 KSNotification::event(
QLatin1String(
"FocusStarted"),
i18n(
"Autofocus operation started"), KSNotification::Focus);
1261 if (m_FocusAlgorithm == FOCUS_LINEAR || m_FocusAlgorithm == FOCUS_LINEAR1PASS)
1263 m_AFfilter = filter();
1264 int position = adaptFocus->adaptStartPosition(currentPosition, m_AFfilter);
1266 curveFitting.reset(
new CurveFitting());
1268 if (m_FocusAlgorithm == FOCUS_LINEAR1PASS)
1271 starFitting.reset(
new CurveFitting());
1272 focusFWHM.reset(
new FocusFWHM(m_ScaleCalc));
1273 focusFourierPower.reset(
new FocusFourierPower(m_ScaleCalc));
1275 initDonutProcessing();
1277 if (initScanStartPos(
false, currentPosition))
1280 if (m_AutofocusReason == FOCUS_FOCUS_ADVISOR)
1282 focusAdvisor->initControl();
1288 setupLinearFocuser(position);
1289 if (!changeFocus(linearRequestedPosition - currentPosition))
1290 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FOCUSER_NO_MOVE);
1298void Focus::setupLinearFocuser(
int initialPosition)
1300 FocusAlgorithmInterface::FocusParams params(curveFitting.get(),
1301 m_OpsFocusMechanics->focusMaxTravel->value(), m_OpsFocusMechanics->focusTicks->value(), initialPosition, absMotionMin,
1302 absMotionMax, MAXIMUM_ABS_ITERATIONS, m_OpsFocusProcess->focusTolerance->value() / 100.0, m_AFfilter,
1303 currentTemperatureSourceElement ? currentTemperatureSourceElement->value : INVALID_VALUE,
1304 m_OpsFocusMechanics->focusOutSteps->value(), m_OpsFocusMechanics->focusNumSteps->value(),
1305 m_FocusAlgorithm, m_OpsFocusMechanics->focusBacklash->value(), m_CurveFit, m_OpsFocusProcess->focusUseWeights->isChecked(),
1306 m_StarMeasure, m_StarPSF, m_OpsFocusProcess->focusRefineCurveFit->isChecked(), m_FocusWalk,
1307 m_OpsFocusProcess->focusDonut->isChecked(), m_OpsFocusProcess->focusOutlierRejection->value(), m_OptDir, m_ScaleCalc);
1310 initialFocuserAbsPosition = initialPosition;
1311 linearFocuser.reset(MakeLinearFocuser(params));
1312 linearRequestedPosition = linearFocuser->initialPosition();
1316void Focus::initDonutProcessing()
1318 if (!m_OpsFocusProcess->focusDonut->isChecked())
1321 m_donutOrigExposure = focusExposure->value();
1325void Focus::resetDonutProcessing()
1328 if (m_OpsFocusProcess->focusDonut->isChecked() && inAutoFocus)
1329 focusExposure->setValue(m_donutOrigExposure);
1332int Focus::adjustLinearPosition(
int position,
int newPosition,
int overscan,
bool updateDir)
1334 if (overscan > 0 && newPosition > position)
1337 int adjustment = overscan;
1338 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Linear: extending outward movement by overscan %1").
arg(adjustment);
1340 if (newPosition + adjustment > absMotionMax)
1341 adjustment =
static_cast<int>(absMotionMax) - newPosition;
1343 focuserAdditionalMovement = adjustment;
1344 focuserAdditionalMovementUpdateDir = updateDir;
1346 return newPosition + adjustment;
1354void Focus::checkStopFocus(
bool abort)
1356 m_abortInProgress =
true;
1359 resetFocusIteration = MAXIMUM_RESET_ITERATIONS + 1;
1361 if (captureTimer.isActive())
1363 captureTimer.stop();
1365 if (m_captureInProgress)
1367 if (inAutoFocus ==
false && inFocusLoop ==
false)
1369 captureB->setEnabled(
true);
1370 stopFocusB->setEnabled(
false);
1372 appendLogText(
i18n(
"Capture aborted."));
1374 else if (inAutoFocus)
1376 stopFocusB->setEnabled(
false);
1377 appendLogText(
i18n(
"Capture in progress, retrying in 1s..."));
1380 checkStopFocus(abort);
1386 if (m_starDetectInProgress)
1388 stopFocusB->setEnabled(
false);
1389 appendLogText(
i18n(
"Star detection in progress, retrying in 1s..."));
1392 checkStopFocus(abort);
1397 completeFocusProcedure(abort ? Ekos::FOCUS_ABORTED : Ekos::FOCUS_FAILED, Ekos::FOCUS_FAIL_ABORT);
1400void Focus::meridianFlipStarted()
1403 if (state() == FOCUS_IDLE || state() == FOCUS_COMPLETE || state() == FOCUS_FAILED || state() == FOCUS_ABORTED)
1407 int old = resetFocusIteration;
1411 resetFocusIteration = old;
1417 if (state() <= FOCUS_ABORTED)
1421 if (focusAdvisor->inFocusAdvisor())
1423 focusAdvisor->stop();
1429void Focus::processAbort()
1431 bool focusLoop = inFocusLoop;
1432 checkStopFocus(
true);
1433 appendLogText(
i18n(
"Autofocus aborted."));
1440void Focus::stop(Ekos::FocusState completionState)
1442 qCDebug(KSTARS_EKOS_FOCUS) <<
"Stopping Focus";
1444 captureTimeout.stop();
1445 m_FocusMotionTimer.stop();
1446 m_FocusMotionTimerCounter = 0;
1447 m_FocuserReconnectCounter = 0;
1449 opticalTrainCombo->setEnabled(
true);
1450 resetDonutProcessing();
1451 inAutoFocus =
false;
1452 inAdjustFocus =
false;
1453 adaptFocus->setInAdaptiveFocus(
false);
1454 inBuildOffsets =
false;
1455 inScanStartPos =
false;
1456 focusAdvisor->reset();
1457 m_AutofocusReason = AutofocusReason::FOCUS_NONE;
1458 m_AutofocusReasonInfo =
"";
1459 focuserAdditionalMovement = 0;
1460 focuserAdditionalMovementUpdateDir =
true;
1461 inFocusLoop =
false;
1462 m_captureInProgress =
false;
1463 m_abortInProgress =
false;
1464 m_starDetectInProgress =
false;
1465 isVShapeSolution =
false;
1466 captureFailureCounter = 0;
1467 minimumRequiredHFR = INVALID_STAR_MEASURE;
1469 starMeasureFrames.clear();
1478 disconnect(m_Camera, &ISD::Camera::error,
this, &Ekos::Focus::processCaptureError);
1480 if (rememberUploadMode != m_Camera->getUploadMode())
1481 m_Camera->setUploadMode(rememberUploadMode);
1484 if (m_RememberCameraFastExposure)
1486 m_RememberCameraFastExposure =
false;
1487 m_Camera->setFastExposureEnabled(
true);
1490 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
1491 targetChip->abortExposure();
1500 if (m_GuidingSuspended)
1502 emit resumeGuiding();
1503 m_GuidingSuspended =
false;
1506 if (completionState == Ekos::FOCUS_ABORTED || completionState == Ekos::FOCUS_FAILED)
1507 setState(completionState);
1510void Focus::capture(
double settleTime)
1512 if (m_abortInProgress)
1515 m_captureInProgress =
false;
1516 qCDebug(KSTARS_EKOS_FOCUS) <<
"Abort AF: discarding capture request.";
1522 if (settleTime > 0 && m_captureInProgress ==
false)
1524 captureTimer.start(
static_cast<int>(settleTime * 1000));
1528 if (m_captureInProgress)
1530 qCWarning(KSTARS_EKOS_FOCUS) <<
"Capture called while already in progress. Capture is ignored.";
1534 if (m_Camera ==
nullptr)
1536 appendLogText(
i18n(
"Error: No Camera detected."));
1537 checkStopFocus(
true);
1541 if (m_Camera->isConnected() ==
false)
1543 appendLogText(
i18n(
"Error: Lost connection to Camera."));
1544 checkStopFocus(
true);
1549 captureTimeout.stop();
1551 waitStarSelectTimer.stop();
1553 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
1555 if (m_Camera->isBLOBEnabled() ==
false)
1557 m_Camera->setBLOBEnabled(
true);
1560 if (focusFilter->currentIndex() != -1)
1562 if (m_FilterWheel ==
nullptr)
1564 appendLogText(
i18n(
"Error: No Filter Wheel detected."));
1565 checkStopFocus(
true);
1568 if (m_FilterWheel->isConnected() ==
false)
1570 appendLogText(
i18n(
"Error: Lost connection to Filter Wheel."));
1571 checkStopFocus(
true);
1578 int targetPosition = focusFilter->currentIndex() + 1;
1579 if (!inBuildOffsets)
1581 QString lockedFilter = m_FilterManager->getFilterLock(filter());
1586 if (lockedFilter !=
"--" && lockedFilter != filter())
1588 int lockedFilterIndex = focusFilter->findText(lockedFilter);
1589 if (lockedFilterIndex >= 0)
1592 fallbackFilterPending =
true;
1593 fallbackFilterPosition = targetPosition;
1594 targetPosition = lockedFilterIndex + 1;
1599 filterPositionPending = (targetPosition != currentFilterPosition);
1600 if (filterPositionPending)
1605 FilterManager::FilterPolicy policy = (inAutoFocus) ?
1606 static_cast<FilterManager::FilterPolicy
>(FilterManager::CHANGE_POLICY) :
1607 static_cast<FilterManager::FilterPolicy
>(FilterManager::CHANGE_POLICY | FilterManager::OFFSET_POLICY);
1608 m_FilterManager->setFilterPosition(targetPosition, policy);
1611 else if (targetPosition != focusFilter->currentIndex() + 1)
1612 focusFilter->setCurrentIndex(targetPosition - 1);
1615 m_FocusView->setProperty(
"suspended", m_OpsFocusSettings->useFocusDarkFrame->isChecked());
1616 prepareCapture(targetChip);
1619 connect(m_Camera, &ISD::Camera::error,
this, &Ekos::Focus::processCaptureError,
Qt::UniqueConnection);
1621 if (frameSettings.contains(targetChip))
1623 QVariantMap settings = frameSettings[targetChip];
1624 targetChip->setFrame(settings[
"x"].toInt(), settings[
"y"].toInt(), settings[
"w"].toInt(),
1625 settings[
"h"].toInt());
1626 settings[
"binx"] = (focusBinning->currentIndex() + 1);
1627 settings[
"biny"] = (focusBinning->currentIndex() + 1);
1628 frameSettings[targetChip] = settings;
1631 m_captureInProgress =
true;
1632 if (state() != FOCUS_PROGRESS)
1633 setState(FOCUS_PROGRESS);
1635 m_FocusView->setBaseSize(focusingWidget->size());
1637 if (targetChip->capture(focusExposure->value()))
1641 captureTimeout.start( (focusExposure->value() + m_OpsFocusMechanics->focusCaptureTimeout->value()) * 1000);
1643 if (inFocusLoop ==
false)
1644 appendLogText(
i18n(
"Capturing image..."));
1648 else if (inAutoFocus)
1650 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_CAPTURE_FAILED);
1656 if (m_Camera->getUploadMode() == ISD::Camera::UPLOAD_LOCAL)
1658 rememberUploadMode = ISD::Camera::UPLOAD_LOCAL;
1659 m_Camera->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
1663 if (m_Camera->isFastExposureEnabled())
1665 m_RememberCameraFastExposure =
true;
1666 m_Camera->setFastExposureEnabled(
false);
1669 m_Camera->setEncodingFormat(
"FITS");
1670 targetChip->setBatchMode(
false);
1671 targetChip->setBinning((focusBinning->currentIndex() + 1), (focusBinning->currentIndex() + 1));
1672 targetChip->setCaptureMode(FITS_FOCUS);
1673 targetChip->setFrameType(FRAME_LIGHT);
1674 targetChip->setCaptureFilter(FITS_NONE);
1676 if (isFocusISOEnabled() && focusISO->currentIndex() != -1 &&
1677 targetChip->getISOIndex() != focusISO->currentIndex())
1678 targetChip->setISOIndex(focusISO->currentIndex());
1680 if (isFocusGainEnabled() && focusGain->value() != GainSpinSpecialValue)
1681 m_Camera->setGain(focusGain->value());
1684bool Focus::focusIn(
int ms)
1686 if (currentPosition == absMotionMin)
1688 appendLogText(
i18n(
"At minimum focus position %1...", absMotionMin));
1691 focusInB->setEnabled(
false);
1692 focusOutB->setEnabled(
false);
1693 startGotoB->setEnabled(
false);
1695 ms = m_OpsFocusMechanics->focusTicks->value();
1696 if (currentPosition - ms <= absMotionMin)
1698 ms = currentPosition - absMotionMin;
1699 appendLogText(
i18n(
"Moving to minimum focus position %1...", absMotionMin));
1701 return changeFocus(-ms);
1704bool Focus::focusOut(
int ms)
1706 if (currentPosition == absMotionMax)
1708 appendLogText(
i18n(
"At maximum focus position %1...", absMotionMax));
1711 focusInB->setEnabled(
false);
1712 focusOutB->setEnabled(
false);
1713 startGotoB->setEnabled(
false);
1715 ms = m_OpsFocusMechanics->focusTicks->value();
1716 if (currentPosition + ms >= absMotionMax)
1718 ms = absMotionMax - currentPosition;
1719 appendLogText(
i18n(
"Moving to maximum focus position %1...", absMotionMax));
1721 return changeFocus(ms);
1726bool Focus::changeFocus(
int amount,
bool updateDir)
1730 if (inAutoFocus && abs(amount) <= 1)
1732 if (m_RestartState == RESTART_NOW)
1739 capture(m_OpsFocusMechanics->focusSettleTime->value());
1744 if (m_Focuser ==
nullptr)
1746 appendLogText(
i18n(
"Error: No Focuser detected."));
1747 checkStopFocus(
true);
1751 if (m_Focuser->isConnected() ==
false)
1753 appendLogText(
i18n(
"Error: Lost connection to Focuser."));
1754 checkStopFocus(
true);
1758 const int newPosition = adjustLinearPosition(currentPosition, currentPosition + amount,
1759 m_OpsFocusMechanics->focusAFOverscan->value(),
1761 if (newPosition == currentPosition)
1764 const int newAmount = newPosition - currentPosition;
1765 const int absNewAmount = abs(newAmount);
1766 const bool focusingOut = newAmount > 0;
1767 const QString dirStr = focusingOut ?
i18n(
"outward") :
i18n(
"inward");
1770 m_LastFocusDirection = (focusingOut) ? FOCUS_OUT : FOCUS_IN;
1773 m_Focuser->focusOut();
1775 m_Focuser->focusIn();
1778 m_FocusMotionTimer.start();
1782 m_LastFocusSteps = newPosition;
1783 m_Focuser->moveAbs(newPosition);
1784 appendLogText(
i18n(
"Focusing %2 by %1 steps...", abs(absNewAmount), dirStr));
1786 else if (canRelMove)
1788 m_LastFocusSteps = absNewAmount;
1789 m_Focuser->moveRel(absNewAmount);
1790 appendLogText(
i18np(
"Focusing %2 by %1 step...",
"Focusing %2 by %1 steps...", absNewAmount, dirStr));
1794 m_LastFocusSteps = absNewAmount;
1795 m_Focuser->moveByTimer(absNewAmount);
1796 appendLogText(
i18n(
"Focusing %2 by %1 ms...", absNewAmount, dirStr));
1802void Focus::handleFocusMotionTimeout()
1822 qCDebug(KSTARS_EKOS_FOCUS) <<
"handleFocusMotionTimeout() called while not in AutoFocus";
1826 m_FocusMotionTimerCounter++;
1828 if (m_FocusMotionTimerCounter > 4)
1831 appendLogText(
i18n(
"Focuser is still timing out. Aborting..."));
1832 stop(Ekos::FOCUS_ABORTED);
1835 else if (m_FocusMotionTimerCounter > 2)
1837 QString focuser = m_Focuser->getDeviceName();
1838 appendLogText(
i18n(
"Focus motion timed out (%1). Restarting focus driver %2", m_FocusMotionTimerCounter, focuser));
1839 emit focuserTimedout(focuser);
1843 Focus::reconnectFocuser(focuser);
1848 if (!changeFocus(m_LastFocusSteps - currentPosition))
1849 appendLogText(
i18n(
"Focus motion timed out (%1). Focusing to %2 steps...", m_FocusMotionTimerCounter, m_LastFocusSteps));
1852void Focus::selectImageMask()
1854 const bool useFullField = m_OpsFocusSettings->focusUseFullField->isChecked();
1855 ImageMaskType masktype;
1856 if (m_OpsFocusSettings->focusRingMaskRB->isChecked())
1857 masktype = FOCUS_MASK_RING;
1858 else if (m_OpsFocusSettings->focusMosaicMaskRB->isChecked())
1859 masktype = FOCUS_MASK_MOSAIC;
1861 masktype = FOCUS_MASK_NONE;
1864 m_OpsFocusSettings->focusRingMaskRB->setEnabled(useFullField);
1865 m_OpsFocusSettings->focusMosaicMaskRB->setEnabled(useFullField);
1867 m_OpsFocusSettings->focusFullFieldInnerRadius->setEnabled(useFullField && masktype == FOCUS_MASK_RING);
1868 m_OpsFocusSettings->focusFullFieldOuterRadius->setEnabled(useFullField && masktype == FOCUS_MASK_RING);
1870 m_OpsFocusSettings->focusMosaicTileWidth->setEnabled(useFullField && masktype == FOCUS_MASK_MOSAIC);
1871 m_OpsFocusSettings->focusSpacerLabel->setEnabled(useFullField && masktype == FOCUS_MASK_MOSAIC);
1872 m_OpsFocusSettings->focusMosaicSpace->setEnabled(useFullField && masktype == FOCUS_MASK_MOSAIC);
1875 if (masktype == FOCUS_MASK_RING)
1876 m_FocusView->setImageMask(
new ImageRingMask(m_OpsFocusSettings->focusFullFieldInnerRadius->value() / 100.0,
1877 m_OpsFocusSettings->focusFullFieldOuterRadius->value() / 100.0));
1878 else if (masktype == FOCUS_MASK_MOSAIC)
1879 m_FocusView->setImageMask(
new ImageMosaicMask(m_OpsFocusSettings->focusMosaicTileWidth->value(),
1880 m_OpsFocusSettings->focusMosaicSpace->value()));
1882 m_FocusView->setImageMask(
nullptr);
1884 checkMosaicMaskLimits();
1885 m_currentImageMask = masktype;
1886 startAbInsB->setEnabled(canAbInsStart());
1889void Focus::reconnectFocuser(
const QString &focuser)
1891 m_FocuserReconnectCounter++;
1893 if (m_Focuser && m_Focuser->getDeviceName() == focuser)
1895 appendLogText(
i18n(
"Attempting to reconnect focuser: %1", focuser));
1896 refreshOpticalTrain();
1897 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FOCUSER_ERROR);
1901 if (m_FocuserReconnectCounter > 12)
1904 appendLogText(
i18n(
"Cannot reconnect focuser: %1. Aborting...", focuser));
1905 stop(Ekos::FOCUS_ABORTED);
1911 reconnectFocuser(focuser);
1918 if (data->property(
"chip").toInt() == ISD::CameraChip::GUIDE_CCD)
1923 m_FocusView->loadData(data);
1927 m_ImageData.
reset();
1929 captureTimeout.stop();
1930 captureTimeoutCounter = 0;
1931 m_MissingCameraCounter = 0;
1933 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
1935 disconnect(m_Camera, &ISD::Camera::error,
this, &Ekos::Focus::processCaptureError);
1937 if (m_ImageData && m_OpsFocusSettings->useFocusDarkFrame->isChecked())
1939 QVariantMap settings = frameSettings[targetChip];
1940 uint16_t offsetX = settings[
"x"].toInt() / settings[
"binx"].toInt();
1941 uint16_t offsetY = settings[
"y"].toInt() / settings[
"biny"].toInt();
1943 m_DarkProcessor->denoise(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()),
1944 targetChip, m_ImageData, focusExposure->value(), offsetX, offsetY);
1948 setCaptureComplete();
1952void Focus::starDetectionFinished()
1954 m_starDetectInProgress =
false;
1955 if (m_abortInProgress)
1958 qCDebug(KSTARS_EKOS_FOCUS) <<
"Abort AF: discarding results from " << __FUNCTION__;
1962 appendLogText(
i18n(
"Detection complete."));
1965 double hfr = INVALID_STAR_MEASURE;
1967 if (m_StarFinderWatcher.result() ==
false)
1969 qCWarning(KSTARS_EKOS_FOCUS) <<
"Failed to extract any stars.";
1973 if (m_OpsFocusSettings->focusUseFullField->isChecked())
1975 m_FocusView->filterStars();
1978 hfr = m_ImageData->getHFR(m_StarMeasure == FOCUS_STAR_HFR_ADJ ? HFR_ADJ_AVERAGE : HFR_AVERAGE);
1982 m_FocusView->setTrackingBoxEnabled(
true);
1987 if (starCenter.isNull() ==
false)
1988 hfr = m_ImageData->getHFR(starCenter.x(), starCenter.y());
1992 hfr = m_ImageData->getHFR(m_FocusDetection == ALGORITHM_SEP ? HFR_HIGH : HFR_MAX);
1997 currentNumStars = m_ImageData->getDetectedStars();
2001 currentMeasure = currentHFR;
2004 if (m_StarMeasure == FOCUS_STAR_NUM_STARS)
2006 currentMeasure = currentNumStars;
2007 currentWeight = 1.0;
2009 else if (m_StarMeasure == FOCUS_STAR_FWHM)
2011 getFWHM(m_ImageData->getStarCenters(), ¤tFWHM, ¤tWeight);
2012 currentMeasure = currentFWHM;
2014 else if (m_StarMeasure == FOCUS_STAR_FOURIER_POWER)
2016 getFourierPower(¤tFourierPower, ¤tWeight);
2017 currentMeasure = currentFourierPower;
2021 currentMeasure = currentHFR;
2023 std::vector<double> hfrs(stars.
size());
2028 currentWeight = calculateStarWeight(m_OpsFocusProcess->focusUseWeights->isChecked(), hfrs);
2031 setCurrentMeasure();
2035void Focus::getFWHM(
const QList<Edge *> &stars,
double *FWHM,
double *weight)
2037 *FWHM = INVALID_STAR_MEASURE;
2040 auto imageBuffer = m_ImageData->getImageBuffer();
2042 switch (m_ImageData->getStatistics().dataType)
2045 focusFWHM->processFWHM(
reinterpret_cast<uint8_t
const *
>(imageBuffer), stars, m_ImageData, starFitting, FWHM, weight);
2049 focusFWHM->processFWHM(
reinterpret_cast<short const *
>(imageBuffer), stars, m_ImageData, starFitting, FWHM, weight);
2053 focusFWHM->processFWHM(
reinterpret_cast<unsigned short const *
>(imageBuffer), stars, m_ImageData, starFitting, FWHM,
2058 focusFWHM->processFWHM(
reinterpret_cast<long const *
>(imageBuffer), stars, m_ImageData, starFitting, FWHM, weight);
2062 focusFWHM->processFWHM(
reinterpret_cast<unsigned long const *
>(imageBuffer), stars, m_ImageData, starFitting, FWHM, weight);
2066 focusFWHM->processFWHM(
reinterpret_cast<float const *
>(imageBuffer), stars, m_ImageData, starFitting, FWHM, weight);
2070 focusFWHM->processFWHM(
reinterpret_cast<long long const *
>(imageBuffer), stars, m_ImageData, starFitting, FWHM, weight);
2074 focusFWHM->processFWHM(
reinterpret_cast<double const *
>(imageBuffer), stars, m_ImageData, starFitting, FWHM, weight);
2078 qCDebug(KSTARS_EKOS_FOCUS) <<
"Unknown image buffer datatype " << m_ImageData->getStatistics().dataType <<
2079 " Cannot calc FWHM";
2085void Focus::getFourierPower(
double *fourierPower,
double *weight,
const int mosaicTile)
2087 *fourierPower = INVALID_STAR_MEASURE;
2090 auto imageBuffer = m_ImageData->getImageBuffer();
2092 switch (m_ImageData->getStatistics().dataType)
2095 focusFourierPower->processFourierPower(
reinterpret_cast<uint8_t
const *
>(imageBuffer), m_ImageData,
2096 m_FocusView->imageMask(), mosaicTile, fourierPower, weight);
2100 focusFourierPower->processFourierPower(
reinterpret_cast<short const *
>(imageBuffer), m_ImageData,
2101 m_FocusView->imageMask(), mosaicTile, fourierPower, weight);
2105 focusFourierPower->processFourierPower(
reinterpret_cast<unsigned short const *
>(imageBuffer), m_ImageData,
2106 m_FocusView->imageMask(), mosaicTile, fourierPower, weight);
2110 focusFourierPower->processFourierPower(
reinterpret_cast<long const *
>(imageBuffer), m_ImageData,
2111 m_FocusView->imageMask(), mosaicTile, fourierPower, weight);
2115 focusFourierPower->processFourierPower(
reinterpret_cast<unsigned long const *
>(imageBuffer), m_ImageData,
2116 m_FocusView->imageMask(), mosaicTile, fourierPower, weight);
2120 focusFourierPower->processFourierPower(
reinterpret_cast<float const *
>(imageBuffer), m_ImageData,
2121 m_FocusView->imageMask(), mosaicTile, fourierPower, weight);
2125 focusFourierPower->processFourierPower(
reinterpret_cast<long long const *
>(imageBuffer), m_ImageData,
2126 m_FocusView->imageMask(), mosaicTile, fourierPower, weight);
2130 focusFourierPower->processFourierPower(
reinterpret_cast<double const *
>(imageBuffer), m_ImageData,
2131 m_FocusView->imageMask(), mosaicTile, fourierPower, weight);
2135 qCDebug(KSTARS_EKOS_FOCUS) <<
"Unknown image buffer datatype " << m_ImageData->getStatistics().dataType <<
2136 " Cannot calc Fourier Power";
2141double Focus::calculateStarWeight(
const bool useWeights,
const std::vector<double> values)
2143 if (!useWeights || values.size() <= 0)
2148 return Mathematics::RobustStatistics::ComputeWeight(m_ScaleCalc, values);
2151void Focus::analyzeSources()
2153 appendLogText(
i18n(
"Detecting sources..."));
2154 m_starDetectInProgress =
true;
2156 QVariantMap extractionSettings;
2157 extractionSettings[
"optionsProfileIndex"] = m_OpsFocusProcess->focusSEPProfile->currentIndex();
2158 extractionSettings[
"optionsProfileGroup"] =
static_cast<int>(Ekos::FocusProfiles);
2159 m_ImageData->setSourceExtractorSettings(extractionSettings);
2163 if (m_OpsFocusSettings->focusUseFullField->isChecked())
2165 m_FocusView->setTrackingBoxEnabled(
false);
2167 if (m_FocusDetection != ALGORITHM_CENTROID && m_FocusDetection != ALGORITHM_SEP)
2168 m_StarFinderWatcher.setFuture(m_ImageData->findStars(ALGORITHM_CENTROID));
2170 m_StarFinderWatcher.setFuture(m_ImageData->findStars(m_FocusDetection));
2174 QRect searchBox = m_FocusView->isTrackingBoxEnabled() ? m_FocusView->getTrackingBox() :
QRect();
2178 m_StarFinderWatcher.setFuture(m_ImageData->findStars(m_FocusDetection, searchBox));
2183 m_FocusView->setTrackingBoxEnabled(
false);
2187 if (m_FocusDetection != ALGORITHM_CENTROID && m_FocusDetection != ALGORITHM_SEP)
2188 m_StarFinderWatcher.setFuture(m_ImageData->findStars(ALGORITHM_CENTROID));
2191 m_StarFinderWatcher.setFuture(m_ImageData->findStars(m_FocusDetection, searchBox));
2196bool Focus::appendMeasure(
double newMeasure)
2199 starMeasureFrames.append(newMeasure);
2202 QVector <double> samples(starMeasureFrames);
2203 samples.erase(std::remove_if(samples.begin(), samples.end(), [](
const double measure)
2205 return measure == INVALID_STAR_MEASURE;
2209 if (!samples.isEmpty())
2211 currentMeasure = Mathematics::RobustStatistics::ComputeLocation(
2212 Mathematics::RobustStatistics::LOCATION_SIGMACLIPPING, std::vector<double>(samples.begin(), samples.end()));
2214 switch(m_StarMeasure)
2216 case FOCUS_STAR_HFR:
2217 case FOCUS_STAR_HFR_ADJ:
2218 currentHFR = currentMeasure;
2220 case FOCUS_STAR_FWHM:
2221 currentFWHM = currentMeasure;
2223 case FOCUS_STAR_NUM_STARS:
2224 currentNumStars = currentMeasure;
2226 case FOCUS_STAR_FOURIER_POWER:
2227 currentFourierPower = currentMeasure;
2238 int framesCount = m_OpsFocusProcess->focusFramesCount->value();
2239 if ((minimumRequiredHFR > 0) || (inAutoFocus && !inBuildOffsets && !inScanStartPos && !focusAdvisor->inFocusAdvisor()
2240 && m_FocusAlgorithm == FOCUS_LINEAR1PASS
2241 && linearFocuser && !linearFocuser->isInFirstPass()))
2243 framesCount = m_OpsFocusProcess->focusHFRFramesCount->value();
2245 return starMeasureFrames.count() < framesCount;
2248void Focus::settle(
const FocusState completionState,
const bool autoFocusUsed,
const bool buildOffsetsUsed,
2249 const AutofocusFailReason failCode,
const QString failCodeInfo)
2252 m_state = completionState;
2255 if (completionState == Ekos::FOCUS_COMPLETE)
2257 KSNotification::event(
QLatin1String(
"FocusSuccessful"),
i18n(
"Autofocus operation completed successfully"),
2258 KSNotification::Focus);
2260 if (m_FocusAlgorithm == FOCUS_LINEAR1PASS && curveFitting !=
nullptr)
2261 emit autofocusComplete(m_LastSourceAutofocusTemperature,
filter(), getAnalyzeData(),
2262 m_OpsFocusProcess->focusUseWeights->isChecked(),
2263 curveFitting->serialize(), linearFocuser->getTextStatus(R2));
2265 emit autofocusComplete(m_LastSourceAutofocusTemperature,
filter(), getAnalyzeData(),
2266 m_OpsFocusProcess->focusUseWeights->isChecked());
2270 KSNotification::event(
QLatin1String(
"FocusFailed"),
i18n(
"Autofocus operation failed"),
2271 KSNotification::Focus, KSNotification::Alert);
2272 emit autofocusAborted(
filter(), getAnalyzeData(), m_OpsFocusProcess->focusUseWeights->isChecked(), failCode, failCodeInfo);
2276 if (completionState == Ekos::FOCUS_COMPLETE)
2278 if (autoFocusUsed && fallbackFilterPending)
2283 m_FilterManager->setFilterAbsoluteFocusDetails(focusFilter->currentIndex(), currentPosition,
2284 m_LastSourceAutofocusTemperature, m_LastSourceAutofocusAlt);
2288 qCDebug(KSTARS_EKOS_FOCUS) <<
"Settled. State:" << Ekos::getFocusStatusString(state());
2291 if (fallbackFilterPending)
2293 FilterManager::FilterPolicy policy = (autoFocusUsed) ?
2294 static_cast<FilterManager::FilterPolicy
>(FilterManager::CHANGE_POLICY) :
2295 static_cast<FilterManager::FilterPolicy
>(FilterManager::CHANGE_POLICY | FilterManager::OFFSET_POLICY);
2296 m_FilterManager->setFilterPosition(fallbackFilterPosition, policy);
2299 emit newStatus(state());
2301 if (autoFocusUsed && buildOffsetsUsed)
2303 m_FilterManager->autoFocusComplete(state(), currentPosition, m_LastSourceAutofocusTemperature, m_LastSourceAutofocusAlt);
2308QString Focus::getAnalyzeData()
2310 QString analysis_results =
"";
2312 for (
int i = 0; i < plot_position.size(); ++i)
2315 .arg(i == 0 ?
"" :
"|" )
2321 return analysis_results;
2324void Focus::completeFocusProcedure(FocusState completionState, AutofocusFailReason failCode,
QString failCodeInfo,
2328 if (inAutoFocus && failCode != Ekos::FOCUS_FAIL_ADVISOR_COMPLETE)
2331 updatePlotPosition();
2333 if (completionState == Ekos::FOCUS_COMPLETE)
2337 emit redrawHFRPlot(polynomialFit.get(), currentPosition, currentHFR);
2339 appendLogText(
i18np(
"Focus procedure completed after %1 iteration.",
2340 "Focus procedure completed after %1 iterations.", plot_position.count()));
2342 setLastFocusTemperature();
2344 resetAdaptiveFocus(m_OpsFocusSettings->focusAdaptive->isChecked());
2348 qCInfo(KSTARS_EKOS_FOCUS) <<
"Autofocus values: position," << currentPosition <<
", temperature,"
2349 << m_LastSourceAutofocusTemperature <<
", filter," <<
filter()
2350 <<
", HFR," << currentHFR <<
", altitude," << m_LastSourceAutofocusAlt;
2352 if (m_FocusAlgorithm == FOCUS_POLYNOMIAL)
2355 plot_position.append(currentPosition);
2356 plot_value.append(currentHFR);
2357 plot_weight.append(1.0);
2358 plot_outlier.append(
false);
2361 appendFocusLogText(
QString(
"%1, %2, %3, %4, %5\n")
2368 absTicksSpin->setValue(currentPosition);
2371 else if (canAbsMove && initialFocuserAbsPosition >= 0 && resetFocusIteration <= MAXIMUM_RESET_ITERATIONS &&
2372 m_RestartState != RESTART_ABORT)
2375 bool const retry_focusing = m_RestartState == RESTART_NONE &&
2376 (failCode == Ekos::FOCUS_FAIL_ADVISOR_RERUN || ++resetFocusIteration < MAXIMUM_RESET_ITERATIONS);
2381 m_RestartState = RESTART_NOW;
2390 emit autofocusAborted(
filter(), getAnalyzeData(), m_OpsFocusProcess->focusUseWeights->isChecked(), failCode, failCodeInfo);
2402 m_RestartState = RESTART_ABORT;
2408 resetFocusIteration = 0;
2411 const bool autoFocusUsed = inAutoFocus;
2412 const bool inBuildOffsetsUsed = inBuildOffsets;
2415 if (m_FocusAlgorithm == FOCUS_POLYNOMIAL && plot)
2416 emit drawPolynomial(polynomialFit.get(), isVShapeSolution,
true);
2419 int const settleTime = m_GuidingSuspended ? m_OpsFocusSettings->focusGuideSettleTime->value() : 0;
2422 stop(completionState);
2425 appendLogText(
i18n(
"Settling for %1s...", settleTime));
2427 QTimer::singleShot(settleTime * 1000,
this, [ &, settleTime, completionState, autoFocusUsed, inBuildOffsetsUsed, failCode,
2430 settle(completionState, autoFocusUsed, inBuildOffsetsUsed, failCode, failCodeInfo);
2433 appendLogText(
i18n(
"Settling complete."));
2437void Focus::resetFocuser()
2440 if (m_Focuser && m_Focuser->isConnected() && initialFocuserAbsPosition >= 0)
2443 if (currentPosition == initialFocuserAbsPosition)
2446 appendLogText(
i18n(
"Autofocus failed, moving back to initial focus position %1.", initialFocuserAbsPosition));
2447 changeFocus(initialFocuserAbsPosition - currentPosition);
2452void Focus::setCurrentMeasure()
2455 qCDebug(KSTARS_EKOS_FOCUS) <<
"Focus newFITS #" << starMeasureFrames.count() + 1 <<
": Current HFR " << currentHFR <<
2457 << (starSelected ? 1 : currentNumStars);
2460 if (appendMeasure(currentMeasure))
2465 else starMeasureFrames.clear();
2470 emit newHFR(currentHFR, currentPosition, inAutoFocus);
2472 emit newHFR(currentHFR, -1, inAutoFocus);
2475 HFROut->setText(
QString(
"%1").arg(currentHFR * getStarUnits(m_StarMeasure, m_StarUnits), 0,
'f', 2));
2476 if (m_StarMeasure == FOCUS_STAR_FWHM)
2477 FWHMOut->setText(
QString(
"%1").arg(currentFWHM * getStarUnits(m_StarMeasure, m_StarUnits), 0,
'f', 2));
2478 starsOut->setText(
QString(
"%1").arg(m_ImageData->getDetectedStars()));
2479 iterOut->setText(
QString(
"%1").arg(absIterations + 1));
2482 if (lastHFR == INVALID_STAR_MEASURE)
2483 appendLogText(
i18n(
"FITS received. No stars detected."));
2489 if (m_FocusAlgorithm == FOCUS_POLYNOMIAL && isVShapeSolution)
2491 completeFocusProcedure(Ekos::FOCUS_COMPLETE, Ekos::FOCUS_FAIL_NONE);
2495 Edge selectedHFRStarHFR = m_ImageData->getSelectedHFRStar();
2502 if (starCenter.isNull() ==
false && (inAutoFocus || minimumRequiredHFR >= 0))
2505 starSelected =
true;
2506 starCenter.setX(qMax(0,
static_cast<int>(selectedHFRStarHFR.x)));
2507 starCenter.setY(qMax(0,
static_cast<int>(selectedHFRStarHFR.y)));
2509 syncTrackingBoxPosition();
2513 oneStar.
setZ(currentHFR);
2514 starsHFR.append(oneStar);
2519 QVector3D oneStar(starCenter.x(), starCenter.y(), currentHFR);
2520 starsHFR.append(oneStar);
2523 if (currentHFR > maxHFR)
2524 maxHFR = currentHFR;
2532 if (inFocusLoop || (inAutoFocus && ! isPositionBased()))
2534 int pos = plot_position.empty() ? 1 : plot_position.last() + 1;
2535 addPlotPosition(pos, currentHFR);
2541 QVector3D oneStar(starCenter.x(), starCenter.y(), INVALID_STAR_MEASURE);
2542 starsHFR.append(oneStar);
2547 m_FocusView->updateFrame();
2551 if (m_abInsOn && !inScanStartPos && !focusAdvisor->inFocusAdvisor())
2552 calculateAbInsData();
2556void Focus::saveFocusFrame()
2558 if (inAutoFocus && Options::focusLogging() && Options::saveFocusImages())
2569 if (focusAdvisor->inFocusAdvisor())
2570 prefix = focusAdvisor->getFocusFramePrefix();
2571 else if (inScanStartPos)
2572 prefix =
QString(
"_ssp_%1_%2").
arg(m_AFRun).
arg(absIterations + 1);
2573 else if (m_FocusAlgorithm == FOCUS_LINEAR1PASS && linearFocuser)
2575 const int currentStep = linearFocuser->currentStep() + 1;
2581 prefix.
append(
QString(
"_%1").arg(starMeasureFrames.count()));
2587 m_ImageData->saveImage(filename);
2591void Focus::calculateAbInsData()
2593 ImageMosaicMask *mosaicmask =
dynamic_cast<ImageMosaicMask *
>(m_FocusView->imageMask().get());
2595 auto stars = m_ImageData->getStarCenters();
2598 for (
int star = 0; star < stars.
count(); star++)
2600 const int x = stars[star]->x;
2601 const int y = stars[star]->y;
2602 for (
int tile = 0; tile < NUM_TILES; tile++)
2604 QRect thisTile = tiles[tile];
2607 tileStars[tile].
append(stars[star]);
2614 for (
int tile = 0; tile < tileStars.count(); tile++)
2616 double measure, weight;
2618 if (m_StarMeasure == FOCUS_STAR_NUM_STARS)
2620 measure = tileStars[tile].count();
2623 else if (m_StarMeasure == FOCUS_STAR_FWHM)
2625 getFWHM(tileStars[tile], &measure, &weight);
2627 else if (m_StarMeasure == FOCUS_STAR_FOURIER_POWER)
2629 getFourierPower(&measure, &weight, tile);
2634 std::vector<double> HFRs;
2636 for (
int star = 0; star < tileStars[tile].count(); star++)
2638 HFRs.push_back(tileStars[tile][star]->HFR);
2640 measure = Mathematics::RobustStatistics::ComputeLocation(Mathematics::RobustStatistics::LOCATION_SIGMACLIPPING, HFRs, 2);
2641 weight = calculateStarWeight(m_OpsFocusProcess->focusUseWeights->isChecked(), HFRs);
2644 m_abInsMeasure[tile].append(measure);
2645 m_abInsWeight[tile].append(weight);
2646 m_abInsNumStars[tile].append(tileStars[tile].count());
2648 if (!linearFocuser->isInFirstPass())
2653 int xAv = 0, yAv = 0;
2654 if (m_StarMeasure != FOCUS_STAR_FOURIER_POWER)
2656 QPoint tileCenter = tiles[tile].center();
2657 int xSum = 0.0, ySum = 0.0;
2658 for (
int star = 0; star < tileStars[tile].count(); star++)
2660 xSum += tileStars[tile][star]->x - tileCenter.
x();
2661 ySum += tileStars[tile][star]->y - tileCenter.
y();
2664 xAv = (tileStars[tile].count() <= 0) ? 0 : xSum / tileStars[tile].count();
2665 yAv = (tileStars[tile].count() <= 0) ? 0 : ySum / tileStars[tile].count();
2667 m_abInsTileCenterOffset.append(
QPoint(xAv, yAv));
2670 m_abInsPosition.append(currentPosition);
2673void Focus::setCaptureComplete()
2675 DarkLibrary::Instance()->disconnect(
this);
2678 syncTrackingBoxPosition();
2681 if (inFocusLoop ==
false)
2682 appendLogText(
i18n(
"Image received."));
2684 if (m_captureInProgress && inFocusLoop ==
false && inAutoFocus ==
false)
2685 m_Camera->setUploadMode(rememberUploadMode);
2687 if (m_RememberCameraFastExposure && inFocusLoop ==
false && inAutoFocus ==
false)
2689 m_RememberCameraFastExposure =
false;
2690 m_Camera->setFastExposureEnabled(
true);
2693 m_captureInProgress =
false;
2694 if (m_abortInProgress)
2698 qCDebug(KSTARS_EKOS_FOCUS) <<
"Abort AF: discarding frame results in " << __FUNCTION__;
2703 checkMosaicMaskLimits();
2706 emit newImage(m_FocusView);
2708 emit newStarPixmap(m_FocusView->getTrackingBoxPixmap(10));
2714 if (inFocusLoop ==
false || (inFocusLoop && (m_FocusView->isTrackingBoxEnabled()
2715 || m_OpsFocusSettings->focusUseFullField->isChecked())))
2721void Focus::setHFRComplete()
2731 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
2734 int subBinX = 1, subBinY = 1;
2735 if (!targetChip->getBinning(&subBinX, &subBinY))
2736 qCDebug(KSTARS_EKOS_FOCUS) <<
"Warning: target chip is reporting no binning property, using 1x1.";
2743 if (m_OpsFocusSettings->focusUseFullField->isChecked() ==
false && starCenter.isNull())
2745 int x = 0, y = 0, w = 0, h = 0;
2748 if (frameSettings.contains(targetChip))
2750 QVariantMap settings = frameSettings[targetChip];
2751 x = settings[
"x"].toInt();
2752 y = settings[
"y"].toInt();
2753 w = settings[
"w"].toInt();
2754 h = settings[
"h"].toInt();
2758 targetChip->getFrame(&x, &y, &w, &h);
2761 if (m_OpsFocusSettings->focusAutoStarEnabled->isChecked())
2764 const Edge selectedHFRStar = m_ImageData->getSelectedHFRStar();
2766 if (selectedHFRStar.x == -1)
2768 appendLogText(
i18n(
"Failed to automatically select a star. Please select a star manually."));
2771 m_FocusView->setTrackingBox(
QRect(w - m_OpsFocusSettings->focusBoxSize->value() / (subBinX * 2),
2772 h - m_OpsFocusSettings->focusBoxSize->value() / (subBinY * 2),
2773 m_OpsFocusSettings->focusBoxSize->value() / subBinX, m_OpsFocusSettings->focusBoxSize->value() / subBinY));
2774 m_FocusView->setTrackingBoxEnabled(
true);
2777 setState(Ekos::FOCUS_WAITING);
2780 waitStarSelectTimer.start();
2786 starCenter.setX(selectedHFRStar.x);
2787 starCenter.setY(selectedHFRStar.y);
2788 starCenter.setZ(subBinX);
2789 starSelected =
true;
2790 syncTrackingBoxPosition();
2793 if (subFramed ==
false && isFocusSubFrameEnabled() && m_OpsFocusSettings->focusSubFrame->isChecked())
2795 int offset = (
static_cast<double>(m_OpsFocusSettings->focusBoxSize->value()) / subBinX) * 1.5;
2796 int subX = (selectedHFRStar.x - offset) * subBinX;
2797 int subY = (selectedHFRStar.y - offset) * subBinY;
2798 int subW = offset * 2 * subBinX;
2799 int subH = offset * 2 * subBinY;
2801 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
2802 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
2809 if ((subW + subX) > maxW)
2811 if ((subH + subY) > maxH)
2816 QVariantMap settings = frameSettings[targetChip];
2817 settings[
"x"] = subX;
2818 settings[
"y"] = subY;
2819 settings[
"w"] = subW;
2820 settings[
"h"] = subH;
2821 settings[
"binx"] = subBinX;
2822 settings[
"biny"] = subBinY;
2824 qCDebug(KSTARS_EKOS_FOCUS) <<
"Frame is subframed. X:" << subX <<
"Y:" << subY <<
"W:" << subW <<
"H:" << subH <<
"binX:" <<
2825 subBinX <<
"binY:" << subBinY;
2829 frameSettings[targetChip] = settings;
2832 starCenter.setX(subW / (2 * subBinX));
2833 starCenter.setY(subH / (2 * subBinY));
2834 starCenter.setZ(subBinX);
2838 m_FocusView->setFirstLoad(
true);
2847 starCenter.setX(selectedHFRStar.x);
2848 starCenter.setY(selectedHFRStar.y);
2849 starCenter.setZ(subBinX);
2862 appendLogText(
i18n(
"Capture complete. Select a star to focus."));
2864 starSelected =
false;
2868 int subBinX = 1, subBinY = 1;
2869 targetChip->getBinning(&subBinX, &subBinY);
2871 m_FocusView->setTrackingBox(
QRect((w - m_OpsFocusSettings->focusBoxSize->value()) / (subBinX * 2),
2872 (h - m_OpsFocusSettings->focusBoxSize->value()) / (2 * subBinY),
2873 m_OpsFocusSettings->focusBoxSize->value() / subBinX, m_OpsFocusSettings->focusBoxSize->value() / subBinY));
2874 m_FocusView->setTrackingBoxEnabled(
true);
2877 setState(Ekos::FOCUS_WAITING);
2880 waitStarSelectTimer.start();
2886 if (minimumRequiredHFR >= 0)
2889 if (currentHFR == INVALID_STAR_MEASURE)
2891 if (noStarCount++ < MAX_RECAPTURE_RETRIES)
2893 appendLogText(
i18n(
"No stars detected while testing HFR, capturing again..."));
2895 if (noStarCount == MAX_RECAPTURE_RETRIES)
2904 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_NO_STARS);
2909 else if (currentHFR > minimumRequiredHFR)
2911 qCDebug(KSTARS_EKOS_FOCUS) <<
"Current HFR:" << currentHFR <<
"is above required minimum HFR:" << minimumRequiredHFR <<
2912 ". Starting AutoFocus...";
2915 minimumRequiredHFR = INVALID_STAR_MEASURE;
2916 runAutoFocus(AutofocusReason::FOCUS_HFR_CHECK, reasonInfo);
2921 qCDebug(KSTARS_EKOS_FOCUS) <<
"Current HFR:" << currentHFR <<
"is below required minimum HFR:" << minimumRequiredHFR <<
2922 ". Autofocus successful.";
2923 completeFocusProcedure(Ekos::FOCUS_COMPLETE, Ekos::FOCUS_FAIL_NONE);
2931 if (inAutoFocus ==
false)
2935 if (state() != Ekos::FOCUS_IDLE)
2936 setState(Ekos::FOCUS_IDLE);
2943 if (state() != Ekos::FOCUS_PROGRESS)
2944 setState(Ekos::FOCUS_PROGRESS);
2949 else if(focusAdvisor->inFocusAdvisor())
2950 focusAdvisor->control();
2951 else if(m_FocusAlgorithm == FOCUS_LINEAR || m_FocusAlgorithm == FOCUS_LINEAR1PASS)
2953 else if (canAbsMove || canRelMove)
2961QString Focus::getyAxisLabel(StarMeasure starMeasure)
2964 m_StarUnits == FOCUS_UNITS_ARCSEC ? str +=
" (\")" : str +=
" (pix)";
2968 switch (starMeasure)
2970 case FOCUS_STAR_HFR:
2972 case FOCUS_STAR_HFR_ADJ:
2974 m_StarUnits == FOCUS_UNITS_ARCSEC ? str +=
" (\")" : str +=
" (pix)";
2976 case FOCUS_STAR_FWHM:
2978 m_StarUnits == FOCUS_UNITS_ARCSEC ? str +=
" (\")" : str +=
" (pix)";
2980 case FOCUS_STAR_NUM_STARS:
2983 case FOCUS_STAR_FOURIER_POWER:
2984 str =
"Fourier Power";
2993void Focus::clearDataPoints()
2996 polynomialFit.reset();
2997 plot_position.
clear();
2999 plot_weight.clear();
3000 plot_outlier.clear();
3001 isVShapeSolution =
false;
3002 m_abInsPosition.clear();
3003 m_abInsTileCenterOffset.clear();
3004 if (m_abInsMeasure.count() != NUM_TILES)
3006 m_abInsMeasure.resize(NUM_TILES);
3007 m_abInsWeight.resize(NUM_TILES);
3008 m_abInsNumStars.resize(NUM_TILES);
3012 for (
int i = 0; i < m_abInsMeasure.count(); i++)
3014 m_abInsMeasure[i].clear();
3015 m_abInsWeight[i].clear();
3016 m_abInsNumStars[i].clear();
3020 emit initHFRPlot(getyAxisLabel(m_StarMeasure), getStarUnits(m_StarMeasure, m_StarUnits),
3021 m_OptDir == CurveFitting::OPTIMISATION_MINIMISE, m_OpsFocusProcess->focusUseWeights->isChecked(),
3022 inFocusLoop ==
false && isPositionBased());
3025bool Focus::autoFocusChecks()
3027 if (++absIterations > MAXIMUM_ABS_ITERATIONS)
3029 appendLogText(
i18n(
"Autofocus failed: exceeded max iterations %1", MAXIMUM_ABS_ITERATIONS));
3030 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_MAX_ITERS);
3035 if (currentHFR == INVALID_STAR_MEASURE)
3037 if (noStarCount < MAX_RECAPTURE_RETRIES)
3040 appendLogText(
i18n(
"No stars detected, capturing again..."));
3044 else if (m_FocusAlgorithm == FOCUS_LINEAR)
3046 appendLogText(
i18n(
"Failed to detect any stars at position %1. Continuing...", currentPosition));
3049 else if(!m_OpsFocusProcess->focusDonut->isChecked())
3052 appendLogText(
i18n(
"Failed to detect any stars. Reset frame and try again."));
3053 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_NO_STARS);
3063void Focus::plotLinearFocus()
3072 linearFocuser->getMeasurements(&positions, &values, &weights);
3073 const FocusAlgorithmInterface::FocusParams ¶ms = linearFocuser->getParams();
3080 bool incrementalChange =
false;
3081 if (positions.
size() > 1 && positions.
size() == lastPositions.
size() + 1)
3084 for (
int i = 0; i < positions.
size() - 1; ++i)
3085 if (positions[i] != lastPositions[i] || values[i] != lastValues[i])
3090 incrementalChange =
ok;
3092 lastPositions = positions;
3093 lastValues = values;
3095 const bool outlier =
false;
3096 if (incrementalChange)
3097 emit newHFRPlotPosition(
static_cast<double>(positions.
last()), values.
last(), (pow(weights.
last(), -0.5)),
3098 outlier, params.initialStepSize, plt);
3101 emit initHFRPlot(getyAxisLabel(m_StarMeasure), getStarUnits(m_StarMeasure, m_StarUnits),
3102 m_OptDir == CurveFitting::OPTIMISATION_MINIMISE, params.useWeights, plt);
3103 for (
int i = 0; i < positions.
size(); ++i)
3104 emit newHFRPlotPosition(
static_cast<double>(positions[i]), values[i], (pow(weights.
last(), -0.5)),
3105 outlier, params.initialStepSize, plt);
3109 if (values.
size() > 3)
3115 double minPosition, minValue;
3116 double searchMin = std::max(params.minPositionAllowed, params.startPosition - params.maxTravel);
3117 double searchMax = std::min(params.maxPositionAllowed, params.startPosition + params.maxTravel);
3119 linearFocuser->getPass1Measurements(&pass1Positions, &pass1Values, &pass1Weights, &pass1Outliers);
3120 if (m_FocusAlgorithm == FOCUS_LINEAR || m_CurveFit == CurveFitting::FOCUS_QUADRATIC)
3124 polynomialFit.reset(
new PolynomialFit(2, pass1Positions, pass1Values));
3126 if (polynomialFit->findMinimum(params.startPosition, searchMin, searchMax, &minPosition, &minValue))
3128 emit drawPolynomial(polynomialFit.get(),
true,
true, plt);
3132 if (linearFocuser->isDone())
3133 emit minimumFound(-1, -1, plt);
3135 emit minimumFound(minPosition, minValue, plt);
3140 emit drawPolynomial(polynomialFit.get(),
false,
false, plt);
3141 emit minimumFound(-1, -1, plt);
3147 if (curveFitting->findMinMax(params.startPosition, searchMin, searchMax, &minPosition, &minValue, params.curveFit,
3148 params.optimisationDirection))
3150 R2 = curveFitting->calculateR2(
static_cast<CurveFitting::CurveFit
>(params.curveFit));
3151 emit drawCurve(curveFitting.get(),
true,
true, plt);
3154 emit minimumFound(minPosition, minValue, plt);
3159 emit drawCurve(curveFitting.get(),
false,
false, plt);
3160 emit minimumFound(-1, -1, plt);
3166 HFROut->setText(
QString(
"%1").arg(currentHFR * getStarUnits(m_StarMeasure, m_StarUnits), 0,
'f', 2));
3168 emit setTitle(linearFocuser->getTextStatus(R2));
3170 if (!plt) HFRPlot->replot();
3174CurveFitting::FittingGoal Focus::getGoal(
int numSteps)
3177 if (m_FocusWalk == FOCUS_WALK_CLASSIC)
3178 return CurveFitting::FittingGoal::STANDARD;
3181 return (numSteps >= m_OpsFocusMechanics->focusNumSteps->value()) ? CurveFitting::FittingGoal::BEST :
3182 CurveFitting::FittingGoal::STANDARD;
3188void Focus::plotLinearFinalUpdates()
3191 if (!m_OpsFocusProcess->focusRefineCurveFit->isChecked())
3194 emit drawCFZ(linearFocuser->solution(), linearFocuser->solutionValue(), m_cfzSteps,
3195 m_CFZUI->focusCFZDisplayVCurve->isChecked());
3197 emit finalUpdates(linearFocuser->getTextStatus(R2), plt);
3207 linearFocuser->getPass1Measurements(&pass1Positions, &pass1Values, &pass1Weights, &pass1Outliers);
3208 const FocusAlgorithmInterface::FocusParams ¶ms = linearFocuser->getParams();
3210 emit initHFRPlot(getyAxisLabel(m_StarMeasure), getStarUnits(m_StarMeasure, m_StarUnits),
3211 m_OptDir == CurveFitting::OPTIMISATION_MINIMISE, m_OpsFocusProcess->focusUseWeights->isChecked(), plt);
3213 for (
int i = 0; i < pass1Positions.
size(); ++i)
3214 emit newHFRPlotPosition(
static_cast<double>(pass1Positions[i]), pass1Values[i], (pow(pass1Weights[i], -0.5)),
3215 pass1Outliers[i], params.initialStepSize, plt);
3217 R2 = curveFitting->calculateR2(
static_cast<CurveFitting::CurveFit
>(params.curveFit));
3218 emit drawCurve(curveFitting.get(),
true,
true,
false);
3221 emit minimumFound(linearFocuser->solution(), linearFocuser->solutionValue(), plt);
3223 emit drawCFZ(linearFocuser->solution(), linearFocuser->solutionValue(), m_cfzSteps,
3224 m_CFZUI->focusCFZDisplayVCurve->isChecked());
3226 emit setTitle(linearFocuser->getTextStatus(R2), plt);
3230void Focus::startAberrationInspector()
3232#ifdef HAVE_DATAVISUALIZATION
3234 AberrationInspector::abInsData data;
3236 ImageMosaicMask *mosaicmask =
dynamic_cast<ImageMosaicMask *
>(m_FocusView->imageMask().get());
3239 appendLogText(
i18n(
"Unable to launch Aberration Inspector run %1...", m_abInsRun));
3244 data.run = ++m_abInsRun;
3245 data.curveFit = m_CurveFit;
3246 data.useWeights = m_OpsFocusProcess->focusUseWeights->isChecked();
3247 data.optDir = m_OptDir;
3248 data.sensorWidth = m_CcdWidth;
3249 data.sensorHeight = m_CcdHeight;
3250 data.pixelSize = m_CcdPixelSizeX;
3251 data.tileWidth = mosaicmask->tiles()[0].width();
3252 data.focuserStepMicrons = m_CFZUI->focusCFZStepSize->value();
3253 data.yAxisLabel = getyAxisLabel(m_StarMeasure);
3254 data.starUnits = getStarUnits(m_StarMeasure, m_StarUnits);
3255 data.cfzSteps = m_cfzSteps;
3256 data.isPositionBased = isPositionBased();
3259 appendLogText(
i18n(
"Launching Aberration Inspector run %1...", m_abInsRun));
3261 m_abInsNumStars, m_abInsTileCenterOffset));
3268bool Focus::initScanStartPos(
const bool force,
const int initialPosition)
3272 if (!m_OpsFocusProcess->focusScanStartPos->isChecked())
3275 if (!m_OpsFocusProcess->focusScanAlwaysOn->isChecked() && !m_AFRerun)
3280 inScanStartPos =
true;
3281 initialFocuserAbsPosition = initialPosition;
3282 m_scanMeasure.clear();
3283 m_scanPosition.clear();
3285 appendLogText(
i18n(
"Starting scan for initial focuser position."));
3286 emit setTitle(
QString(
i18n(
"Scanning for starting position...")),
true);
3288 if (!changeFocus(initialPosition - currentPosition))
3289 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FOCUSER_NO_MOVE);
3294void Focus::scanStartPos()
3297 if (currentHFR == INVALID_STAR_MEASURE)
3299 if (noStarCount < MAX_RECAPTURE_RETRIES)
3302 appendLogText(
i18n(
"No stars detected, capturing again..."));
3308 appendLogText(
i18n(
"Failed to detect any stars. Aborting..."));
3309 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_NO_STARS);
3315 if (++absIterations > MAXIMUM_ABS_ITERATIONS)
3317 appendLogText(
i18n(
"Scan Start Pos: exceeded max iterations %1", MAXIMUM_ABS_ITERATIONS));
3318 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_MAX_ITERS);
3323 m_scanPosition.push_back(currentPosition);
3324 m_scanMeasure.push_back(currentMeasure);
3327 const int step = m_scanPosition.size();
3328 const int maxSteps = m_OpsFocusProcess->focusScanDatapoints->value();
3329 const int stepSize = m_OpsFocusMechanics->focusTicks->value() * m_OpsFocusProcess->focusScanStepSizeFactor->value();
3330 emit newHFRPlotPosition(
static_cast<double>(currentPosition), currentMeasure, pow(currentWeight, -0.5),
false, stepSize,
3332 if (step < maxSteps)
3335 emit setTitle(
QString(
i18n(
"Scanning for starting position %1/%2", step, maxSteps)),
true);
3336 deltaPos = step * stepSize * std::pow(-1, step + 1);
3341 auto it = std::min_element(std::begin(m_scanMeasure), std::end(m_scanMeasure));
3342 auto min = std::distance(std::begin(m_scanMeasure), it);
3343 if (min >= m_OpsFocusProcess->focusScanDatapoints->value() - 2)
3346 deltaPos = m_scanPosition[min] - currentPosition;
3347 m_scanPosition.clear();
3348 m_scanMeasure.clear();
3349 emit setTitle(
QString(
i18n(
"No scan minimum - widening search...")),
true);
3354 if (m_AutofocusReason == FOCUS_FOCUS_ADVISOR)
3355 focusAdvisor->setInFocusAdvisor(
false);
3357 const int initialPosition = m_scanPosition[min];
3358 setupLinearFocuser(initialPosition);
3359 inScanStartPos =
false;
3361 deltaPos = linearRequestedPosition - currentPosition;
3362 emit setTitle(
QString(
i18n(
"Scan Start Position %1 Found", initialPosition)),
true);
3363 appendLogText(
i18n(
"Scan Start Position %1 found", initialPosition));
3366 if (!changeFocus(deltaPos))
3367 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FOCUSER_NO_MOVE);
3370void Focus::autoFocusLinear()
3372 if (!autoFocusChecks())
3375 if (!canAbsMove && !canRelMove && canTimerMove)
3378 if (linearRequestedPosition != currentPosition)
3381 qCDebug(KSTARS_EKOS_FOCUS) <<
"Linear: warning, changing position " << currentPosition <<
" to "
3382 << linearRequestedPosition;
3384 currentPosition = linearRequestedPosition;
3389 bool useFocusStarsHFR = m_OpsFocusSettings->focusUseFullField->isChecked()
3390 && m_OpsFocusProcess->focusFramesCount->value() == 1;
3391 auto focusStars = useFocusStarsHFR || (m_FocusAlgorithm == FOCUS_LINEAR1PASS) ? &(m_ImageData->getStarCenters()) : nullptr;
3393 linearRequestedPosition = linearFocuser->newMeasurement(currentPosition, currentMeasure, currentWeight, focusStars);
3394 if (m_FocusAlgorithm == FOCUS_LINEAR1PASS && linearFocuser->isDone() && linearFocuser->solution() != -1)
3397 plotLinearFinalUpdates();
3399 startAberrationInspector();
3405 if (linearFocuser->isDone())
3407 if (linearFocuser->solution() != -1)
3410 if (m_AutofocusReason == FOCUS_FOCUS_ADVISOR)
3412 if (focusAdvisor->analyseAF())
3413 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_ADVISOR_RERUN,
"",
false);
3415 completeFocusProcedure(Ekos::FOCUS_COMPLETE, Ekos::FOCUS_FAIL_NONE,
"",
false);
3417 else if (m_CurveFit == CurveFitting::FOCUS_QUADRATIC)
3419 completeFocusProcedure(Ekos::FOCUS_COMPLETE, Ekos::FOCUS_FAIL_NONE,
"",
false);
3420 else if (R2 >= m_OpsFocusProcess->focusR2Limit->value())
3424 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Linear Curve Fit check passed R2=%1 focusR2Limit=%2").
arg(R2).
arg(
3425 m_OpsFocusProcess->focusR2Limit->value());
3426 completeFocusProcedure(Ekos::FOCUS_COMPLETE, FOCUS_FAIL_NONE,
"",
false);
3429 else if (R2Retries == 0)
3432 appendLogText(
i18n(
"Curve Fit check failed R2=%1 focusR2Limit=%2 retrying...", R2,
3433 m_OpsFocusProcess->focusR2Limit->value()));
3436 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_R2, failCodeInfo,
false);
3442 appendLogText(
i18n(
"Curve Fit check failed again R2=%1 focusR2Limit=%2 but continuing...", R2,
3443 m_OpsFocusProcess->focusR2Limit->value()));
3444 completeFocusProcedure(Ekos::FOCUS_COMPLETE, Ekos::FOCUS_FAIL_NONE,
"",
false);
3450 qCDebug(KSTARS_EKOS_FOCUS) << linearFocuser->doneReason();
3451 AutofocusFailReason failCode = linearFocuser->getFailCode();
3452 appendLogText(
i18n(
"Linear autofocus algorithm aborted: %1", AutofocusFailReasonStr[failCode]));
3453 completeFocusProcedure(Ekos::FOCUS_ABORTED, failCode,
"",
false);
3459 const int delta = linearRequestedPosition - currentPosition;
3461 if (!changeFocus(delta))
3462 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FOCUSER_NO_MOVE,
"",
false);
3468void Focus::autoFocusAbs()
3472 static int minHFRPos = 0, focusOutLimit = 0, focusInLimit = 0, lastHFRPos = 0, fluctuations = 0;
3473 static double minHFR = 0, lastDelta = 0;
3474 double targetPosition = 0;
3475 bool ignoreLimitedDelta =
false;
3477 QString deltaTxt =
QString(
"%1").
arg(fabs(currentHFR - minHFR) * 100.0, 0,
'g', 3);
3480 qCDebug(KSTARS_EKOS_FOCUS) <<
"===============================";
3481 qCDebug(KSTARS_EKOS_FOCUS) <<
"Current HFR: " << currentHFR <<
" Current Position: " << currentPosition;
3482 qCDebug(KSTARS_EKOS_FOCUS) <<
"Last minHFR: " << minHFR <<
" Last MinHFR Pos: " << minHFRPos;
3483 qCDebug(KSTARS_EKOS_FOCUS) <<
"Delta: " << deltaTxt <<
"%";
3484 qCDebug(KSTARS_EKOS_FOCUS) <<
"========================================";
3487 appendLogText(
i18n(
"FITS received. HFR %1 @ %2. Delta (%3%)", HFRText, currentPosition, deltaTxt));
3489 appendLogText(
i18n(
"FITS received. HFR %1 @ %2.", HFRText, currentPosition));
3491 if (!autoFocusChecks())
3494 addPlotPosition(currentPosition, currentHFR);
3496 switch (m_LastFocusDirection)
3499 lastHFR = currentHFR;
3500 initialFocuserAbsPosition = currentPosition;
3501 minHFR = currentHFR;
3502 minHFRPos = currentPosition;
3512 if (absMotionMax < currentPosition + pulseDuration)
3514 if (currentPosition < absMotionMax)
3516 pulseDuration = absMotionMax - currentPosition;
3521 m_LastFocusDirection = FOCUS_IN;
3524 else if (currentPosition + pulseDuration < absMotionMin)
3526 if (absMotionMin < currentPosition)
3528 pulseDuration = currentPosition - absMotionMin;
3533 m_LastFocusDirection = FOCUS_OUT;
3537 m_LastFocusDirection = (pulseDuration > 0) ? FOCUS_OUT : FOCUS_IN;
3538 if (!changeFocus(pulseDuration,
false))
3539 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FOCUSER_NO_MOVE);
3545 if (reverseDir && focusInLimit && focusOutLimit &&
3546 fabs(currentHFR - minHFR) < (m_OpsFocusProcess->focusTolerance->value() / 100.0) && HFRInc == 0)
3548 if (absIterations <= 2)
3550 QString message =
i18n(
"Change in HFR is too small. Try increasing the step size or decreasing the tolerance.");
3551 appendLogText(message);
3552 KSNotification::event(
QLatin1String(
"FocusFailed"), message, KSNotification::Focus, KSNotification::Alert);
3553 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_SMALL_HFR);
3555 else if (noStarCount > 0)
3557 QString message =
i18n(
"Failed to detect focus star in frame. Capture and select a focus star.");
3558 appendLogText(message);
3559 KSNotification::event(
QLatin1String(
"FocusFailed"), message, KSNotification::Focus, KSNotification::Alert);
3560 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_NO_STARS);
3564 completeFocusProcedure(Ekos::FOCUS_COMPLETE, Ekos::FOCUS_FAIL_NONE);
3568 else if (currentHFR < lastHFR)
3571 if (HFRInc >= 1 && m_LastFocusDirection == FOCUS_OUT && lastHFRPos < focusInLimit && fabs(currentHFR - lastHFR) > 0.1)
3573 focusInLimit = lastHFRPos;
3574 qCDebug(KSTARS_EKOS_FOCUS) <<
"New FocusInLimit " << focusInLimit;
3576 else if (HFRInc >= 1 && m_LastFocusDirection == FOCUS_IN && lastHFRPos > focusOutLimit &&
3577 fabs(currentHFR - lastHFR) > 0.1)
3579 focusOutLimit = lastHFRPos;
3580 qCDebug(KSTARS_EKOS_FOCUS) <<
"New FocusOutLimit " << focusOutLimit;
3583 double factor = std::max(1.0, HFRDec / 2.0);
3584 if (m_LastFocusDirection == FOCUS_IN)
3585 targetPosition = currentPosition - (pulseDuration * factor);
3587 targetPosition = currentPosition + (pulseDuration * factor);
3589 qCDebug(KSTARS_EKOS_FOCUS) <<
"current Position" << currentPosition <<
" targetPosition " << targetPosition;
3591 lastHFR = currentHFR;
3594 if (lastHFR < minHFR)
3597 minHFRPos = currentPosition;
3598 qCDebug(KSTARS_EKOS_FOCUS) <<
"new minHFR " << minHFR <<
" @ position " << minHFRPos;
3601 lastHFRPos = currentPosition;
3608 if (plot_position.count() >= 2)
3610 plot_position.remove(plot_position.count() - 2);
3611 plot_value.remove(plot_value.count() - 2);
3625 lastHFR = currentHFR;
3626 lastHFRPos = currentPosition;
3635 qCDebug(KSTARS_EKOS_FOCUS) <<
"Focus is moving away from optimal HFR.";
3638 if (m_LastFocusDirection == FOCUS_IN)
3640 focusInLimit = currentPosition;
3641 qCDebug(KSTARS_EKOS_FOCUS) <<
"Setting focus IN limit to " << focusInLimit;
3645 focusOutLimit = currentPosition;
3646 qCDebug(KSTARS_EKOS_FOCUS) <<
"Setting focus OUT limit to " << focusOutLimit;
3649 if (m_FocusAlgorithm == FOCUS_POLYNOMIAL && plot_position.count() > 4)
3651 polynomialFit.reset(
new PolynomialFit(2, 5, plot_position, plot_value));
3652 double a = *std::min_element(plot_position.constBegin(), plot_position.constEnd());
3653 double b = *std::max_element(plot_position.constBegin(), plot_position.constEnd());
3654 double min_position = 0, min_hfr = 0;
3655 isVShapeSolution = polynomialFit->findMinimum(minHFRPos, a, b, &min_position, &min_hfr);
3656 qCDebug(KSTARS_EKOS_FOCUS) <<
"Found Minimum?" << (isVShapeSolution ?
"Yes" :
"No");
3657 if (isVShapeSolution)
3659 ignoreLimitedDelta =
true;
3660 qCDebug(KSTARS_EKOS_FOCUS) <<
"Minimum Solution:" << min_hfr <<
"@" << min_position;
3661 targetPosition = round(min_position);
3662 appendLogText(
i18n(
"Found polynomial solution @ %1",
QString::number(min_position,
'f', 0)));
3664 emit drawPolynomial(polynomialFit.get(), isVShapeSolution,
true);
3665 emit minimumFound(min_position, min_hfr);
3669 emit drawPolynomial(polynomialFit.get(), isVShapeSolution,
false);
3678 if (std::abs(lastDelta) > 0)
3679 targetPosition = currentPosition + lastDelta;
3681 targetPosition = currentPosition + pulseDuration;
3683 else if (isVShapeSolution ==
false)
3685 ignoreLimitedDelta =
true;
3687 if (m_LastFocusDirection == FOCUS_OUT)
3688 targetPosition = minHFRPos - pulseDuration / 2;
3690 targetPosition = minHFRPos + pulseDuration / 2;
3693 qCDebug(KSTARS_EKOS_FOCUS) <<
"new targetPosition " << targetPosition;
3697 if (focusInLimit != 0 && m_LastFocusDirection == FOCUS_IN && targetPosition < focusInLimit)
3699 targetPosition = focusInLimit;
3700 qCDebug(KSTARS_EKOS_FOCUS) <<
"Limiting target pulse to focus in limit " << targetPosition;
3702 else if (focusOutLimit != 0 && m_LastFocusDirection == FOCUS_OUT && targetPosition > focusOutLimit)
3704 targetPosition = focusOutLimit;
3705 qCDebug(KSTARS_EKOS_FOCUS) <<
"Limiting target pulse to focus out limit " << targetPosition;
3709 if (targetPosition < absMotionMin)
3710 targetPosition = absMotionMin;
3711 else if (targetPosition > absMotionMax)
3712 targetPosition = absMotionMax;
3715 if (targetPosition == currentPosition)
3719 if (targetPosition == minHFRPos || isVShapeSolution)
3721 appendLogText(
"Stopping at minimum recorded HFR position.");
3722 completeFocusProcedure(Ekos::FOCUS_COMPLETE, Ekos::FOCUS_FAIL_NONE);
3726 QString message =
i18n(
"Focuser cannot move further, device limits reached. Autofocus aborted.");
3727 appendLogText(message);
3728 KSNotification::event(
QLatin1String(
"FocusFailed"), message, KSNotification::Focus, KSNotification::Alert);
3729 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FOCUSER_OOB);
3735 if (fluctuations >= MAXIMUM_FLUCTUATIONS)
3737 QString message =
i18n(
"Unstable fluctuations. Try increasing initial step size or exposure time.");
3738 appendLogText(message);
3739 KSNotification::event(
QLatin1String(
"FocusFailed"), message, KSNotification::Focus, KSNotification::Alert);
3740 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FLUCTUATIONS);
3745 if (focusOutLimit && focusOutLimit == focusInLimit)
3747 QString message =
i18n(
"Deadlock reached. Please try again with different settings.");
3748 appendLogText(message);
3749 KSNotification::event(
QLatin1String(
"FocusFailed"), message, KSNotification::Focus, KSNotification::Alert);
3750 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_DEADLOCK);
3755 if (fabs(targetPosition - initialFocuserAbsPosition) > m_OpsFocusMechanics->focusMaxTravel->value())
3757 int minTravelLimit = qMax(0.0, initialFocuserAbsPosition - m_OpsFocusMechanics->focusMaxTravel->value());
3758 int maxTravelLimit = qMin(absMotionMax, initialFocuserAbsPosition + m_OpsFocusMechanics->focusMaxTravel->value());
3762 if (fabs(currentPosition - minTravelLimit) > 10 && targetPosition < minTravelLimit)
3764 targetPosition = minTravelLimit;
3767 else if (fabs(currentPosition - maxTravelLimit) > 10 && targetPosition > maxTravelLimit)
3769 targetPosition = maxTravelLimit;
3773 qCDebug(KSTARS_EKOS_FOCUS) <<
"targetPosition (" << targetPosition <<
") - initHFRAbsPos ("
3774 << initialFocuserAbsPosition <<
") exceeds maxTravel distance of " << m_OpsFocusMechanics->focusMaxTravel->value();
3776 QString message =
i18n(
"Maximum travel limit reached. Autofocus aborted.");
3777 appendLogText(message);
3778 KSNotification::event(
QLatin1String(
"FocusFailed"), message, KSNotification::Focus, KSNotification::Alert);
3779 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FOCUSER_OOB);
3785 lastDelta = (targetPosition - currentPosition);
3787 qCDebug(KSTARS_EKOS_FOCUS) <<
"delta (targetPosition - currentPosition) " << lastDelta;
3790 if (ignoreLimitedDelta ==
false)
3792 double limitedDelta = qMax(-1.0 * m_OpsFocusMechanics->focusMaxSingleStep->value(),
3793 qMin(1.0 * m_OpsFocusMechanics->focusMaxSingleStep->value(), lastDelta));
3794 if (std::fabs(limitedDelta - lastDelta) > 0)
3796 qCDebug(KSTARS_EKOS_FOCUS) <<
"Limited delta to maximum permitted single step " <<
3797 m_OpsFocusMechanics->focusMaxSingleStep->value();
3798 lastDelta = limitedDelta;
3802 m_LastFocusDirection = (lastDelta > 0) ? FOCUS_OUT : FOCUS_IN;
3803 if (!changeFocus(lastDelta,
false))
3804 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FOCUSER_NO_MOVE);
3810void Focus::addPlotPosition(
int pos,
double value,
bool plot)
3812 plot_position.append(pos);
3813 plot_value.append(value);
3815 emit newHFRPlotPosition(
static_cast<double>(pos), value, 1.0,
false, pulseDuration);
3821void Focus::updatePlotPosition()
3823 if (m_FocusAlgorithm == FOCUS_LINEAR1PASS)
3826 if (inScanStartPos || focusAdvisor->inFocusAdvisor())
3829 plot_position.
clear();
3831 plot_weight.clear();
3832 plot_outlier.clear();
3836 linearFocuser->getPass1Measurements(&positions, &plot_value, &plot_weight, &plot_outlier);
3837 plot_position.clear();
3838 for (
int i = 0; i < positions.
count(); i++)
3839 plot_position.append(positions[i]);
3842 if (linearFocuser && linearFocuser->isDone() && linearFocuser->solution() != -1)
3844 plot_position.append(linearFocuser->solution());
3845 plot_value.append(linearFocuser->solutionValue());
3846 plot_weight.append(linearFocuser->solutionWeight());
3847 plot_outlier.append(
false);
3851 else if (m_FocusAlgorithm == FOCUS_LINEAR)
3854 linearFocuser->getMeasurements(&positions, &plot_value, &plot_weight);
3855 plot_position.
clear();
3856 plot_outlier.clear();
3857 for (
int i = 0; i < positions.
count(); i++)
3859 plot_position.append(positions[i]);
3861 plot_outlier.append(
false);
3867 for (
int i = 0; i < plot_position.count(); i++)
3869 plot_weight.append(1.0);
3870 plot_outlier.append(
false);
3875void Focus::autoFocusRel()
3877 static int noStarCount = 0;
3878 static double minHFR = 1e6;
3879 QString deltaTxt =
QString(
"%1").
arg(fabs(currentHFR - minHFR) * 100.0, 0,
'g', 2);
3883 appendLogText(
i18n(
"FITS received. HFR %1. Delta (%2%) Min HFR (%3)", HFRText, deltaTxt, minHFRText));
3885 if (pulseDuration <= MINIMUM_PULSE_TIMER)
3887 appendLogText(
i18n(
"Autofocus failed to reach proper focus. Try adjusting the tolerance value."));
3888 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_TOLERANCE);
3893 if (currentHFR == INVALID_STAR_MEASURE)
3895 if (noStarCount < MAX_RECAPTURE_RETRIES)
3898 appendLogText(
i18n(
"No stars detected, capturing again..."));
3902 else if (m_FocusAlgorithm == FOCUS_LINEAR || m_FocusAlgorithm == FOCUS_LINEAR1PASS)
3904 appendLogText(
i18n(
"Failed to detect any stars at position %1. Continuing...", currentPosition));
3907 else if(!m_OpsFocusProcess->focusDonut->isChecked())
3910 appendLogText(
i18n(
"Failed to detect any stars. Reset frame and try again."));
3911 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_NO_STARS);
3918 switch (m_LastFocusDirection)
3921 lastHFR = currentHFR;
3923 m_LastFocusDirection = FOCUS_IN;
3924 changeFocus(-pulseDuration,
false);
3929 if (fabs(currentHFR - minHFR) < (m_OpsFocusProcess->focusTolerance->value() / 100.0) && HFRInc == 0)
3931 completeFocusProcedure(Ekos::FOCUS_COMPLETE, Ekos::FOCUS_FAIL_NONE);
3933 else if (currentHFR < lastHFR)
3935 if (currentHFR < minHFR)
3936 minHFR = currentHFR;
3938 lastHFR = currentHFR;
3939 changeFocus(m_LastFocusDirection == FOCUS_IN ? -pulseDuration : pulseDuration, false);
3946 lastHFR = currentHFR;
3950 pulseDuration *= 0.75;
3952 if (!changeFocus(m_LastFocusDirection == FOCUS_IN ? pulseDuration : -pulseDuration, false))
3953 completeFocusProcedure(
Ekos::FOCUS_ABORTED,
Ekos::FOCUS_FAIL_FOCUSER_NO_MOVE);
3956 m_LastFocusDirection = (m_LastFocusDirection == FOCUS_IN) ? FOCUS_OUT : FOCUS_IN;
3962void Focus::autoFocusProcessPositionChange(IPState state)
3964 if (state == IPS_OK)
3970 if (focuserAdditionalMovement > 0)
3972 int temp = focuserAdditionalMovement;
3973 focuserAdditionalMovement = 0;
3975 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Undoing overscan extension. Moving back in by %1 ticks in %2s")
3976 .
arg(temp).
arg(m_OpsFocusMechanics->focusOverscanDelay->value());
3978 QTimer::singleShot(m_OpsFocusMechanics->focusOverscanDelay->value() * 1000,
this, [
this, temp]()
3980 if (!changeFocus(-temp, focuserAdditionalMovementUpdateDir))
3982 appendLogText(i18n(
"Focuser error, check INDI panel."));
3983 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FOCUSER_NO_MOVE);
3987 else if (inAutoFocus)
3990 if (m_FocusAlgorithm == FOCUS_LINEAR || m_FocusAlgorithm == FOCUS_LINEAR1PASS)
3991 if (abs(linearRequestedPosition - currentPosition) > m_OpsFocusMechanics->focusTicks->value())
3992 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Focus positioning error: requested position %1, current position %2")
3993 .
arg(linearRequestedPosition).
arg(currentPosition);
3995 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Focus position reached at %1, starting capture in %2 seconds.").
arg(
3996 currentPosition).
arg(m_OpsFocusMechanics->focusSettleTime->value());
3998 if (m_OpsFocusProcess->focusDonut->isChecked())
3999 donutTimeDilation();
4000 capture(m_OpsFocusMechanics->focusSettleTime->value());
4003 else if (state == IPS_ALERT)
4005 appendLogText(
i18n(
"Focuser error, check INDI panel."));
4006 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FOCUSER_ERROR);
4009 qCDebug(KSTARS_EKOS_FOCUS) <<
4010 QString(
"autoFocusProcessPositionChange called with state %1 (%2), focuserAdditionalMovement=%3, inAutoFocus=%4, m_captureInProgress=%5, currentPosition=%6")
4011 .
arg(state).
arg(pstateStr(state)).
arg(focuserAdditionalMovement).
arg(inAutoFocus).
arg(m_captureInProgress)
4012 .
arg(currentPosition);
4016void Focus::donutTimeDilation()
4018 if (m_OpsFocusProcess->focusTimeDilation->value() == 1.0 || inScanStartPos || focusAdvisor->inFocusAdvisor())
4022 const double centre = (m_OpsFocusMechanics->focusNumSteps->value() + 1.0) / 2.0;
4024 const int currentStep = linearFocuser->currentStep() + 1;
4026 if (currentStep <= m_OpsFocusMechanics->focusNumSteps->value())
4027 distance = std::abs(centre - currentStep);
4031 double multiplier =
distance / (centre - 1.0) * m_OpsFocusProcess->focusTimeDilation->value();
4032 multiplier = std::max(multiplier, 1.0);
4033 const double exposure = multiplier * m_donutOrigExposure;
4034 focusExposure->setValue(exposure);
4035 qCDebug(KSTARS_EKOS_FOCUS) <<
"Donut time dilation for point " << currentStep <<
" from " << m_donutOrigExposure <<
" to "
4040void Focus::updateProperty(INDI::Property prop)
4042 if (m_Focuser ==
nullptr || prop.getType() != INDI_NUMBER || prop.getDeviceName() != m_Focuser->getDeviceName())
4045 auto nvp = prop.getNumber();
4051 if (nvp->isNameMatch(
"FOCUS_BACKLASH_STEPS"))
4053 m_OpsFocusMechanics->focusBacklash->setValue(nvp->np[0].value);
4057 if (nvp->isNameMatch(
"ABS_FOCUS_POSITION"))
4062 if (m_DebugFocuserCounter++ >= 10 && m_DebugFocuserCounter <= 14)
4064 if (m_DebugFocuserCounter == 14)
4065 m_DebugFocuserCounter = 0;
4066 appendLogText(
i18n(
"Simulate focuser comms failure..."));
4071 m_FocusMotionTimer.stop();
4072 INumber *pos = IUFindNumber(nvp,
"FOCUS_ABSOLUTE_POSITION");
4073 IPState newState = nvp->s;
4078 int newPosition =
static_cast<int>(pos->value);
4083 if (currentPosition == newPosition && currentPositionState == newState)
4085 qCDebug(KSTARS_EKOS_FOCUS) <<
"Focuser position " << currentPosition <<
" and state:"
4086 << pstateStr(currentPositionState) <<
" unchanged";
4090 currentPositionState = newState;
4092 if (currentPosition != newPosition)
4094 currentPosition = newPosition;
4095 qCDebug(KSTARS_EKOS_FOCUS) <<
"Abs Focuser position changed to " << currentPosition <<
"State:" << pstateStr(
4096 currentPositionState);
4098 emit absolutePositionChanged(currentPosition);
4102 qCDebug(KSTARS_EKOS_FOCUS) <<
"Can't access FOCUS_ABSOLUTE_POSITION. Current state:"
4103 << pstateStr(currentPositionState) <<
" New state:" << pstateStr(newState);
4105 if (newState != IPS_OK)
4107 if (inAutoFocus || inAdjustFocus || adaptFocus->inAdaptiveFocus())
4111 qCDebug(KSTARS_EKOS_FOCUS) <<
"Restarting focus motion timer, state " << pstateStr(newState);
4112 m_FocusMotionTimer.start();
4118 if (focuserAdditionalMovement == 0)
4123 if (focuserAdditionalMovement == 0)
4125 inAdjustFocus =
false;
4126 emit focusPositionAdjusted();
4131 if (adaptFocus->inAdaptiveFocus())
4133 if (focuserAdditionalMovement == 0)
4135 adaptFocus->adaptiveFocusAdmin(currentPosition,
true,
true);
4140 if (m_RestartState == RESTART_NOW && status() != Ekos::FOCUS_ABORTED)
4142 if (focuserAdditionalMovement == 0)
4144 m_RestartState = RESTART_NONE;
4146 inAutoFocus = inBuildOffsets = inAdjustFocus = inScanStartPos =
false;
4147 adaptFocus->setInAdaptiveFocus(
false);
4148 focusAdvisor->setInFocusAdvisor(
false);
4149 appendLogText(
i18n(
"Restarting autofocus process..."));
4150 runAutoFocus(m_AutofocusReason, m_AutofocusReasonInfo);
4154 else if (m_RestartState == RESTART_ABORT && focuserAdditionalMovement == 0)
4160 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FORCE_ABORT);
4161 m_RestartState = RESTART_NONE;
4162 inAutoFocus = inBuildOffsets = inAdjustFocus = inScanStartPos =
false;
4163 adaptFocus->setInAdaptiveFocus(
false);
4164 focusAdvisor->setInFocusAdvisor(
false);
4170 autoFocusProcessPositionChange(newState);
4171 else if (newState == IPS_ALERT)
4172 appendLogText(
i18n(
"Focuser error, check INDI panel."));
4179 if (nvp->isNameMatch(
"manualfocusdrive"))
4184 if (m_DebugFocuserCounter++ >= 10 && m_DebugFocuserCounter <= 14)
4186 if (m_DebugFocuserCounter == 14)
4187 m_DebugFocuserCounter = 0;
4188 appendLogText(
i18n(
"Simulate focuser comms failure..."));
4193 m_FocusMotionTimer.stop();
4195 INumber *pos = IUFindNumber(nvp,
"manualfocusdrive");
4196 IPState newState = nvp->s;
4197 if (pos && newState == IPS_OK)
4199 if (focuserAdditionalMovement == 0)
4202 currentPosition += pos->value;
4203 absTicksLabel->setText(
QString::number(
static_cast<int>(currentPosition)));
4204 emit absolutePositionChanged(currentPosition);
4207 if (inAdjustFocus && newState == IPS_OK)
4209 if (focuserAdditionalMovement == 0)
4211 inAdjustFocus =
false;
4212 emit focusPositionAdjusted();
4217 if (adaptFocus->inAdaptiveFocus() && newState == IPS_OK)
4219 if (focuserAdditionalMovement == 0)
4221 adaptFocus->adaptiveFocusAdmin(currentPosition,
true,
true);
4227 if (m_RestartState == RESTART_NOW && newState == IPS_OK && status() != Ekos::FOCUS_ABORTED)
4229 if (focuserAdditionalMovement == 0)
4231 m_RestartState = RESTART_NONE;
4233 inAutoFocus = inBuildOffsets = inAdjustFocus = inScanStartPos =
false;
4234 adaptFocus->setInAdaptiveFocus(
false);
4235 focusAdvisor->setInFocusAdvisor(
false);
4236 appendLogText(
i18n(
"Restarting autofocus process..."));
4237 runAutoFocus(m_AutofocusReason, m_AutofocusReasonInfo);
4241 else if (m_RestartState == RESTART_ABORT && newState == IPS_OK)
4244 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FORCE_ABORT);
4245 m_RestartState = RESTART_NONE;
4246 inAutoFocus = inBuildOffsets = inAdjustFocus = inScanStartPos =
false;
4247 adaptFocus->setInAdaptiveFocus(
false);
4248 focusAdvisor->setInFocusAdvisor(
false);
4253 autoFocusProcessPositionChange(newState);
4254 else if (newState == IPS_ALERT)
4255 appendLogText(
i18n(
"Focuser error, check INDI panel."));
4260 if (nvp->isNameMatch(
"REL_FOCUS_POSITION"))
4262 m_FocusMotionTimer.stop();
4264 INumber *pos = IUFindNumber(nvp,
"FOCUS_RELATIVE_POSITION");
4265 IPState newState = nvp->s;
4266 if (pos && newState == IPS_OK)
4268 if (focuserAdditionalMovement == 0)
4271 currentPosition += pos->value * (m_LastFocusDirection == FOCUS_IN ? -1 : 1);
4272 qCDebug(KSTARS_EKOS_FOCUS)
4273 <<
QString(
"Rel Focuser position moved %1 by %2 to %3")
4274 .
arg((m_LastFocusDirection == FOCUS_IN) ?
"in" :
"out").arg(pos->value).
arg(currentPosition);
4275 absTicksLabel->setText(
QString::number(
static_cast<int>(currentPosition)));
4276 emit absolutePositionChanged(currentPosition);
4279 if (inAdjustFocus && newState == IPS_OK)
4281 if (focuserAdditionalMovement == 0)
4283 inAdjustFocus =
false;
4284 emit focusPositionAdjusted();
4289 if (adaptFocus->inAdaptiveFocus() && newState == IPS_OK)
4291 if (focuserAdditionalMovement == 0)
4293 adaptFocus->adaptiveFocusAdmin(currentPosition,
true,
true);
4299 if (m_RestartState == RESTART_NOW && newState == IPS_OK && status() != Ekos::FOCUS_ABORTED)
4301 if (focuserAdditionalMovement == 0)
4303 m_RestartState = RESTART_NONE;
4305 inAutoFocus = inBuildOffsets = inAdjustFocus = inScanStartPos =
false;
4306 adaptFocus->setInAdaptiveFocus(
false);
4307 focusAdvisor->setInFocusAdvisor(
false);
4308 appendLogText(
i18n(
"Restarting autofocus process..."));
4309 runAutoFocus(m_AutofocusReason, m_AutofocusReasonInfo);
4313 else if (m_RestartState == RESTART_ABORT && newState == IPS_OK)
4316 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FORCE_ABORT);
4317 m_RestartState = RESTART_NONE;
4318 inAutoFocus = inBuildOffsets = inAdjustFocus = inScanStartPos =
false;
4319 adaptFocus->setInAdaptiveFocus(
false);
4320 focusAdvisor->setInFocusAdvisor(
false);
4325 autoFocusProcessPositionChange(newState);
4326 else if (newState == IPS_ALERT)
4327 appendLogText(
i18n(
"Focuser error, check INDI panel."));
4335 if (nvp->isNameMatch(
"FOCUS_TIMER"))
4337 IPState newState = nvp->s;
4338 m_FocusMotionTimer.stop();
4340 if (m_RestartState == RESTART_NOW && newState == IPS_OK && status() != Ekos::FOCUS_ABORTED)
4342 if (focuserAdditionalMovement == 0)
4344 m_RestartState = RESTART_NONE;
4346 inAutoFocus = inBuildOffsets = inAdjustFocus = inScanStartPos =
false;
4347 adaptFocus->setInAdaptiveFocus(
false);
4348 focusAdvisor->setInFocusAdvisor(
false);
4349 appendLogText(
i18n(
"Restarting autofocus process..."));
4350 runAutoFocus(m_AutofocusReason, m_AutofocusReasonInfo);
4354 else if (m_RestartState == RESTART_ABORT && newState == IPS_OK)
4357 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FORCE_ABORT);
4358 m_RestartState = RESTART_NONE;
4359 inAutoFocus = inBuildOffsets = inAdjustFocus = inScanStartPos =
false;
4360 adaptFocus->setInAdaptiveFocus(
false);
4361 focusAdvisor->setInFocusAdvisor(
false);
4365 if (canAbsMove ==
false && canRelMove ==
false)
4368 INumber *pos = IUFindNumber(nvp,
"FOCUS_TIMER_VALUE");
4371 currentPosition += pos->value * (m_LastFocusDirection == FOCUS_IN ? -1 : 1);
4372 qCDebug(KSTARS_EKOS_FOCUS)
4373 <<
QString(
"Timer Focuser position moved %1 by %2 to %3")
4374 .
arg((m_LastFocusDirection == FOCUS_IN) ?
"in" :
"out").arg(pos->value).
arg(currentPosition);
4377 if (pos && newState == IPS_OK && focuserAdditionalMovement == 0)
4380 if (inAdjustFocus && newState == IPS_OK)
4382 if (focuserAdditionalMovement == 0)
4384 inAdjustFocus =
false;
4385 emit focusPositionAdjusted();
4390 if (adaptFocus->inAdaptiveFocus() && newState == IPS_OK)
4392 if (focuserAdditionalMovement == 0)
4394 adaptFocus->adaptiveFocusAdmin(
true,
true,
true);
4399 autoFocusProcessPositionChange(newState);
4401 else if (newState == IPS_ALERT)
4402 appendLogText(
i18n(
"Focuser error, check INDI panel."));
4410 m_LogText.insert(0,
i18nc(
"log entry; %1 is the date, %2 is the text",
"%1 %2",
4411 KStarsData::Instance()->lt().toString(
"yyyy-MM-ddThh:mm:ss"), text));
4413 qCInfo(KSTARS_EKOS_FOCUS) << text;
4418void Focus::clearLog()
4424void Focus::appendFocusLogText(
const QString &lines)
4426 if (Options::focusLogging())
4429 if (!m_FocusLogFile.exists())
4433 dir.mkpath(
"focuslogs");
4435 if (m_FocusLogEnabled)
4438 header <<
"date, time, position, temperature, filter, HFR, altitude\n";
4442 qCWarning(KSTARS_EKOS_FOCUS) <<
"Failed to open focus log file: " << m_FocusLogFileName;
4445 if (m_FocusLogEnabled)
4454void Focus::startFraming()
4456 if (m_Camera ==
nullptr)
4458 appendLogText(
i18n(
"No CCD connected."));
4462 waitStarSelectTimer.stop();
4465 starMeasureFrames.clear();
4470 setState(Ekos::FOCUS_FRAMING);
4474 appendLogText(
i18n(
"Starting continuous exposure..."));
4479void Focus::resetButtons()
4483 startFocusB->setEnabled(
false);
4484 startAbInsB->setEnabled(
false);
4485 startLoopB->setEnabled(
false);
4486 focusOutB->setEnabled(
true);
4487 focusInB->setEnabled(
true);
4488 startGotoB->setEnabled(canAbsMove);
4489 stopFocusB->setEnabled(
true);
4490 captureB->setEnabled(
false);
4491 opticalTrainCombo->setEnabled(
false);
4492 trainB->setEnabled(
false);
4506 if (disabledWidgets.empty())
4508 AFDisable(trainLabel,
false);
4509 AFDisable(opticalTrainCombo,
false);
4510 AFDisable(trainB,
false);
4511 AFDisable(focuserGroup,
true);
4512 AFDisable(clearDataB,
false);
4515 m_FocusGainAFEnabled = focusGain->isEnabled();
4516 m_FocusISOAFEnabled = focusISO->isEnabled();
4517 AFDisable(ccdGroup,
false);
4519 AFDisable(toolsGroup,
false);
4522 m_FocusSubFrameAFEnabled = m_OpsFocusSettings->focusSubFrame->isEnabled();
4525 AFDisable(m_OpsFocusSettings,
false);
4526 AFDisable(m_OpsFocusProcess,
false);
4527 AFDisable(m_OpsFocusMechanics,
false);
4528 AFDisable(focusAdvisor->focusAdvGroupBox,
false);
4529 AFDisable(m_CFZDialog,
false);
4532 stopFocusB->setEnabled(
true);
4538 for(
int i = 0 ; i < disabledWidgets.size() ; i++)
4539 disabledWidgets[i]->setEnabled(
true);
4540 disabledWidgets.clear();
4542 auto enableCaptureButtons = (m_captureInProgress ==
false && m_starDetectInProgress ==
false);
4544 captureB->setEnabled(enableCaptureButtons);
4545 resetFrameB->setEnabled(enableCaptureButtons);
4546 startLoopB->setEnabled(enableCaptureButtons);
4547 m_OpsFocusSettings->focusAutoStarEnabled->setEnabled(enableCaptureButtons
4548 && m_OpsFocusSettings->focusUseFullField->isChecked() ==
false);
4550 if (m_Focuser && m_Focuser->isConnected())
4552 focusOutB->setEnabled(
true);
4553 focusInB->setEnabled(
true);
4555 startFocusB->setEnabled(m_FocusType == FOCUS_AUTO);
4556 startAbInsB->setEnabled(canAbInsStart());
4557 stopFocusB->setEnabled(!enableCaptureButtons);
4558 startGotoB->setEnabled(canAbsMove);
4559 stopGotoB->setEnabled(
true);
4563 focusOutB->setEnabled(
false);
4564 focusInB->setEnabled(
false);
4566 startFocusB->setEnabled(
false);
4567 startAbInsB->setEnabled(
false);
4568 stopFocusB->setEnabled(
false);
4569 startGotoB->setEnabled(
false);
4570 stopGotoB->setEnabled(
false);
4578bool Focus::canAbInsStart()
4580 return canAbsMove && m_FocusAlgorithm == FOCUS_LINEAR1PASS && m_currentImageMask == FOCUS_MASK_MOSAIC;
4584void Focus::AFDisable(
QWidget * widget,
const bool children)
4589 for(
auto *wid : widget->findChildren<
QWidget *>())
4591 if (wid->isEnabled())
4593 wid->setEnabled(
false);
4594 disabledWidgets.push_back(wid);
4603 disabledWidgets.push_back(widget);
4607bool Focus::isFocusGainEnabled()
4609 return (inAutoFocus) ? m_FocusGainAFEnabled : focusGain->isEnabled();
4612bool Focus::isFocusISOEnabled()
4614 return (inAutoFocus) ? m_FocusISOAFEnabled : focusISO->isEnabled();
4617bool Focus::isFocusSubFrameEnabled()
4619 return (inAutoFocus) ? m_FocusSubFrameAFEnabled : m_OpsFocusSettings->focusSubFrame->isEnabled();
4622void Focus::updateBoxSize(
int value)
4624 if (m_Camera ==
nullptr)
4627 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
4629 if (targetChip ==
nullptr)
4632 int subBinX, subBinY;
4633 targetChip->getBinning(&subBinX, &subBinY);
4635 QRect trackBox = m_FocusView->getTrackingBox();
4639 QRect(
center.x() - value / (2 * subBinX),
center.y() - value / (2 * subBinY), value / subBinX, value / subBinY);
4641 m_FocusView->setTrackingBox(trackBox);
4644void Focus::selectFocusStarFraction(
double x,
double y)
4646 if (m_ImageData.isNull())
4649 focusStarSelected(x * m_ImageData->width(), y * m_ImageData->height());
4653 emit newImage(m_FocusView);
4657void Focus::focusStarSelected(
int x,
int y)
4659 if (state() == Ekos::FOCUS_PROGRESS)
4662 if (subFramed ==
false)
4664 rememberStarCenter.setX(x);
4665 rememberStarCenter.setY(y);
4668 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
4670 int subBinX, subBinY;
4671 targetChip->getBinning(&subBinX, &subBinY);
4674 if (subBinX != (focusBinning->currentIndex() + 1))
4680 int offset = (
static_cast<double>(m_OpsFocusSettings->focusBoxSize->value()) / subBinX) * 1.5;
4684 bool squareMovedOutside =
false;
4686 if (subFramed ==
false && m_OpsFocusSettings->focusSubFrame->isChecked() && targetChip->canSubframe())
4688 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
4690 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
4693 x = (x - offset) * subBinX;
4694 y = (y - offset) * subBinY;
4695 int w = offset * 2 * subBinX;
4696 int h = offset * 2 * subBinY;
4715 QVariantMap settings = frameSettings[targetChip];
4720 settings[
"binx"] = subBinX;
4721 settings[
"biny"] = subBinY;
4723 frameSettings[targetChip] = settings;
4727 qCDebug(KSTARS_EKOS_FOCUS) <<
"Frame is subframed. X:" << x <<
"Y:" << y <<
"W:" << w <<
"H:" << h <<
"binX:" << subBinX <<
4730 m_FocusView->setFirstLoad(
true);
4735 starCenter.setX(w / (2 * subBinX));
4736 starCenter.setY(h / (2 * subBinY));
4741 double dist = sqrt((starCenter.x() - x) * (starCenter.x() - x) + (starCenter.y() - y) * (starCenter.y() - y));
4743 squareMovedOutside = (dist > (
static_cast<double>(m_OpsFocusSettings->focusBoxSize->value()) / subBinX));
4747 starRect =
QRect(starCenter.x() - m_OpsFocusSettings->focusBoxSize->value() / (2 * subBinX),
4748 starCenter.y() - m_OpsFocusSettings->focusBoxSize->value() / (2 * subBinY),
4749 m_OpsFocusSettings->focusBoxSize->value() / subBinX,
4750 m_OpsFocusSettings->focusBoxSize->value() / subBinY);
4751 m_FocusView->setTrackingBox(starRect);
4756 starCenter.setZ(subBinX);
4758 if (squareMovedOutside && inAutoFocus ==
false && m_OpsFocusSettings->focusAutoStarEnabled->isChecked())
4760 m_OpsFocusSettings->focusAutoStarEnabled->blockSignals(
true);
4761 m_OpsFocusSettings->focusAutoStarEnabled->setChecked(
false);
4762 m_OpsFocusSettings->focusAutoStarEnabled->blockSignals(
false);
4763 appendLogText(
i18n(
"Disabling Auto Star Selection as star selection box was moved manually."));
4764 starSelected =
false;
4766 else if (starSelected ==
false)
4768 appendLogText(
i18n(
"Focus star is selected."));
4769 starSelected =
true;
4773 waitStarSelectTimer.stop();
4774 FocusState nextState = inAutoFocus ? FOCUS_PROGRESS : FOCUS_IDLE;
4775 if (nextState != state())
4777 setState(nextState);
4781void Focus::checkFocus(
double requiredHFR)
4783 if (inAutoFocus || inAdjustFocus || adaptFocus->inAdaptiveFocus())
4787 str =
i18n(
"Autofocus");
4788 else if (inAdjustFocus)
4789 str =
i18n(
"Adjust Focus");
4791 str =
i18n(
"Adaptive Focus");
4793 if (++m_StartRetries < MAXIMUM_RESTART_ITERATIONS)
4795 appendLogText(
i18n(
"Check focus request - Waiting 10sec for %1 to complete.", str));
4798 checkFocus(requiredHFR);
4803 appendLogText(
i18n(
"Discarding Check Focus request - %1 in progress.", str));
4804 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_INTERNAL);
4810 if (inFocusLoop || inBuildOffsets)
4812 QString str = inFocusLoop ?
"Focus Looping" :
" Build Offsets";
4813 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Check Focus rejected, %1 is already running.").
arg(str);
4817 qCDebug(KSTARS_EKOS_FOCUS) <<
"Check Focus requested with minimum required HFR" << requiredHFR;
4818 minimumRequiredHFR = requiredHFR;
4820 appendLogText(
"Capturing to check HFR...");
4825void Focus::toggleSubframe(
bool enable)
4827 if (enable ==
false)
4830 starSelected =
false;
4836 m_OpsFocusSettings->focusAutoStarEnabled->setEnabled(
true);
4838 m_OpsFocusSettings->focusNoMaskRB->setChecked(
true);
4843 m_OpsFocusSettings->focusAutoStarEnabled->setChecked(
false);
4844 m_OpsFocusSettings->focusAutoStarEnabled->setEnabled(
false);
4849 m_OpsFocusSettings->focusRingMaskRB->setEnabled(!enable);
4850 m_OpsFocusSettings->focusMosaicMaskRB->setEnabled(!enable);
4859void Focus::setUseWeights()
4861 if (m_CurveFit == CurveFitting::FOCUS_QUADRATIC || !m_OpsFocusSettings->focusUseFullField->isChecked()
4862 || m_StarMeasure == FOCUS_STAR_NUM_STARS
4863 || m_StarMeasure == FOCUS_STAR_FOURIER_POWER)
4865 m_OpsFocusProcess->focusUseWeights->setEnabled(
false);
4866 m_OpsFocusProcess->focusUseWeights->setChecked(
false);
4869 m_OpsFocusProcess->focusUseWeights->setEnabled(
true);
4878void Focus::setDonutBuster()
4880 if (m_FocusAlgorithm != FOCUS_LINEAR1PASS)
4882 m_OpsFocusProcess->focusDonut->hide();
4883 m_OpsFocusProcess->focusDonut->setEnabled(
false);
4884 m_OpsFocusProcess->focusDonut->setChecked(
false);
4888 m_OpsFocusProcess->focusDonut->show();
4889 if ((m_StarMeasure == FOCUS_STAR_HFR || m_StarMeasure == FOCUS_STAR_HFR_ADJ || m_StarMeasure == FOCUS_STAR_FWHM) &&
4890 (m_FocusWalk == FOCUS_WALK_FIXED_STEPS || m_FocusWalk == FOCUS_WALK_CFZ_SHUFFLE) &&
4891 (m_CurveFit != CurveFitting::FOCUS_QUADRATIC))
4892 m_OpsFocusProcess->focusDonut->setEnabled(
true);
4895 m_OpsFocusProcess->focusDonut->setEnabled(
false);
4896 m_OpsFocusProcess->focusDonut->setChecked(
false);
4901void Focus::setExposure(
double value)
4903 focusExposure->setValue(value);
4906void Focus::setBinning(
int subBinX,
int subBinY)
4908 INDI_UNUSED(subBinY);
4909 focusBinning->setCurrentIndex(subBinX - 1);
4912void Focus::setAutoStarEnabled(
bool enable)
4914 m_OpsFocusSettings->focusAutoStarEnabled->setChecked(enable);
4917void Focus::setAutoSubFrameEnabled(
bool enable)
4919 m_OpsFocusSettings->focusSubFrame->setChecked(enable);
4922void Focus::setAutoFocusParameters(
int boxSize,
int stepSize,
int maxTravel,
double tolerance)
4924 m_OpsFocusSettings->focusBoxSize->setValue(boxSize);
4925 m_OpsFocusMechanics->focusTicks->setValue(stepSize);
4926 m_OpsFocusMechanics->focusMaxTravel->setValue(maxTravel);
4927 m_OpsFocusProcess->focusTolerance->setValue(tolerance);
4930void Focus::checkAutoStarTimeout()
4933 if (starCenter.isNull() && (inAutoFocus || minimumRequiredHFR > 0))
4937 if (rememberStarCenter.isNull() ==
false)
4939 focusStarSelected(rememberStarCenter.x(), rememberStarCenter.y());
4940 appendLogText(
i18n(
"No star was selected. Using last known position..."));
4945 initialFocuserAbsPosition = -1;
4946 appendLogText(
i18n(
"No star was selected. Aborting..."));
4947 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_NO_STARS);
4949 else if (state() == FOCUS_WAITING)
4950 setState(FOCUS_IDLE);
4953void Focus::setAbsoluteFocusTicks()
4955 if (absTicksSpin->value() == currentPosition)
4957 appendLogText(
i18n(
"Focuser already at %1...", currentPosition));
4960 focusInB->setEnabled(
false);
4961 focusOutB->setEnabled(
false);
4962 startGotoB->setEnabled(
false);
4963 if (!changeFocus(absTicksSpin->value() - currentPosition))
4964 qCDebug(KSTARS_EKOS_FOCUS) <<
"setAbsoluteFocusTicks unable to move focuser.";
4967void Focus::syncTrackingBoxPosition()
4969 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
4970 Q_ASSERT(targetChip);
4972 int subBinX = 1, subBinY = 1;
4973 targetChip->getBinning(&subBinX, &subBinY);
4975 if (starCenter.isNull() ==
false)
4977 double boxSize = m_OpsFocusSettings->focusBoxSize->value();
4979 targetChip->getFrame(&x, &y, &w, &h);
4981 if (boxSize / subBinX >= w || boxSize / subBinY >= h)
4983 m_OpsFocusSettings->focusBoxSize->setValue((boxSize / subBinX >= w) ? w : h);
4988 if (subBinX != starCenter.z())
4990 if (starCenter.z() > 0)
4992 starCenter.setX(starCenter.x() * (starCenter.z() / subBinX));
4993 starCenter.setY(starCenter.y() * (starCenter.z() / subBinY));
4996 starCenter.setZ(subBinX);
4999 QRect starRect =
QRect(starCenter.x() - boxSize / (2 * subBinX), starCenter.y() - boxSize / (2 * subBinY),
5000 boxSize / subBinX, boxSize / subBinY);
5001 m_FocusView->setTrackingBoxEnabled(
true);
5002 m_FocusView->setTrackingBox(starRect);
5006void Focus::showFITSViewer()
5008 static int lastFVTabID = -1;
5015 fv->loadData(m_ImageData, url, &lastFVTabID);
5016 connect(fv.get(), &FITSViewer::terminated,
this, [
this]()
5021 else if (fv->updateData(m_ImageData, url, lastFVTabID, &lastFVTabID) ==
false)
5022 fv->loadData(m_ImageData, url, &lastFVTabID);
5028void Focus::adjustFocusOffset(
int value,
bool useAbsoluteOffset)
5031 if (inAdjustFocus || adaptFocus->inAdaptiveFocus())
5033 QString str = inAdjustFocus ?
i18n(
"Adjust Focus") :
i18n(
"Adaptive Focus");
5034 if (++m_StartRetries < MAXIMUM_RESTART_ITERATIONS)
5036 appendLogText(
i18n(
"Adjust focus request - Waiting 10sec for %1 to complete.", str));
5039 adjustFocusOffset(value, useAbsoluteOffset);
5044 qCDebug(KSTARS_EKOS_FOCUS) <<
"adjustFocusOffset called whilst" << str <<
"in progress. Ignoring...";
5045 emit focusPositionAdjusted();
5050 inAdjustFocus =
true;
5053 int newPosition = (useAbsoluteOffset) ? value : value + currentPosition;
5055 if (!changeFocus(newPosition - currentPosition))
5056 qCDebug(KSTARS_EKOS_FOCUS) <<
"adjustFocusOffset unable to move focuser";
5059void Focus::toggleFocusingWidgetFullScreen()
5061 if (focusingWidget->parent() ==
nullptr)
5063 focusingWidget->setParent(
this);
5064 rightLayout->insertWidget(0, focusingWidget);
5065 focusingWidget->showNormal();
5069 focusingWidget->setParent(
nullptr);
5070 focusingWidget->setWindowTitle(
i18nc(
"@title:window",
"Focus Frame"));
5072 focusingWidget->showMaximized();
5073 focusingWidget->show();
5077void Focus::setMountStatus(ISD::Mount::Status newState)
5081 case ISD::Mount::MOUNT_PARKING:
5082 case ISD::Mount::MOUNT_SLEWING:
5083 case ISD::Mount::MOUNT_MOVING:
5084 captureB->setEnabled(
false);
5085 startFocusB->setEnabled(
false);
5086 startAbInsB->setEnabled(
false);
5087 startLoopB->setEnabled(
false);
5102void Focus::setMountCoords(
const SkyPoint &position, ISD::Mount::PierSide pierSide,
const dms &ha)
5111 auto name = deviceRemoved->getDeviceName();
5115 if (m_Focuser && m_Focuser->getDeviceName() == name)
5117 m_Focuser->disconnect(
this);
5118 m_Focuser =
nullptr;
5127 for (
auto &oneSource : m_TemperatureSources)
5129 if (oneSource->getDeviceName() == name)
5132 if (m_LastSourceDeviceAutofocusTemperature && m_LastSourceDeviceAutofocusTemperature->getDeviceName() == name)
5133 m_LastSourceDeviceAutofocusTemperature.reset(
nullptr);
5135 m_TemperatureSources.removeAll(oneSource);
5138 defaultFocusTemperatureSource->removeItem(defaultFocusTemperatureSource->findText(name));
5145 if (m_Camera && m_Camera->getDeviceName() == name)
5147 m_Camera->disconnect(
this);
5158 if (m_FilterWheel && m_FilterWheel->getDeviceName() == name)
5160 m_FilterWheel->disconnect(
this);
5161 m_FilterWheel =
nullptr;
5171void Focus::setupFilterManager()
5174 if (m_FilterManager)
5175 m_FilterManager->disconnect(
this);
5178 Ekos::Manager::Instance()->createFilterManager(m_FilterWheel);
5181 Ekos::Manager::Instance()->getFilterManager(m_FilterWheel->getDeviceName(), m_FilterManager);
5186 connect(
this, &Focus::absolutePositionChanged, m_FilterManager.get(), &FilterManager::setFocusAbsolutePosition);
5189 connect(
this, &Focus::newStatus,
this, [
this](Ekos::FocusState state)
5191 if (m_FilterManager)
5193 m_FilterManager->setFocusStatus(state);
5194 if (focusFilter->currentIndex() != -1 && canAbsMove && state == Ekos::FOCUS_COMPLETE)
5196 m_FilterManager->setFilterAbsoluteFocusDetails(focusFilter->currentIndex(), currentPosition,
5197 m_LastSourceAutofocusTemperature, m_LastSourceAutofocusAlt);
5205 connect(m_FilterManager.get(), &FilterManager::newStatus,
this, [
this](Ekos::FilterState filterState)
5208 if (filterState == FILTER_OFFSET && state() != Ekos::FOCUS_PROGRESS)
5210 if (m_GuidingSuspended == false && m_OpsFocusSettings->focusSuspendGuiding->isChecked())
5212 m_GuidingSuspended = true;
5213 emit suspendGuiding();
5219 connect(m_FilterManager.get(), &FilterManager::ready,
this, [
this]()
5222 if (focusFilter->currentIndex() != currentFilterPosition - 1)
5223 focusFilter->setCurrentIndex(currentFilterPosition - 1);
5225 if (filterPositionPending)
5227 filterPositionPending = false;
5230 else if (fallbackFilterPending)
5232 fallbackFilterPending =
false;
5233 emit newStatus(state());
5238 connect(m_FilterManager.get(), &FilterManager::failed,
this, [
this]()
5240 appendLogText(i18n(
"Filter operation failed."));
5241 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_FILTER_MANAGER);
5245 connect(m_FilterManager.get(), &FilterManager::runAutoFocus,
this, &Focus::runAutoFocus);
5248 connect(m_FilterManager.get(), &FilterManager::abortAutoFocus,
this, &Focus::abort);
5251 connect(m_FilterManager.get(), &FilterManager::newFocusOffset,
this, &Focus::adjustFocusOffset);
5254 connect(m_FilterManager.get(), &FilterManager::labelsChanged,
this, [
this]()
5256 focusFilter->clear();
5257 focusFilter->addItems(m_FilterManager->getFilterLabels());
5258 currentFilterPosition = m_FilterManager->getFilterPosition();
5259 focusFilter->setCurrentIndex(currentFilterPosition - 1);
5263 connect(m_FilterManager.get(), &FilterManager::positionChanged,
this, [
this]()
5265 currentFilterPosition = m_FilterManager->getFilterPosition();
5266 focusFilter->setCurrentIndex(currentFilterPosition - 1);
5270 connect(m_FilterManager.get(), &FilterManager::exposureChanged,
this, [
this]()
5272 focusExposure->setValue(m_FilterManager->getFilterExposure());
5276 connect(m_FilterManager.get(), &FilterManager::wavelengthChanged,
this, [
this]()
5278 wavelengthChanged();
5282void Focus::connectFilterManager()
5287 if (m_FilterManager)
5289 m_FilterManager->refreshFilterModel();
5290 m_FilterManager->show();
5291 m_FilterManager->raise();
5296 connect(
this, &Focus::focusPositionAdjusted,
this, [
this]()
5298 if (m_FilterManager)
5299 m_FilterManager->setFocusOffsetComplete();
5300 if (m_GuidingSuspended && state() != Ekos::FOCUS_PROGRESS)
5302 QTimer::singleShot(m_OpsFocusMechanics->focusSettleTime->value() * 1000,
this, [
this]()
5304 m_GuidingSuspended = false;
5305 emit resumeGuiding();
5314 if (inAutoFocus && m_OpsFocusProcess->focusDonut->isEnabled())
5317 if (m_FilterManager)
5318 m_FilterManager->setFilterExposure(focusFilter->currentIndex(), focusExposure->value());
5324 if (m_FilterManager)
5326 focusExposure->setValue(m_FilterManager->getFilterExposure(text));
5334void Focus::toggleVideo(
bool enabled)
5336 if (m_Camera ==
nullptr)
5339 if (m_Camera->isBLOBEnabled() ==
false)
5342 if (Options::guiderType() != Ekos::Guide::GUIDE_INTERNAL)
5343 m_Camera->setBLOBEnabled(
true);
5350 m_Camera->setVideoStreamEnabled(enabled);
5352 KSMessageBox::Instance()->questionYesNo(
i18n(
"Image transfer is disabled for this camera. Would you like to enable it?"));
5356 m_Camera->setVideoStreamEnabled(enabled);
5372void Focus::setVideoStreamEnabled(
bool enabled)
5376 liveVideoB->setChecked(
true);
5381 liveVideoB->setChecked(
false);
5386void Focus::processCaptureTimeout()
5388 m_captureInProgress =
false;
5390 if (m_abortInProgress)
5393 qCDebug(KSTARS_EKOS_FOCUS) <<
"Abort AF: discarding frame in " << __FUNCTION__;
5397 captureTimeoutCounter++;
5399 if (captureTimeoutCounter >= 3)
5401 captureTimeoutCounter = 0;
5402 m_MissingCameraCounter = 0;
5403 captureTimeout.stop();
5404 appendLogText(
i18n(
"Exposure timeout. Aborting..."));
5405 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_CAPTURE_TIMEOUT);
5409 appendLogText(
i18n(
"Exposure timeout. Restarting exposure..."));
5410 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
5411 targetChip->abortExposure();
5413 capture(focusExposure->value());
5417 else if (m_MissingCameraCounter < 40)
5419 m_MissingCameraCounter++;
5420 qCDebug(KSTARS_EKOS_FOCUS) <<
"Unable to restart focus exposure as camera is missing, trying again in 5 seconds...";
5425 m_MissingCameraCounter = 0;
5426 captureTimeoutCounter = 0;
5427 captureTimeout.stop();
5428 appendLogText(
i18n(
"Exposure timeout. Aborting..."));
5429 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_CAPTURE_TIMEOUT);
5434void Focus::processCaptureErrorDefault()
5436 processCaptureError(ISD::Camera::ERROR_CAPTURE);
5441 m_captureInProgress =
false;
5442 captureTimeout.stop();
5444 if (m_abortInProgress)
5446 qCDebug(KSTARS_EKOS_FOCUS) <<
"Abort AF: discarding frame in " << __FUNCTION__;
5452 appendLogText(
i18n(
"Failed to save image. Aborting..."));
5453 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_CAPTURE_FAILED);
5460 captureFailureCounter++;
5462 if (captureFailureCounter >= 3)
5464 captureFailureCounter = 0;
5465 captureTimeoutCounter = 0;
5466 m_MissingCameraCounter = 0;
5467 appendLogText(
i18n(
"Exposure failure. Aborting..."));
5468 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_CAPTURE_FAILED);
5472 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
5473 targetChip->abortExposure();
5474 capture(focusExposure->value());
5478 else if (m_MissingCameraCounter < 40)
5480 m_MissingCameraCounter++;
5481 qCDebug(KSTARS_EKOS_FOCUS) <<
"Unable to restart focus exposure as camera is missing, trying again in 5 seconds...";
5488 m_MissingCameraCounter = 0;
5489 captureFailureCounter = 0;
5490 captureTimeoutCounter = 0;
5491 captureTimeout.stop();
5492 appendLogText(
i18n(
"Exposure failure. Aborting..."));
5493 completeFocusProcedure(Ekos::FOCUS_ABORTED, Ekos::FOCUS_FAIL_CAPTURE_FAILED);
5497void Focus::syncSettings()
5510 if ( (dsb = qobject_cast<QDoubleSpinBox*>(sender())))
5513 value = dsb->
value();
5516 else if ( (sb = qobject_cast<QSpinBox*>(sender())))
5519 value = sb->
value();
5521 else if ( (cb = qobject_cast<QCheckBox*>(sender())))
5526 else if ( (gb = qobject_cast<QGroupBox*>(sender())))
5531 else if ( (rb = qobject_cast<QRadioButton*>(sender())))
5537 m_Settings.remove(key);
5542 else if ( (cbox = qobject_cast<QComboBox*>(sender())))
5547 else if ( (s = qobject_cast<QSplitter*>(sender())))
5555 Options::self()->setProperty(key.
toLatin1(), value);
5557 m_Settings[key] = value;
5558 m_GlobalSettings[key] = value;
5562 m_DebounceTimer.start();
5568void Focus::settleSettings()
5570 emit settingsUpdated(getAllSettings());
5572 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
5573 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::Focus, m_Settings);
5576void Focus::loadGlobalSettings()
5581 QVariantMap settings;
5583 for (
auto &oneWidget : findChildren<
QComboBox*>())
5585 if (oneWidget->objectName() ==
"opticalTrainCombo")
5588 key = oneWidget->objectName();
5589 value = Options::self()->property(key.
toLatin1());
5590 if (value.
isValid() && oneWidget->count() > 0)
5592 oneWidget->setCurrentText(value.
toString());
5593 settings[key] = value;
5596 qCDebug(KSTARS_EKOS_FOCUS) <<
"Option" << key <<
"not found!";
5602 key = oneWidget->objectName();
5603 value = Options::self()->property(key.
toLatin1());
5607 settings[key] = value;
5610 qCDebug(KSTARS_EKOS_FOCUS) <<
"Option" << key <<
"not found!";
5614 for (
auto &oneWidget : findChildren<
QSpinBox*>())
5616 key = oneWidget->objectName();
5617 value = Options::self()->property(key.
toLatin1());
5621 settings[key] = value;
5624 qCDebug(KSTARS_EKOS_FOCUS) <<
"Option" << key <<
"not found!";
5628 for (
auto &oneWidget : findChildren<
QCheckBox*>())
5630 key = oneWidget->objectName();
5631 value = Options::self()->property(key.
toLatin1());
5634 oneWidget->setChecked(value.
toBool());
5635 settings[key] = value;
5637 else if (key != forceInSeqAF->objectName())
5638 qCDebug(KSTARS_EKOS_FOCUS) <<
"Option" << key <<
"not found!";
5642 for (
auto &oneWidget : findChildren<
QGroupBox*>())
5644 if (oneWidget->isCheckable())
5646 key = oneWidget->objectName();
5647 value = Options::self()->property(key.
toLatin1());
5650 oneWidget->setChecked(value.
toBool());
5651 settings[key] = value;
5654 qCDebug(KSTARS_EKOS_FOCUS) <<
"Option" << key <<
"not found!";
5659 for (
auto &oneWidget : findChildren<
QSplitter*>())
5661 key = oneWidget->objectName();
5662 value = Options::self()->property(key.
toLatin1());
5667 oneWidget->restoreState(valueBA);
5668 settings[key] = valueBA;
5671 qCDebug(KSTARS_EKOS_FOCUS) <<
"Option" << key <<
"not found!";
5677 key = oneWidget->objectName();
5678 value = Options::self()->property(key.
toLatin1());
5681 oneWidget->setChecked(value.
toBool());
5682 settings[key] = value;
5687 m_GlobalSettings = m_Settings = settings;
5690void Focus::checkMosaicMaskLimits()
5692 if (m_Camera ==
nullptr || m_Camera->isConnected() ==
false)
5694 auto targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
5695 if (targetChip ==
nullptr || frameSettings.contains(targetChip) ==
false)
5697 auto settings = frameSettings[targetChip];
5700 auto width = settings[
"w"].toInt();
5701 auto height = settings[
"h"].toInt();
5702 if (width == 0 || height == 0)
5706 auto min = std::min(width, height);
5708 m_OpsFocusSettings->focusMosaicTileWidth->setMaximum(100 * min / (3 * width));
5711void Focus::connectSyncSettings()
5714 for (
auto &oneWidget : findChildren<
QComboBox*>())
5716 if (oneWidget != opticalTrainCombo)
5717 connect(oneWidget, QOverload<int>::of(&
QComboBox::activated), this, &
Ekos::Focus::syncSettings);
5724 for (
auto &oneWidget : findChildren<
QSpinBox*>())
5725 connect(oneWidget, QOverload<int>::of(&
QSpinBox::valueChanged), this, &
Ekos::Focus::syncSettings);
5728 for (
auto &oneWidget : findChildren<
QCheckBox*>())
5732 for (
auto &oneWidget : findChildren<
QGroupBox*>())
5733 if (oneWidget->isCheckable())
5737 for (
auto &oneWidget : findChildren<
QSplitter*>())
5745void Focus::disconnectSyncSettings()
5748 for (
auto &oneWidget : findChildren<
QComboBox*>())
5749 disconnect(oneWidget, QOverload<int>::of(&
QComboBox::activated), this, &
Ekos::Focus::syncSettings);
5753 disconnect(oneWidget, QOverload<double>::of(&
QDoubleSpinBox::valueChanged), this, &
Ekos::Focus::syncSettings);
5756 for (
auto &oneWidget : findChildren<
QSpinBox*>())
5757 disconnect(oneWidget, QOverload<int>::of(&
QSpinBox::valueChanged), this, &
Ekos::Focus::syncSettings);
5760 for (
auto &oneWidget : findChildren<
QCheckBox*>())
5761 disconnect(oneWidget, &
QCheckBox::toggled, this, &
Ekos::Focus::syncSettings);
5764 for (
auto &oneWidget : findChildren<
QGroupBox*>())
5765 if (oneWidget->isCheckable())
5766 disconnect(oneWidget, &
QGroupBox::toggled, this, &
Ekos::Focus::syncSettings);
5769 for (
auto &oneWidget : findChildren<
QSplitter*>())
5770 disconnect(oneWidget, &
QSplitter::splitterMoved, this, &
Ekos::Focus::syncSettings);
5774 disconnect(oneWidget, &
QRadioButton::toggled, this, &
Ekos::Focus::syncSettings);
5777void Focus::initPlots()
5781 profileDialog =
new QDialog(
this);
5784 profileDialog->setWindowTitle(
i18nc(
"@title:window",
"Relative Profile"));
5785 profilePlot =
new FocusProfilePlot(profileDialog);
5788 profileDialog->setLayout(profileLayout);
5789 profileDialog->resize(400, 300);
5792 connect(
this, &Ekos::Focus::newHFR, [
this](
double currentHFR,
int pos)
5794 Q_UNUSED(pos) profilePlot->drawProfilePlot(currentHFR);
5798void Focus::initConnections()
5801 waitStarSelectTimer.setInterval(AUTO_STAR_TIMEOUT);
5806 m_DebounceTimer.setInterval(500);
5807 m_DebounceTimer.setSingleShot(
true);
5822 captureTimer.setSingleShot(
true);
5829 captureTimeout.setSingleShot(
true);
5864 &Ekos::Focus::updateBoxSize);
5870 m_CFZDialog->show();
5871 m_CFZDialog->raise();
5877 focusAdvisor->setButtons(
false);
5878 focusAdvisor->show();
5879 focusAdvisor->raise();
5885 Options::setFocusForceInSeqAF(enabled);
5891 setFocusDetection(static_cast<StarAlgorithm>(index));
5897 setFocusAlgorithm(static_cast<Algorithm>(index));
5903 this, [&](
int index)
5905 setCurveFit(static_cast<CurveFitting::CurveFit>(index));
5910 this, [&](
int index)
5912 setStarMeasure(static_cast<StarMeasure>(index));
5917 this, [&](
int index)
5919 setStarPSF(static_cast<StarPSF>(index));
5924 this, [&](
int index)
5926 setStarUnits(static_cast<StarUnits>(index));
5931 this, [&](
int index)
5933 setWalk(static_cast<FocusWalk>(index));
5944 starCenter = QVector3D();
5945 starSelected = false;
5946 m_FocusView->setTrackingBox(QRect());
5954 &Ekos::Focus::calcCFZ);
5957 &Ekos::Focus::calcCFZ);
5998void Focus::setFocusDetection(StarAlgorithm starAlgorithm)
6000 static bool first =
true;
6001 if (!first && m_FocusDetection == starAlgorithm)
6006 m_FocusDetection = starAlgorithm;
6009 setFocusAlgorithm(m_FocusAlgorithm);
6011 if (m_FocusDetection == ALGORITHM_BAHTINOV)
6014 m_OpsFocusSettings->focusAutoStarEnabled->setChecked(
false);
6015 m_OpsFocusSettings->focusBoxSize->setMaximum(512);
6020 if (m_OpsFocusSettings->focusBoxSize->value() > 256)
6023 m_OpsFocusSettings->focusBoxSize->setValue(m_OpsFocusSettings->focusBoxSize->value());
6025 m_OpsFocusSettings->focusBoxSize->setMaximum(256);
6027 m_OpsFocusSettings->focusAutoStarEnabled->setEnabled(m_FocusDetection != ALGORITHM_BAHTINOV);
6031void Focus::setFocusAlgorithm(Algorithm algorithm)
6033 m_FocusAlgorithm = algorithm;
6036 case FOCUS_ITERATIVE:
6038 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusMultiRowAverageLabel);
6039 m_OpsFocusProcess->focusMultiRowAverageLabel->hide();
6040 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusMultiRowAverage);
6041 m_OpsFocusProcess->focusMultiRowAverage->hide();
6043 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusGaussianSigmaLabel);
6044 m_OpsFocusProcess->focusGaussianSigmaLabel->hide();
6045 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusGaussianSigma);
6046 m_OpsFocusProcess->focusGaussianSigma->hide();
6048 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusGaussianKernelSizeLabel);
6049 m_OpsFocusProcess->focusGaussianKernelSizeLabel->hide();
6050 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusGaussianKernelSize);
6051 m_OpsFocusProcess->focusGaussianKernelSize->hide();
6053 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusStarMeasureLabel);
6054 m_OpsFocusProcess->focusStarMeasureLabel->hide();
6055 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusStarMeasure);
6056 m_OpsFocusProcess->focusStarMeasure->hide();
6058 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusStarPSFLabel);
6059 m_OpsFocusProcess->focusStarPSFLabel->hide();
6060 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusStarPSF);
6061 m_OpsFocusProcess->focusStarPSF->hide();
6063 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusUseWeights);
6064 m_OpsFocusProcess->focusUseWeights->hide();
6066 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusR2LimitLabel);
6067 m_OpsFocusProcess->focusR2LimitLabel->hide();
6068 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusR2Limit);
6069 m_OpsFocusProcess->focusR2Limit->hide();
6071 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusRefineCurveFit);
6072 m_OpsFocusProcess->focusRefineCurveFit->hide();
6073 m_OpsFocusProcess->focusRefineCurveFit->setChecked(
false);
6075 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusToleranceLabel);
6076 m_OpsFocusProcess->focusToleranceLabel->hide();
6077 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusTolerance);
6078 m_OpsFocusProcess->focusTolerance->hide();
6080 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusThresholdLabel);
6081 m_OpsFocusProcess->focusThresholdLabel->hide();
6082 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusThreshold);
6083 m_OpsFocusProcess->focusThreshold->hide();
6085 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusCurveFitLabel);
6086 m_OpsFocusProcess->focusCurveFitLabel->hide();
6087 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusCurveFit);
6088 m_OpsFocusProcess->focusCurveFit->hide();
6091 m_OpsFocusProcess->focusDonut->hide();
6092 m_OpsFocusProcess->focusDonut->setChecked(
false);
6095 m_OpsFocusProcess->focusScanStartPos->hide();
6096 m_OpsFocusProcess->focusScanStartPos->setChecked(
false);
6099 m_OpsFocusProcess->focusCurveFit->setCurrentIndex(CurveFitting::FOCUS_QUADRATIC);
6102 if (m_OpsFocusProcess->focusStarMeasure->count() != 1)
6104 m_OpsFocusProcess->focusStarMeasure->clear();
6105 m_OpsFocusProcess->focusStarMeasure->addItem(m_StarMeasureText.at(FOCUS_STAR_HFR));
6106 m_OpsFocusProcess->focusStarMeasure->setCurrentIndex(FOCUS_STAR_HFR);
6110 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusToleranceLabel, 3, 0);
6111 m_OpsFocusProcess->focusToleranceLabel->show();
6112 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusTolerance, 3, 1);
6113 m_OpsFocusProcess->focusTolerance->show();
6115 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusFramesCountLabel, 3, 2);
6116 m_OpsFocusProcess->focusFramesCountLabel->show();
6117 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusFramesCount, 3, 3);
6118 m_OpsFocusProcess->focusFramesCount->show();
6120 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusHFRFramesCountLabel, 4, 2);
6121 m_OpsFocusProcess->focusHFRFramesCountLabel->show();
6122 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusHFRFramesCount, 4, 3);
6123 m_OpsFocusProcess->focusHFRFramesCount->show();
6125 if (m_FocusDetection == ALGORITHM_THRESHOLD)
6127 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusThresholdLabel, 5, 0);
6128 m_OpsFocusProcess->focusThresholdLabel->show();
6129 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusThreshold, 5, 1);
6130 m_OpsFocusProcess->focusThreshold->show();
6132 else if (m_FocusDetection == ALGORITHM_BAHTINOV)
6134 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusMultiRowAverageLabel, 5, 0);
6135 m_OpsFocusProcess->focusMultiRowAverageLabel->show();
6136 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusMultiRowAverage, 5, 1);
6137 m_OpsFocusProcess->focusMultiRowAverage->show();
6139 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusGaussianSigmaLabel, 5, 2);
6140 m_OpsFocusProcess->focusGaussianSigmaLabel->show();
6141 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusGaussianSigma, 5, 3);
6142 m_OpsFocusProcess->focusGaussianSigma->show();
6144 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusGaussianKernelSizeLabel, 6, 0);
6145 m_OpsFocusProcess->focusGaussianKernelSizeLabel->show();
6146 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusGaussianKernelSize, 6, 1);
6147 m_OpsFocusProcess->focusGaussianKernelSize->show();
6151 startAbInsB->setEnabled(canAbInsStart());
6155 m_OpsFocusSettings->focusAdaptive->setChecked(
false);
6156 m_OpsFocusSettings->focusAdaptStart->setChecked(
false);
6157 m_OpsFocusSettings->adaptiveFocusGroup->setEnabled(
false);
6160 m_OpsFocusMechanics->focusMaxSingleStep->setEnabled(
true);
6161 m_OpsFocusMechanics->focusOutSteps->setEnabled(
false);
6164 if (m_OpsFocusMechanics->focusWalk->count() != 1)
6166 m_OpsFocusMechanics->focusWalk->clear();
6167 m_OpsFocusMechanics->focusWalk->addItem(m_FocusWalkText.at(FOCUS_WALK_CLASSIC));
6168 m_OpsFocusMechanics->focusWalk->setCurrentIndex(FOCUS_WALK_CLASSIC);
6172 case FOCUS_POLYNOMIAL:
6174 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusMultiRowAverageLabel);
6175 m_OpsFocusProcess->focusMultiRowAverageLabel->hide();
6176 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusMultiRowAverage);
6177 m_OpsFocusProcess->focusMultiRowAverage->hide();
6179 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusGaussianSigmaLabel);
6180 m_OpsFocusProcess->focusGaussianSigmaLabel->hide();
6181 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusGaussianSigma);
6182 m_OpsFocusProcess->focusGaussianSigma->hide();
6184 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusGaussianKernelSizeLabel);
6185 m_OpsFocusProcess->focusGaussianKernelSizeLabel->hide();
6186 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusGaussianKernelSize);
6187 m_OpsFocusProcess->focusGaussianKernelSize->hide();
6189 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusStarPSFLabel);
6190 m_OpsFocusProcess->focusStarPSFLabel->hide();
6191 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusStarPSF);
6192 m_OpsFocusProcess->focusStarPSF->hide();
6194 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusUseWeights);
6195 m_OpsFocusProcess->focusUseWeights->hide();
6197 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusR2LimitLabel);
6198 m_OpsFocusProcess->focusR2LimitLabel->hide();
6199 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusR2Limit);
6200 m_OpsFocusProcess->focusR2Limit->hide();
6202 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusRefineCurveFit);
6203 m_OpsFocusProcess->focusRefineCurveFit->hide();
6204 m_OpsFocusProcess->focusRefineCurveFit->setChecked(
false);
6206 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusToleranceLabel);
6207 m_OpsFocusProcess->focusToleranceLabel->hide();
6208 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusTolerance);
6209 m_OpsFocusProcess->focusTolerance->hide();
6211 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusThresholdLabel);
6212 m_OpsFocusProcess->focusThresholdLabel->hide();
6213 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusThreshold);
6214 m_OpsFocusProcess->focusThreshold->hide();
6217 m_OpsFocusProcess->focusDonut->hide();
6218 m_OpsFocusProcess->focusDonut->setChecked(
false);
6221 m_OpsFocusProcess->focusScanStartPos->hide();
6222 m_OpsFocusProcess->focusScanStartPos->setChecked(
false);
6225 if (m_OpsFocusProcess->focusStarMeasure->count() != 1)
6227 m_OpsFocusProcess->focusStarMeasure->clear();
6228 m_OpsFocusProcess->focusStarMeasure->addItem(m_StarMeasureText.at(FOCUS_STAR_HFR));
6229 m_OpsFocusProcess->focusStarMeasure->setCurrentIndex(FOCUS_STAR_HFR);
6234 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusCurveFitLabel, 1, 2);
6235 m_OpsFocusProcess->focusCurveFitLabel->show();
6236 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusCurveFit, 1, 3);
6237 m_OpsFocusProcess->focusCurveFit->show();
6238 if (m_OpsFocusProcess->focusCurveFit->count() != 1)
6240 m_OpsFocusProcess->focusCurveFit->clear();
6241 m_OpsFocusProcess->focusCurveFit->addItem(m_CurveFitText.at(CurveFitting::FOCUS_QUADRATIC));
6242 m_OpsFocusProcess->focusCurveFit->setCurrentIndex(CurveFitting::FOCUS_QUADRATIC);
6245 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusToleranceLabel, 3, 0);
6246 m_OpsFocusProcess->focusToleranceLabel->show();
6247 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusTolerance, 3, 1);
6248 m_OpsFocusProcess->focusTolerance->show();
6250 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusFramesCountLabel, 3, 2);
6251 m_OpsFocusProcess->focusFramesCountLabel->show();
6252 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusFramesCount, 3, 3);
6253 m_OpsFocusProcess->focusFramesCount->show();
6255 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusHFRFramesCountLabel, 4, 2);
6256 m_OpsFocusProcess->focusHFRFramesCountLabel->show();
6257 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusHFRFramesCount, 4, 3);
6258 m_OpsFocusProcess->focusHFRFramesCount->show();
6260 if (m_FocusDetection == ALGORITHM_THRESHOLD)
6262 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusThresholdLabel, 5, 0);
6263 m_OpsFocusProcess->focusThresholdLabel->show();
6264 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusThreshold, 5, 1);
6265 m_OpsFocusProcess->focusThreshold->show();
6267 else if (m_FocusDetection == ALGORITHM_BAHTINOV)
6269 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusMultiRowAverageLabel, 5, 0);
6270 m_OpsFocusProcess->focusMultiRowAverageLabel->show();
6271 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusMultiRowAverage, 5, 1);
6272 m_OpsFocusProcess->focusMultiRowAverage->show();
6274 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusGaussianSigmaLabel, 5, 2);
6275 m_OpsFocusProcess->focusGaussianSigmaLabel->show();
6276 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusGaussianSigma, 5, 3);
6277 m_OpsFocusProcess->focusGaussianSigma->show();
6279 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusGaussianKernelSizeLabel, 6, 0);
6280 m_OpsFocusProcess->focusGaussianKernelSizeLabel->show();
6281 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusGaussianKernelSize, 6, 1);
6282 m_OpsFocusProcess->focusGaussianKernelSize->show();
6286 startAbInsB->setEnabled(canAbInsStart());
6290 m_OpsFocusSettings->focusAdaptive->setChecked(
false);
6291 m_OpsFocusSettings->focusAdaptStart->setChecked(
false);
6292 m_OpsFocusSettings->adaptiveFocusGroup->setEnabled(
false);
6295 m_OpsFocusMechanics->focusMaxSingleStep->setEnabled(
true);
6296 m_OpsFocusMechanics->focusOutSteps->setEnabled(
false);
6299 if (m_OpsFocusMechanics->focusWalk->count() != 1)
6301 m_OpsFocusMechanics->focusWalk->clear();
6302 m_OpsFocusMechanics->focusWalk->addItem(m_FocusWalkText.at(FOCUS_WALK_CLASSIC));
6303 m_OpsFocusMechanics->focusWalk->setCurrentIndex(FOCUS_WALK_CLASSIC);
6309 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusMultiRowAverageLabel);
6310 m_OpsFocusProcess->focusMultiRowAverageLabel->hide();
6311 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusMultiRowAverage);
6312 m_OpsFocusProcess->focusMultiRowAverage->hide();
6314 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusGaussianSigmaLabel);
6315 m_OpsFocusProcess->focusGaussianSigmaLabel->hide();
6316 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusGaussianSigma);
6317 m_OpsFocusProcess->focusGaussianSigma->hide();
6319 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusGaussianKernelSizeLabel);
6320 m_OpsFocusProcess->focusGaussianKernelSizeLabel->hide();
6321 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusGaussianKernelSize);
6322 m_OpsFocusProcess->focusGaussianKernelSize->hide();
6324 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusThresholdLabel);
6325 m_OpsFocusProcess->focusThresholdLabel->hide();
6326 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusThreshold);
6327 m_OpsFocusProcess->focusThreshold->hide();
6329 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusStarPSFLabel);
6330 m_OpsFocusProcess->focusStarPSFLabel->hide();
6331 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusStarPSF);
6332 m_OpsFocusProcess->focusStarPSF->hide();
6334 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusUseWeights);
6335 m_OpsFocusProcess->focusUseWeights->hide();
6337 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusR2LimitLabel);
6338 m_OpsFocusProcess->focusR2LimitLabel->hide();
6339 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusR2Limit);
6340 m_OpsFocusProcess->focusR2Limit->hide();
6342 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusRefineCurveFit);
6343 m_OpsFocusProcess->focusRefineCurveFit->hide();
6344 m_OpsFocusProcess->focusRefineCurveFit->setChecked(
false);
6347 m_OpsFocusProcess->focusDonut->hide();
6348 m_OpsFocusProcess->focusDonut->setChecked(
false);
6351 m_OpsFocusProcess->focusScanStartPos->hide();
6352 m_OpsFocusProcess->focusScanStartPos->setChecked(
false);
6355 if (m_OpsFocusProcess->focusStarMeasure->count() != 1)
6357 m_OpsFocusProcess->focusStarMeasure->clear();
6358 m_OpsFocusProcess->focusStarMeasure->addItem(m_StarMeasureText.at(FOCUS_STAR_HFR));
6359 m_OpsFocusProcess->focusStarMeasure->setCurrentIndex(FOCUS_STAR_HFR);
6364 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusCurveFitLabel, 1, 2);
6365 m_OpsFocusProcess->focusCurveFitLabel->show();
6366 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusCurveFit, 1, 3);
6367 m_OpsFocusProcess->focusCurveFit->show();
6368 if (m_OpsFocusProcess->focusCurveFit->count() != 1)
6370 m_OpsFocusProcess->focusCurveFit->clear();
6371 m_OpsFocusProcess->focusCurveFit->addItem(m_CurveFitText.at(CurveFitting::FOCUS_QUADRATIC));
6372 m_OpsFocusProcess->focusCurveFit->setCurrentIndex(CurveFitting::FOCUS_QUADRATIC);
6375 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusToleranceLabel, 3, 0);
6376 m_OpsFocusProcess->focusToleranceLabel->show();
6377 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusTolerance, 3, 1);
6378 m_OpsFocusProcess->focusTolerance->show();
6380 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusFramesCountLabel, 3, 2);
6381 m_OpsFocusProcess->focusFramesCountLabel->show();
6382 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusFramesCount, 3, 3);
6383 m_OpsFocusProcess->focusFramesCount->show();
6385 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusHFRFramesCountLabel, 4, 2);
6386 m_OpsFocusProcess->focusHFRFramesCountLabel->show();
6387 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusHFRFramesCount, 4, 3);
6388 m_OpsFocusProcess->focusHFRFramesCount->show();
6390 if (m_FocusDetection == ALGORITHM_THRESHOLD)
6392 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusThresholdLabel, 5, 0);
6393 m_OpsFocusProcess->focusThresholdLabel->show();
6394 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusThreshold, 5, 1);
6395 m_OpsFocusProcess->focusThreshold->show();
6397 else if (m_FocusDetection == ALGORITHM_BAHTINOV)
6399 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusMultiRowAverageLabel, 5, 0);
6400 m_OpsFocusProcess->focusMultiRowAverageLabel->show();
6401 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusMultiRowAverage, 5, 1);
6402 m_OpsFocusProcess->focusMultiRowAverage->show();
6404 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusGaussianSigmaLabel, 5, 2);
6405 m_OpsFocusProcess->focusGaussianSigmaLabel->show();
6406 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusGaussianSigma, 5, 3);
6407 m_OpsFocusProcess->focusGaussianSigma->show();
6409 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusGaussianKernelSizeLabel, 6, 0);
6410 m_OpsFocusProcess->focusGaussianKernelSizeLabel->show();
6411 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusGaussianKernelSize, 6, 1);
6412 m_OpsFocusProcess->focusGaussianKernelSize->show();
6416 startAbInsB->setEnabled(canAbInsStart());
6420 m_OpsFocusSettings->focusAdaptive->setChecked(
false);
6421 m_OpsFocusSettings->focusAdaptStart->setChecked(
false);
6422 m_OpsFocusSettings->adaptiveFocusGroup->setEnabled(
false);
6425 m_OpsFocusMechanics->focusMaxSingleStep->setEnabled(
false);
6426 m_OpsFocusMechanics->focusOutSteps->setEnabled(
true);
6429 if (m_OpsFocusMechanics->focusWalk->count() != 1)
6431 m_OpsFocusMechanics->focusWalk->clear();
6432 m_OpsFocusMechanics->focusWalk->addItem(m_FocusWalkText.at(FOCUS_WALK_CLASSIC));
6433 m_OpsFocusMechanics->focusWalk->setCurrentIndex(FOCUS_WALK_CLASSIC);
6437 case FOCUS_LINEAR1PASS:
6439 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusMultiRowAverageLabel);
6440 m_OpsFocusProcess->focusMultiRowAverageLabel->hide();
6441 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusMultiRowAverage);
6442 m_OpsFocusProcess->focusMultiRowAverage->hide();
6444 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusGaussianSigmaLabel);
6445 m_OpsFocusProcess->focusGaussianSigmaLabel->hide();
6446 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusGaussianSigma);
6447 m_OpsFocusProcess->focusGaussianSigma->hide();
6449 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusGaussianKernelSizeLabel);
6450 m_OpsFocusProcess->focusGaussianKernelSizeLabel->hide();
6451 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusGaussianKernelSize);
6452 m_OpsFocusProcess->focusGaussianKernelSize->hide();
6454 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusThresholdLabel);
6455 m_OpsFocusProcess->focusThresholdLabel->hide();
6456 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusThreshold);
6457 m_OpsFocusProcess->focusThreshold->hide();
6459 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusToleranceLabel);
6460 m_OpsFocusProcess->focusToleranceLabel->hide();
6461 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusTolerance);
6462 m_OpsFocusProcess->focusTolerance->hide();
6466 if (m_FocusDetection == ALGORITHM_SEP && m_CurveFit != CurveFitting::FOCUS_QUADRATIC)
6468 if (m_OpsFocusProcess->focusStarMeasure->count() != m_StarMeasureText.count())
6470 m_OpsFocusProcess->focusStarMeasure->clear();
6471 m_OpsFocusProcess->focusStarMeasure->addItems(m_StarMeasureText);
6472 m_OpsFocusProcess->focusStarMeasure->setCurrentIndex(FOCUS_STAR_HFR);
6475 else if (m_FocusDetection != ALGORITHM_SEP || m_CurveFit == CurveFitting::FOCUS_QUADRATIC)
6477 if (m_OpsFocusProcess->focusStarMeasure->count() != 1)
6479 m_OpsFocusProcess->focusStarMeasure->clear();
6480 m_OpsFocusProcess->focusStarMeasure->addItem(m_StarMeasureText.at(FOCUS_STAR_HFR));
6481 m_OpsFocusProcess->focusStarMeasure->setCurrentIndex(FOCUS_STAR_HFR);
6487 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusCurveFitLabel, 1, 2);
6488 m_OpsFocusProcess->focusCurveFitLabel->show();
6489 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusCurveFit, 1, 3);
6490 m_OpsFocusProcess->focusCurveFit->show();
6491 if (m_OpsFocusProcess->focusCurveFit->count() != m_CurveFitText.count())
6493 m_OpsFocusProcess->focusCurveFit->clear();
6494 m_OpsFocusProcess->focusCurveFit->addItems(m_CurveFitText);
6495 m_OpsFocusProcess->focusCurveFit->setCurrentIndex(CurveFitting::FOCUS_HYPERBOLA);
6498 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusUseWeights, 3, 0, 1, 2);
6499 m_OpsFocusProcess->focusUseWeights->show();
6501 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusR2LimitLabel, 3, 2);
6502 m_OpsFocusProcess->focusR2LimitLabel->show();
6503 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusR2Limit, 3, 3);
6504 m_OpsFocusProcess->focusR2Limit->show();
6506 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusRefineCurveFit, 4, 0, 1, 2);
6507 m_OpsFocusProcess->focusRefineCurveFit->show();
6509 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusFramesCountLabel, 4, 2);
6510 m_OpsFocusProcess->focusFramesCountLabel->show();
6511 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusFramesCount, 4, 3);
6512 m_OpsFocusProcess->focusFramesCount->show();
6514 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusHFRFramesCountLabel, 5, 2);
6515 m_OpsFocusProcess->focusHFRFramesCountLabel->show();
6516 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusHFRFramesCount, 5, 3);
6517 m_OpsFocusProcess->focusHFRFramesCount->show();
6519 if (m_FocusDetection == ALGORITHM_THRESHOLD)
6521 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusThresholdLabel, 6, 0);
6522 m_OpsFocusProcess->focusThresholdLabel->show();
6523 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusThreshold, 6, 1);
6524 m_OpsFocusProcess->focusThreshold->show();
6526 else if (m_FocusDetection == ALGORITHM_BAHTINOV)
6528 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusMultiRowAverageLabel, 6, 0);
6529 m_OpsFocusProcess->focusMultiRowAverageLabel->show();
6530 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusMultiRowAverage, 6, 1);
6531 m_OpsFocusProcess->focusMultiRowAverage->show();
6533 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusGaussianSigmaLabel, 6, 2);
6534 m_OpsFocusProcess->focusGaussianSigmaLabel->show();
6535 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusGaussianSigma, 6, 3);
6536 m_OpsFocusProcess->focusGaussianSigma->show();
6538 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusGaussianKernelSizeLabel, 7, 0);
6539 m_OpsFocusProcess->focusGaussianKernelSizeLabel->show();
6540 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusGaussianKernelSize, 7, 1);
6541 m_OpsFocusProcess->focusGaussianKernelSize->show();
6545 m_OpsFocusProcess->focusDonut->show();
6546 m_OpsFocusProcess->focusDonut->setEnabled(
true);
6549 m_OpsFocusProcess->focusScanStartPos->show();
6550 m_OpsFocusProcess->focusScanStartPos->setEnabled(
true);
6553 startAbInsB->setEnabled(canAbInsStart());
6557 m_OpsFocusSettings->adaptiveFocusGroup->setEnabled(canAbsMove);
6561 m_OpsFocusMechanics->focusMaxSingleStep->setEnabled(
false);
6562 m_OpsFocusMechanics->focusOutSteps->setEnabled(
true);
6565 if (m_CurveFit == CurveFitting::FOCUS_QUADRATIC)
6567 if (m_OpsFocusMechanics->focusWalk->count() != 1)
6569 m_OpsFocusMechanics->focusWalk->clear();
6570 m_OpsFocusMechanics->focusWalk->addItem(m_FocusWalkText.at(FOCUS_WALK_CLASSIC));
6571 m_OpsFocusMechanics->focusWalk->setCurrentIndex(FOCUS_WALK_CLASSIC);
6576 if (m_OpsFocusMechanics->focusWalk->count() != m_FocusWalkText.count())
6578 m_OpsFocusMechanics->focusWalk->clear();
6579 m_OpsFocusMechanics->focusWalk->addItems(m_FocusWalkText);
6580 m_OpsFocusMechanics->focusWalk->setCurrentIndex(FOCUS_WALK_CLASSIC);
6587void Focus::setCurveFit(CurveFitting::CurveFit curve)
6589 if (m_OpsFocusProcess->focusCurveFit->currentIndex() == -1)
6592 static bool first =
true;
6593 if (!first && m_CurveFit == curve)
6599 setFocusAlgorithm(
static_cast<Algorithm
> (m_OpsFocusProcess->focusAlgorithm->currentIndex()));
6605 case CurveFitting::FOCUS_QUADRATIC:
6606 m_OpsFocusProcess->focusR2Limit->setEnabled(
false);
6607 m_OpsFocusProcess->focusRefineCurveFit->setChecked(
false);
6608 m_OpsFocusProcess->focusRefineCurveFit->setEnabled(
false);
6611 case CurveFitting::FOCUS_HYPERBOLA:
6612 m_OpsFocusProcess->focusR2Limit->setEnabled(
true);
6613 m_OpsFocusProcess->focusRefineCurveFit->setEnabled(
true);
6616 case CurveFitting::FOCUS_PARABOLA:
6617 m_OpsFocusProcess->focusR2Limit->setEnabled(
true);
6618 m_OpsFocusProcess->focusRefineCurveFit->setEnabled(
true);
6626void Focus::setStarMeasure(StarMeasure starMeasure)
6628 if (m_OpsFocusProcess->focusStarMeasure->currentIndex() == -1)
6631 static bool first =
true;
6632 if (!first && m_StarMeasure == starMeasure)
6637 m_StarMeasure = starMeasure;
6638 setFocusAlgorithm(
static_cast<Algorithm
> (m_OpsFocusProcess->focusAlgorithm->currentIndex()));
6646 switch(m_StarMeasure)
6648 case FOCUS_STAR_HFR:
6649 m_OptDir = CurveFitting::OPTIMISATION_MINIMISE;
6650 m_ScaleCalc = Mathematics::RobustStatistics::ScaleCalculation::SCALE_SESTIMATOR;
6651 m_FocusView->setStarsHFREnabled(
true);
6654 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusStarPSFLabel);
6655 m_OpsFocusProcess->focusStarPSFLabel->hide();
6656 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusStarPSF);
6657 m_OpsFocusProcess->focusStarPSF->hide();
6660 case FOCUS_STAR_HFR_ADJ:
6661 m_OptDir = CurveFitting::OPTIMISATION_MINIMISE;
6662 m_ScaleCalc = Mathematics::RobustStatistics::ScaleCalculation::SCALE_SESTIMATOR;
6663 m_FocusView->setStarsHFREnabled(
false);
6666 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusStarPSFLabel);
6667 m_OpsFocusProcess->focusStarPSFLabel->hide();
6668 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusStarPSF);
6669 m_OpsFocusProcess->focusStarPSF->hide();
6672 case FOCUS_STAR_FWHM:
6673 m_OptDir = CurveFitting::OPTIMISATION_MINIMISE;
6674 m_ScaleCalc = Mathematics::RobustStatistics::ScaleCalculation::SCALE_SESTIMATOR;
6676 m_FocusView->setStarsHFREnabled(
false);
6679 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusStarPSFLabel, 2, 2);
6680 m_OpsFocusProcess->focusStarPSFLabel->show();
6681 m_OpsFocusProcess->gridLayoutProcess->addWidget(m_OpsFocusProcess->focusStarPSF, 2, 3);
6682 m_OpsFocusProcess->focusStarPSF->show();
6685 case FOCUS_STAR_NUM_STARS:
6686 m_OptDir = CurveFitting::OPTIMISATION_MAXIMISE;
6687 m_ScaleCalc = Mathematics::RobustStatistics::ScaleCalculation::SCALE_SESTIMATOR;
6688 m_FocusView->setStarsHFREnabled(
true);
6691 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusStarPSFLabel);
6692 m_OpsFocusProcess->focusStarPSFLabel->hide();
6693 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusStarPSF);
6694 m_OpsFocusProcess->focusStarPSF->hide();
6697 case FOCUS_STAR_FOURIER_POWER:
6698 m_OptDir = CurveFitting::OPTIMISATION_MAXIMISE;
6699 m_ScaleCalc = Mathematics::RobustStatistics::ScaleCalculation::SCALE_SESTIMATOR;
6700 m_FocusView->setStarsHFREnabled(
true);
6703 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusStarPSFLabel);
6704 m_OpsFocusProcess->focusStarPSFLabel->hide();
6705 m_OpsFocusProcess->gridLayoutProcess->removeWidget(m_OpsFocusProcess->focusStarPSF);
6706 m_OpsFocusProcess->focusStarPSF->hide();
6714void Focus::setStarPSF(StarPSF starPSF)
6716 m_StarPSF = starPSF;
6719void Focus::setStarUnits(StarUnits starUnits)
6721 m_StarUnits = starUnits;
6724void Focus::setWalk(FocusWalk walk)
6726 if (m_OpsFocusMechanics->focusWalk->currentIndex() == -1)
6729 static bool first =
true;
6730 if (!first && m_FocusWalk == walk)
6739 case FOCUS_WALK_CLASSIC:
6740 m_OpsFocusMechanics->gridLayoutMechanics->replaceWidget(m_OpsFocusMechanics->focusNumStepsLabel,
6741 m_OpsFocusMechanics->focusOutStepsLabel);
6742 m_OpsFocusMechanics->focusNumStepsLabel->hide();
6743 m_OpsFocusMechanics->focusOutStepsLabel->show();
6744 m_OpsFocusMechanics->gridLayoutMechanics->replaceWidget(m_OpsFocusMechanics->focusNumSteps,
6745 m_OpsFocusMechanics->focusOutSteps);
6746 m_OpsFocusMechanics->focusNumSteps->hide();
6747 m_OpsFocusMechanics->focusOutSteps->show();
6750 case FOCUS_WALK_FIXED_STEPS:
6751 case FOCUS_WALK_CFZ_SHUFFLE:
6752 m_OpsFocusMechanics->gridLayoutMechanics->replaceWidget(m_OpsFocusMechanics->focusOutStepsLabel,
6753 m_OpsFocusMechanics->focusNumStepsLabel);
6754 m_OpsFocusMechanics->focusOutStepsLabel->hide();
6755 m_OpsFocusMechanics->focusNumStepsLabel->show();
6756 m_OpsFocusMechanics->gridLayoutMechanics->replaceWidget(m_OpsFocusMechanics->focusOutSteps,
6757 m_OpsFocusMechanics->focusNumSteps);
6758 m_OpsFocusMechanics->focusOutSteps->hide();
6759 m_OpsFocusMechanics->focusNumSteps->show();
6768double Focus::getStarUnits(
const StarMeasure starMeasure,
const StarUnits starUnits)
6770 if (starUnits == FOCUS_UNITS_PIXEL || starMeasure == FOCUS_STAR_NUM_STARS || starMeasure == FOCUS_STAR_FOURIER_POWER)
6772 if (m_CcdPixelSizeX <= 0.0 || m_FocalLength <= 0.0)
6776 return m_CcdPixelSizeX / m_FocalLength * 206.265;
6779void Focus::calcCFZ()
6781 double cfzMicrons, cfzSteps;
6782 double cfzCameraSteps = calcCameraCFZ() / m_CFZUI->focusCFZStepSize->value();
6784 switch(
static_cast<Focus::CFZAlgorithm
> (m_CFZUI->focusCFZAlgorithm->currentIndex()))
6786 case Focus::FOCUS_CFZ_CLASSIC:
6788 cfzMicrons = 4.88f * m_CFZUI->focusCFZTolerance->value() * m_CFZUI->focusCFZWavelength->value() / 1000.0f *
6789 pow(m_CFZUI->focusCFZFNumber->value(), 2.0f);
6790 cfzSteps = cfzMicrons / m_CFZUI->focusCFZStepSize->value();
6791 m_cfzSteps = std::round(std::max(cfzSteps, cfzCameraSteps));
6792 m_CFZUI->focusCFZFormula->setText(
"CFZ = 4.88 t λ f²");
6793 m_CFZUI->focusCFZ->setText(
QString(
"%1 μm").arg(cfzMicrons, 0,
'f', 0));
6794 m_CFZUI->focusCFZSteps->setText(
QString(
"%1 steps").arg(cfzSteps, 0,
'f', 0));
6795 m_CFZUI->focusCFZCameraSteps->setText(
QString(
"%1 steps").arg(cfzCameraSteps, 0,
'f', 0));
6796 m_CFZUI->focusCFZFinal->setText(
QString(
"%1 steps").arg(m_cfzSteps, 0,
'f', 0));
6799 m_CFZUI->gridLayoutCFZ->removeWidget(m_CFZUI->focusCFZTauLabel);
6800 m_CFZUI->focusCFZTauLabel->hide();
6801 m_CFZUI->gridLayoutCFZ->removeWidget(m_CFZUI->focusCFZTau);
6802 m_CFZUI->focusCFZTau->hide();
6803 m_CFZUI->gridLayoutCFZ->removeWidget(m_CFZUI->focusCFZSeeingLabel);
6804 m_CFZUI->focusCFZSeeingLabel->hide();
6805 m_CFZUI->gridLayoutCFZ->removeWidget(m_CFZUI->focusCFZSeeing);
6806 m_CFZUI->focusCFZSeeing->hide();
6809 m_CFZUI->gridLayoutCFZ->addWidget(m_CFZUI->focusCFZToleranceLabel, 1, 0);
6810 m_CFZUI->focusCFZToleranceLabel->show();
6811 m_CFZUI->gridLayoutCFZ->addWidget(m_CFZUI->focusCFZTolerance, 1, 1);
6812 m_CFZUI->focusCFZTolerance->show();
6813 m_CFZUI->gridLayoutCFZ->addWidget(m_CFZUI->focusCFZWavelengthLabel, 2, 0);
6814 m_CFZUI->focusCFZWavelengthLabel->show();
6815 m_CFZUI->gridLayoutCFZ->addWidget(m_CFZUI->focusCFZWavelength, 2, 1);
6816 m_CFZUI->focusCFZWavelength->show();
6819 case Focus::FOCUS_CFZ_WAVEFRONT:
6821 cfzMicrons = 4.0f * m_CFZUI->focusCFZTolerance->value() * m_CFZUI->focusCFZWavelength->value() / 1000.0f * pow(
6822 m_CFZUI->focusCFZFNumber->value(),
6824 cfzSteps = cfzMicrons / m_CFZUI->focusCFZStepSize->value();
6825 m_cfzSteps = std::round(std::max(cfzSteps, cfzCameraSteps));
6826 m_CFZUI->focusCFZFormula->setText(
"CFZ = 4 t λ f²");
6827 m_CFZUI->focusCFZ->setText(
QString(
"%1 μm").arg(cfzMicrons, 0,
'f', 0));
6828 m_CFZUI->focusCFZSteps->setText(
QString(
"%1 steps").arg(cfzSteps, 0,
'f', 0));
6829 m_CFZUI->focusCFZCameraSteps->setText(
QString(
"%1 steps").arg(cfzCameraSteps, 0,
'f', 0));
6830 m_CFZUI->focusCFZFinal->setText(
QString(
"%1 steps").arg(m_cfzSteps, 0,
'f', 0));
6833 m_CFZUI->gridLayoutCFZ->removeWidget(m_CFZUI->focusCFZTauLabel);
6834 m_CFZUI->focusCFZTauLabel->hide();
6835 m_CFZUI->gridLayoutCFZ->removeWidget(m_CFZUI->focusCFZTau);
6836 m_CFZUI->focusCFZTau->hide();
6837 m_CFZUI->gridLayoutCFZ->removeWidget(m_CFZUI->focusCFZSeeingLabel);
6838 m_CFZUI->focusCFZSeeingLabel->hide();
6839 m_CFZUI->gridLayoutCFZ->removeWidget(m_CFZUI->focusCFZSeeing);
6840 m_CFZUI->focusCFZSeeing->hide();
6843 m_CFZUI->gridLayoutCFZ->addWidget(m_CFZUI->focusCFZToleranceLabel, 1, 0);
6844 m_CFZUI->focusCFZToleranceLabel->show();
6845 m_CFZUI->gridLayoutCFZ->addWidget(m_CFZUI->focusCFZTolerance, 1, 1);
6846 m_CFZUI->focusCFZTolerance->show();
6847 m_CFZUI->gridLayoutCFZ->addWidget(m_CFZUI->focusCFZWavelengthLabel, 2, 0);
6848 m_CFZUI->focusCFZWavelengthLabel->show();
6849 m_CFZUI->gridLayoutCFZ->addWidget(m_CFZUI->focusCFZWavelength, 2, 1);
6850 m_CFZUI->focusCFZWavelength->show();
6853 case Focus::FOCUS_CFZ_GOLD:
6855 cfzMicrons = 0.00225f * pow(m_CFZUI->focusCFZTau->value(), 0.5f) * m_CFZUI->focusCFZSeeing->value()
6856 * pow(m_CFZUI->focusCFZFNumber->value(), 2.0f) * m_CFZUI->focusCFZAperture->value();
6857 cfzSteps = cfzMicrons / m_CFZUI->focusCFZStepSize->value();
6858 m_cfzSteps = std::round(std::max(cfzSteps, cfzCameraSteps));
6859 m_CFZUI->focusCFZFormula->setText(
"CFZ = 0.00225 √τ θ f² A");
6860 m_CFZUI->focusCFZ->setText(
QString(
"%1 μm").arg(cfzMicrons, 0,
'f', 0));
6861 m_CFZUI->focusCFZSteps->setText(
QString(
"%1 steps").arg(cfzSteps, 0,
'f', 0));
6862 m_CFZUI->focusCFZCameraSteps->setText(
QString(
"%1 steps").arg(cfzCameraSteps, 0,
'f', 0));
6863 m_CFZUI->focusCFZFinal->setText(
QString(
"%1 steps").arg(m_cfzSteps, 0,
'f', 0));
6866 m_CFZUI->gridLayoutCFZ->removeWidget(m_CFZUI->focusCFZToleranceLabel);
6867 m_CFZUI->focusCFZToleranceLabel->hide();
6868 m_CFZUI->gridLayoutCFZ->removeWidget(m_CFZUI->focusCFZTolerance);
6869 m_CFZUI->focusCFZTolerance->hide();
6870 m_CFZUI->gridLayoutCFZ->removeWidget(m_CFZUI->focusCFZWavelengthLabel);
6871 m_CFZUI->focusCFZWavelengthLabel->hide();
6872 m_CFZUI->gridLayoutCFZ->removeWidget(m_CFZUI->focusCFZWavelength);
6873 m_CFZUI->focusCFZWavelength->hide();
6876 m_CFZUI->gridLayoutCFZ->addWidget(m_CFZUI->focusCFZTauLabel, 1, 0);
6877 m_CFZUI->focusCFZTauLabel->show();
6878 m_CFZUI->gridLayoutCFZ->addWidget(m_CFZUI->focusCFZTau, 1, 1);
6879 m_CFZUI->focusCFZTau->show();
6880 m_CFZUI->gridLayoutCFZ->addWidget(m_CFZUI->focusCFZSeeingLabel, 2, 0);
6881 m_CFZUI->focusCFZSeeingLabel->show();
6882 m_CFZUI->gridLayoutCFZ->addWidget(m_CFZUI->focusCFZSeeing, 2, 1);
6883 m_CFZUI->focusCFZSeeing->show();
6886 if (linearFocuser !=
nullptr && linearFocuser->isDone())
6887 emit drawCFZ(linearFocuser->solution(), linearFocuser->solutionValue(), m_cfzSteps,
6888 m_CFZUI->focusCFZDisplayVCurve->isChecked());
6894double Focus::calcCameraCFZ()
6896 return m_CcdPixelSizeX * pow(m_CFZUI->focusCFZFNumber->value(), 2.0) * m_CFZUI->focusCFZAperture->value() / 1000.0;
6899void Focus::wavelengthChanged()
6902 if (m_FilterManager)
6904 m_CFZUI->focusCFZWavelength->setValue(m_FilterManager->getFilterWavelength(
filter()));
6909void Focus::resetCFZToOT()
6912 m_CFZUI->focusCFZFNumber->setValue(m_FocalRatio);
6913 m_CFZUI->focusCFZAperture->setValue(m_Aperture);
6916 if (m_FilterManager)
6918 if (m_CFZUI->focusCFZWavelength->value() != m_FilterManager->getFilterWavelength(
filter()))
6919 m_CFZUI->focusCFZWavelength->setValue(m_FilterManager->getFilterWavelength(
filter()));
6924void Focus::setState(FocusState newState)
6926 qCDebug(KSTARS_EKOS_FOCUS) <<
"Focus State changes from" << getFocusStatusString(m_state) <<
"to" << getFocusStatusString(
6929 emit newStatus(m_state);
6932void Focus::initView()
6934 m_FocusView.reset(
new FITSView(focusingWidget, FITS_FOCUS));
6936 m_FocusView->setBaseSize(focusingWidget->size());
6937 m_FocusView->createFloatingToolBar();
6940 focusingWidget->setLayout(vlayout);
6942 m_FocusView->setStarsEnabled(
true);
6943 m_FocusView->setStarsHFREnabled(
true);
6946QVariantMap Focus::getAllSettings()
const
6948 QVariantMap settings;
6951 for (
auto &oneWidget : findChildren<
QComboBox*>())
6952 settings.
insert(oneWidget->objectName(), oneWidget->currentText());
6956 settings.
insert(oneWidget->objectName(), oneWidget->value());
6959 for (
auto &oneWidget : findChildren<
QSpinBox*>())
6960 settings.
insert(oneWidget->objectName(), oneWidget->value());
6963 for (
auto &oneWidget : findChildren<
QCheckBox*>())
6964 settings.
insert(oneWidget->objectName(), oneWidget->isChecked());
6967 for (
auto &oneWidget : findChildren<
QGroupBox*>())
6968 if (oneWidget->isCheckable())
6969 settings.
insert(oneWidget->objectName(), oneWidget->isChecked());
6972 for (
auto &oneWidget : findChildren<
QSplitter*>())
6973 settings.
insert(oneWidget->objectName(),
QString::fromUtf8(oneWidget->saveState().toBase64()));
6977 settings.
insert(oneWidget->objectName(), oneWidget->isChecked());
6982void Focus::setAllSettings(
const QVariantMap &settings)
6986 disconnectSyncSettings();
6988 for (
auto &name : settings.keys())
6991 auto comboBox = findChild<QComboBox*>(name);
6994 syncControl(settings, name, comboBox);
6999 auto doubleSpinBox = findChild<QDoubleSpinBox*>(name);
7002 syncControl(settings, name, doubleSpinBox);
7007 auto spinBox = findChild<QSpinBox*>(name);
7010 syncControl(settings, name, spinBox);
7015 auto checkbox = findChild<QCheckBox*>(name);
7018 syncControl(settings, name, checkbox);
7023 auto groupbox = findChild<QGroupBox*>(name);
7024 if (groupbox && groupbox->isCheckable())
7026 syncControl(settings, name, groupbox);
7031 auto splitter = findChild<QSplitter*>(name);
7034 syncControl(settings, name, splitter);
7039 auto radioButton = findChild<QRadioButton*>(name);
7042 syncControl(settings, name, radioButton);
7048 for (
auto &key : settings.keys())
7050 auto value = settings[key];
7052 Options::self()->setProperty(key.
toLatin1(), value);
7054 m_Settings[key] = value;
7055 m_GlobalSettings[key] = value;
7058 emit settingsUpdated(getAllSettings());
7061 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
7062 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::Focus, m_Settings);
7065 connectSyncSettings();
7068 m_CurveFit =
static_cast<CurveFitting::CurveFit
> (m_OpsFocusProcess->focusCurveFit->currentIndex());
7069 setFocusDetection(
static_cast<StarAlgorithm
> (m_OpsFocusProcess->focusDetection->currentIndex()));
7070 setCurveFit(
static_cast<CurveFitting::CurveFit
>(m_OpsFocusProcess->focusCurveFit->currentIndex()));
7071 setStarMeasure(
static_cast<StarMeasure
>(m_OpsFocusProcess->focusStarMeasure->currentIndex()));
7072 setWalk(
static_cast<FocusWalk
>(m_OpsFocusMechanics->focusWalk->currentIndex()));
7076bool Focus::syncControl(
const QVariantMap &settings,
const QString &key,
QWidget * widget)
7087 if ((pSB = qobject_cast<QSpinBox *>(widget)))
7089 const int value = settings[key].toInt(&ok);
7096 else if ((pDSB = qobject_cast<QDoubleSpinBox *>(widget)))
7098 const double value = settings[key].toDouble(&ok);
7105 else if ((pCB = qobject_cast<QCheckBox *>(widget)))
7107 const bool value = settings[key].toBool();
7112 else if ((pGB = qobject_cast<QGroupBox *>(widget)))
7114 const bool value = settings[key].toBool();
7119 else if ((pRadioButton = qobject_cast<QRadioButton *>(widget)))
7121 const bool value = settings[key].toBool();
7123 pRadioButton->
click();
7127 else if ((pComboBox = qobject_cast<QComboBox *>(widget)))
7129 const QString value = settings[key].toString();
7133 else if ((pSplitter = qobject_cast<QSplitter *>(widget)))
7143void Focus::setupOpticalTrainManager()
7145 connect(OpticalTrainManager::Instance(), &OpticalTrainManager::updated,
this, &Focus::refreshOpticalTrain);
7148 OpticalTrainManager::Instance()->openEditor(opticalTrainCombo->currentText());
7152 ProfileSettings::Instance()->setOneSetting(ProfileSettings::FocusOpticalTrain,
7153 OpticalTrainManager::Instance()->
id(opticalTrainCombo->itemText(index)));
7154 refreshOpticalTrain();
7155 emit trainChanged();
7159void Focus::refreshOpticalTrain()
7161 bool validSettings =
false;
7162 opticalTrainCombo->blockSignals(
true);
7163 opticalTrainCombo->clear();
7164 opticalTrainCombo->addItems(OpticalTrainManager::Instance()->getTrainNames());
7165 trainB->setEnabled(
true);
7167 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::FocusOpticalTrain);
7171 auto id = trainID.
toUInt();
7174 if (OpticalTrainManager::Instance()->exists(
id) ==
false)
7176 qCWarning(KSTARS_EKOS_FOCUS) <<
"Optical train doesn't exist for id" << id;
7177 id = OpticalTrainManager::Instance()->id(opticalTrainCombo->itemText(0));
7180 auto name = OpticalTrainManager::Instance()->name(
id);
7182 opticalTrainCombo->setCurrentText(name);
7188 OpticalTrainSettings::Instance()->setOpticalTrainID(
id);
7190 auto focuser = OpticalTrainManager::Instance()->getFocuser(name);
7191 setFocuser(focuser);
7193 auto scope = OpticalTrainManager::Instance()->getScope(name);
7194 double reducer = OpticalTrainManager::Instance()->getReducer(name);
7195 setScopeDetails(scope, reducer);
7197 auto settings = OpticalTrainSettings::Instance()->getOneSetting(OpticalTrainSettings::Focus);
7198 if (settings.isValid())
7200 validSettings =
true;
7201 auto map = settings.toJsonObject().toVariantMap();
7202 if (map != m_Settings)
7205 setAllSettings(map);
7209 auto camera = OpticalTrainManager::Instance()->getCamera(name);
7212 opticalTrainCombo->setToolTip(
QString(
"%1 @ %2").arg(camera->getDeviceName(), scope[
"name"].toString()));
7215 auto nvp = camera->getNumber(
"CCD_INFO");
7218 m_CcdPixelSizeX = 0.0;
7219 m_CcdWidth = m_CcdHeight = 0;
7223 auto np = nvp->findWidgetByName(
"CCD_PIXEL_SIZE_X");
7225 m_CcdPixelSizeX = np->getValue();
7226 np = nvp->findWidgetByName(
"CCD_MAX_X");
7228 m_CcdWidth = np->getValue();
7229 np = nvp->findWidgetByName(
"CCD_MAX_Y");
7231 m_CcdHeight = np->getValue();
7236 auto filterWheel = OpticalTrainManager::Instance()->getFilterWheel(name);
7237 setFilterWheel(filterWheel);
7245 focusAdvisor->setupParams(name);
7246 focusAdvisor->updateParams();
7250 opticalTrainCombo->blockSignals(
false);
7254void Focus::setScopeDetails(
const QJsonObject &scope,
const double reducer)
7256 m_Aperture = scope[
"aperture"].toDouble(-1);
7257 m_FocalLength = scope[
"focal_length"].toDouble(-1);
7258 m_FocalRatio = scope[
"focal_ratio"].toDouble(-1);
7259 m_ScopeType = scope[
"type"].toString();
7260 m_Reducer = reducer;
7263 if (m_Reducer > 0.0)
7264 m_FocalLength *= m_Reducer;
7267 if (m_FocalRatio <= 0.0)
7269 m_FocalRatio = (m_Aperture > 0.001) ? m_FocalLength / m_Aperture : 0.0f;
7270 else if (m_Aperture < 0.0)
7272 m_Aperture = m_FocalLength / m_FocalRatio;
void drawPolynomial(PolynomialFit *poly, bool isVShape, bool activate, bool plot=true)
draw the approximating polynomial into the HFR V-graph
void toggleVideo(bool enabled)
toggleVideo Turn on and off video streaming if supported by the camera.
void checkTemperatureSource(const QString &name=QString())
Check temperature source and make sure information is updated accordingly.
void startFraming()
startFraming Begins continuous capture of the CCD and calculates HFR every frame.
void newHFRPlotPosition(double pos, double hfr, double sigma, bool outlier, int pulseDuration, bool plot=true)
new HFR plot position with sigma
void redrawHFRPlot(PolynomialFit *poly, double solutionPosition, double solutionValue)
redraw the entire HFR plot
void clearDataPoints()
clearDataPoints Remove all data points from HFR plots
void appendLogText(const QString &)
setFocusStatus Upon completion of the focusing process, set its status (fail or pass) and reset focus...
void updateProperty(INDI::Property prop)
updateProperty Read focus number properties of interest as they arrive from the focuser driver and pr...
void focusStarSelected(int x, int y)
focusStarSelected The user selected a focus star, save its coordinates and subframe it if subframing ...
void processData(const QSharedPointer< FITSData > &data)
newFITS A new FITS blob is received by the CCD driver.
void initHFRPlot(QString str, double starUnits, bool minimum, bool useWeights, bool showPosition)
initialize the HFR V plot
Q_SCRIPTABLE Q_NOREPLY void resetFrame()
DBUS interface function.
void processTemperatureSource(INDI::Property prop)
processTemperatureSource Updates focus temperature source.
void drawCFZ(double minPosition, double minValue, int m_cfzSteps, bool plt)
Draw Critical Focus Zone on graph.
void finalUpdates(const QString &title, bool plot=true)
final updates after focus run comopletes on the focus plot
void minimumFound(double solutionPosition, double solutionValue, bool plot=true)
Focus solution with minimal HFR found.
void setTitle(const QString &title, bool plot=true)
draw a title on the focus plot
void drawCurve(CurveFitting *curve, bool isVShape, bool activate, bool plot=true)
draw the curve into the HFR V-graph
CameraChip class controls a particular chip in camera.
Camera class controls an INDI Camera device.
@ ERROR_SAVE
INDI Camera error.
Focuser class handles control of INDI focuser devices.
KPageWidgetItem * addPage(QWidget *page, const QString &itemName, const QString &pixmapName=QString(), const QString &header=QString(), bool manage=true)
void setIcon(const QIcon &icon)
const KStarsDateTime & lt() const
static KStars * Instance()
The sky coordinates of a point in the sky.
An angle, stored as degrees, but expressible in many ways.
const double & Degrees() const
Q_SCRIPTABLE Q_NOREPLY void capture(double settleTime=0.0)
DBUS interface function.
Q_SCRIPTABLE bool focusOut(int ms=-1)
DBUS interface function.
Q_SCRIPTABLE Q_NOREPLY void abort()
DBUS interface function.
Q_SCRIPTABLE bool focusIn(int ms=-1)
DBUS interface function.
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
char * toString(const EngineQuery &query)
Ekos is an advanced Astrophotography tool for Linux.
QString name(GameStandardAction id)
KIOCORE_EXPORT QString number(KIO::filesize_t size)
QString path(const QString &relativePath)
KIOCORE_EXPORT QString dir(const QString &fileClass)
KOSM_EXPORT double distance(const std::vector< const OSM::Node * > &path, Coordinate coord)
QByteArray fromBase64(const QByteArray &base64, Base64Options options)
QByteArray toBase64(Base64Options options) const const
void stateChanged(int state)
void activated(int index)
void currentIndexChanged(int index)
void currentTextChanged(const QString &text)
QDateTime currentDateTime()
QString toString(QStringView format, QCalendar cal) const const
bool registerObject(const QString &path, QObject *object, RegisterOptions options)
QDBusConnection sessionBus()
QString filePath(const QString &fileName) const const
void valueChanged(double d)
bool exists() const const
bool isChecked() const const
QIcon fromTheme(const QString &name)
void append(QList< T > &&value)
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
qsizetype size() const const
bool disconnect(const QMetaObject::Connection &connection)
bool contains(const QPoint &point, bool proper) const const
bool isNull() const const
bool restoreState(const QByteArray &state)
QByteArray saveState() const const
QString & append(QChar ch)
QString arg(Args &&... args) const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
QString number(double n, char format, int precision)
QByteArray toLatin1() const const
QByteArray toUtf8() const const
QTextStream & center(QTextStream &stream)
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QUrl fromLocalFile(const QString &localFile)
bool isValid() const const
void setValue(QVariant &&value)
bool toBool() const const
double toDouble(bool *ok) const const
int toInt(bool *ok) const const
QString toString() const const
uint toUInt(bool *ok) const const