File indexing completed on 2024-05-05 15:55:06

0001 /*
0002     SPDX-FileCopyrightText: 2023 John Evans <john.e.evans.email@googlemail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include "focus.h"
0010 
0011 namespace Ekos
0012 {
0013 
0014 // AdaptiveFocus is setup as a friend class of Focus because it is tightly coupled to Focus relying  on many
0015 // members of Focus, both variables and functions.
0016 //
0017 // adaptiveFocus is signalled (by capture). Check each adaptive dimension (temp, alt) to determine whether a focus move is required.
0018 // Total the movements from each dimension and, if required, adjust focus.
0019 //
0020 // Use the adaptive focus parameters associated with the current filter unless that has a lock filter, in which case use the lock filter.
0021 // Use the last good autofocus run as the reference that provides the focus position, temperature
0022 // and altitude. Adaptive focus then calculates the proposed position based on the current temperature and altitude
0023 // and calculates how to move from the current position to the proposed position - note there may be an overscan involved.
0024 //
0025 // To keep track of the movements the data are passed to Analyze which allows the user to review everything. Analyze displays the
0026 // deltas from the previous adaptive focus run for temperature and altitude to the next adaptive focus run.
0027 //
0028 // Calculations are performed as doubles and rounded to int for the final movement.
0029 //
0030 // A complication is that not all focusers move exactly to the requested position - 'bad boy' focusers. E.g. a request to
0031 // goto position X results in the focuser moving to X, X +/- 1 or X +/- 2. These position errors need to be managed. There
0032 // are 2 aspects to this; before an Adaptive Focus iteration, the focuser may be "off" where it should be. This could be
0033 // because the focuser is a "bad boy" so it moved to the correct position +/- 1 or 2 ticks; this is the Last Pos Error.
0034 // Adaptive Focus will attempt to correct this error even if there are no temperature or altitude changes (providing the
0035 // movement is above the user defined minimum movement.
0036 // When the Adaptive Focus iteration runs, the focuser may again experience a Pos Error.
0037 // These Position Errors are passed to Analyze to breakdown each focuser movement.
0038 //
0039 // Proposed Position = Ref Position (from last Autofocus) + adjustment for temperature + adjustment for altitude
0040 //
0041 // Accounting since last Adaptive Focus
0042 // Last Pos Error Reversal = Last Iteration Proposed Move - Focuser position at start of Adaptive Focus iteration
0043 // This Pos Error = Focuser position at end of Adaptive Focus iteration - Proposed Move
0044 // End Position = Start Position + temperature adjustment + altitude adjustment + Last Pos Error Reversal + This Pos Error
0045 //
0046 // Example: Last Autofocus Run, Pos=100 0C 70Alt. Parameters: 10ticks/Degree C, 1tick/Degree Alt
0047 // 1st Adaptive Focus: 0.5C 71Alt
0048 //                     Proposed Position = 100 + 5 + 1                = 106
0049 //                     Actual Position                                = 105 (focuser movement error)
0050 //                     Accounting: Start Position                     = 100
0051 //                                 Temperature Adjustment             = 5
0052 //                                 Altitude Adjustment                = 1
0053 //                                 Last Pos Error Reversal            = 0
0054 //                                 This Pos Error                     = -1
0055 //                                 End Position = 100 + 5 + 1 + 0 - 1 = 105
0056 //
0057 // 2nd Adaptive Focus: 0.75C 72Alt
0058 //                     Proposed Position = 100 + 7.5 + 2              = 110
0059 //                     Actual Position                                = 112 (focuser movement error)
0060 //                     Accounting: Start Position                     = 105
0061 //                                 Temperature Adjustment             = 2.5
0062 //                                 Altitude Adjustment                = 1
0063 //                                 Last Pos Error Reversal            = 1
0064 //                                 This Pos Error                     = 2
0065 //                                 End Position = 100 + 5 + 1 + 0 - 1 = 112
0066 //
0067 // 3rd Adaptive Focus: 0.25C 72Alt
0068 //                     Proposed Position = 100 + 2.5 + 2              = 105
0069 //                     Actual Position                                = 105 (no focuser movement error)
0070 //                     Accounting: Start Position                     = 112
0071 //                                 Temperature Adjustment             = -5
0072 //                                 Altitude Adjustment                = 0
0073 //                                 Last Pos Error Reversal            = -2
0074 //                                 This Pos Error                     =
0075 //                                 End Position = 100 + 5 + 1 + 0 - 1 = 105
0076 //
0077 // Adaptive Focus moves the focuser between Autofocus runs.
0078 // Adapt Start Pos adjusts the start position of an autofocus run based on Adaptive Focus settings
0079 // The start position uses the last successful AF run for the active filter and adapts that position
0080 // based on the temperature and altitude delta between now and when the last successful AF run happened
0081 // Only enabled for LINEAR 1 PASS
0082 
0083 class AdaptiveFocus
0084 {
0085     public:
0086 
0087         AdaptiveFocus(Focus* _focus);
0088         ~AdaptiveFocus();
0089 
0090         /**
0091          * @brief runAdaptiveFocus runs the next iteration of Adaptive Focus
0092          * @param current focuser position
0093          * @param active filter
0094          */
0095         void runAdaptiveFocus(const int currentPosition, const QString &filter);
0096 
0097         /**
0098          * @brief Perform admin functions on Adaptive Focus to inform other modules of
0099          * @param current focuser position
0100          * @param success (or not)
0101          * @param focuserMoved (or not)
0102          */
0103         void adaptiveFocusAdmin(const int currentPosition, const bool success, const bool focuserMoved);
0104 
0105         /**
0106          * @brief Reset the variables used by Adaptive Focus
0107          */
0108         void resetAdaptiveFocusCounters();
0109 
0110         /**
0111          * @brief Return whether Adaptive Focus is running
0112          * @return inAdaptiveFocus
0113          */
0114         bool inAdaptiveFocus()
0115         {
0116             return m_inAdaptiveFocus;
0117         }
0118 
0119         /**
0120          * @brief Set the value of inAdaptiveFocus
0121          * @param value
0122          */
0123         void setInAdaptiveFocus(bool value);
0124 
0125         /**
0126          * @brief adapt the start position based on temperature and altitude
0127          * @param position is the unadapted focuser position
0128          * @param AFfilter is the filter to run autofocus on
0129          * @return adapted start position
0130          */
0131         int adaptStartPosition(int position, QString &AFfilter);
0132 
0133     private:
0134 
0135         /**
0136          * @brief Get the Adaptive Filter to use
0137          * @param active filter
0138          * @return filter
0139          */
0140         QString getAdaptiveFilter(const QString filter);
0141 
0142         /**
0143          * @brief Get filter offset between active and adaptive filters
0144          * @param Active filter
0145          * @param Adaptive filter
0146          * @return offset
0147          */
0148         int getAdaptiveFilterOffset(const QString &activeFilter, const QString &adaptiveFilter);
0149 
0150         Focus *m_focus { nullptr };
0151 
0152         // Focuser is processing an adaptive focus request
0153         bool m_inAdaptiveFocus { false };
0154 
0155         // m_ThisAdaptiveFocus* variables hold values for the current Adaptive Focus run
0156         int     m_ThisAdaptiveFocusStartPos         { INVALID_VALUE };
0157         double  m_ThisAdaptiveFocusTemperature      { INVALID_VALUE };
0158         double  m_ThisAdaptiveFocusAlt              { INVALID_VALUE };
0159         double  m_ThisAdaptiveFocusTempTicks        { INVALID_VALUE };
0160         double  m_ThisAdaptiveFocusAltTicks         { INVALID_VALUE };
0161         int     m_ThisAdaptiveFocusRoundingError    { 0 };
0162         // m_LastAdaptiveFocus* variables hold values for the previous Adaptive Focus run
0163         QString m_LastAdaptiveFilter                { NULL_FILTER };
0164         double  m_LastAdaptiveFocusTemperature      { INVALID_VALUE };
0165         double  m_LastAdaptiveFocusAlt              { INVALID_VALUE };
0166         int     m_LastAdaptiveFocusPosErrorReversal { INVALID_VALUE };
0167 
0168         int     m_AdaptiveFocusPositionReq          { INVALID_VALUE };
0169         int     m_AdaptiveTotalMove                 { 0 };
0170 };
0171 
0172 }