File indexing completed on 2024-03-24 15:18:31
0001 /* 0002 SPDX-FileCopyrightText: 2020 Hy Murveit <hy@murveit.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "ekos/focus/focusalgorithms.h" 0008 0009 #include <QTest> 0010 #include <memory> 0011 0012 #include <QObject> 0013 0014 // At this point, only the methods in focusalgorithms.h are tested. 0015 0016 class TestFocus : public QObject 0017 { 0018 Q_OBJECT 0019 0020 public: 0021 /** @short Constructor */ 0022 TestFocus(); 0023 0024 /** @short Destructor */ 0025 ~TestFocus() override = default; 0026 0027 private slots: 0028 void basicTest(); 0029 void restartTest(); 0030 void L1PHyperbolaTest(); 0031 void L1PParabolaTest(); 0032 void L1PQuadraticTest(); 0033 }; 0034 0035 #include "testfocus.moc" 0036 0037 using Ekos::FocusAlgorithmInterface; 0038 0039 FocusAlgorithmInterface::FocusParams makeParams() 0040 { 0041 const int maxTravel = 100000; 0042 const int initialStepSize = 25; 0043 const int startPosition = 10000; 0044 const int minPositionAllowed = 0; 0045 const int maxPositionAllowed = 1000000; 0046 const int maxIterations = 30; 0047 const double focusTolerance = 0.05; 0048 const QString filterName = "Red"; 0049 const double temperature = 20.0; 0050 const double initialOutwardSteps = 5; 0051 const int numSteps = 11; 0052 const Ekos::Focus::Algorithm focusAlgorithm = Ekos::Focus::FOCUS_LINEAR; 0053 const int backlash = 0; 0054 const Ekos::CurveFitting::CurveFit curveFit = Ekos::CurveFitting::FOCUS_QUADRATIC; 0055 const bool useWeights = false; 0056 const Ekos::Focus::StarMeasure starMeasure = Ekos::Focus::FOCUS_STAR_HFR; 0057 const Ekos::Focus::StarPSF starPSF = Ekos::Focus::FOCUS_STAR_GAUSSIAN; 0058 const bool refineCurveFit = false; 0059 const Ekos::Focus::FocusWalk focusWalk = Ekos::Focus::FOCUS_WALK_CLASSIC; 0060 const bool donutBuster = false; 0061 auto const optimisationDirection = Ekos::CurveFitting::OPTIMISATION_MINIMISE; 0062 auto const weightCalculation = Mathematics::RobustStatistics::SCALE_QESTIMATOR; 0063 0064 const FocusAlgorithmInterface::FocusParams params(nullptr, 0065 maxTravel, initialStepSize, startPosition, minPositionAllowed, 0066 maxPositionAllowed, maxIterations, focusTolerance, filterName, 0067 temperature, initialOutwardSteps, numSteps, focusAlgorithm, backlash, 0068 curveFit, useWeights, starMeasure, starPSF, refineCurveFit, focusWalk, 0069 donutBuster, optimisationDirection, weightCalculation); 0070 0071 return params; 0072 } 0073 0074 FocusAlgorithmInterface::FocusParams makeL1PHyperbolaParams() 0075 { 0076 const int maxTravel = 100000; 0077 const int initialStepSize = 25; 0078 const int startPosition = 10000; 0079 const int minPositionAllowed = 0; 0080 const int maxPositionAllowed = 1000000; 0081 const int maxIterations = 30; 0082 const double focusTolerance = 0.05; 0083 const QString filterName = "Green"; 0084 const double temperature = 20.0; 0085 const double initialOutwardSteps = 5; 0086 const int numSteps = 11; 0087 const Ekos::Focus::Algorithm focusAlgorithm = Ekos::Focus::FOCUS_LINEAR1PASS; 0088 const int backlash = 300; 0089 const Ekos::CurveFitting::CurveFit curveFit = Ekos::CurveFitting::FOCUS_HYPERBOLA; 0090 const bool useWeights = true; 0091 const Ekos::Focus::StarMeasure starMeasure = Ekos::Focus::FOCUS_STAR_HFR; 0092 const Ekos::Focus::StarPSF starPSF = Ekos::Focus::FOCUS_STAR_GAUSSIAN; 0093 const bool refineCurveFit = false; 0094 const Ekos::Focus::FocusWalk focusWalk = Ekos::Focus::FOCUS_WALK_CLASSIC; 0095 const bool donutBuster = false; 0096 auto const optimisationDirection = Ekos::CurveFitting::OPTIMISATION_MINIMISE; 0097 auto const weightCalculation = Mathematics::RobustStatistics::SCALE_QESTIMATOR; 0098 0099 const FocusAlgorithmInterface::FocusParams params(nullptr, 0100 maxTravel, initialStepSize, startPosition, minPositionAllowed, 0101 maxPositionAllowed, maxIterations, focusTolerance, filterName, 0102 temperature, initialOutwardSteps, numSteps, focusAlgorithm, backlash, 0103 curveFit, useWeights, starMeasure, starPSF, refineCurveFit, focusWalk, 0104 donutBuster, optimisationDirection, weightCalculation); 0105 0106 return params; 0107 } 0108 0109 FocusAlgorithmInterface::FocusParams makeL1PParabolaParams() 0110 { 0111 const int maxTravel = 100000; 0112 const int initialStepSize = 25; 0113 const int startPosition = 10000; 0114 const int minPositionAllowed = 0; 0115 const int maxPositionAllowed = 1000000; 0116 const int maxIterations = 30; 0117 const double focusTolerance = 0.05; 0118 const QString filterName = "Blue"; 0119 const double temperature = 20.0; 0120 const double initialOutwardSteps = 5; 0121 const int numSteps = 11; 0122 const Ekos::Focus::Algorithm focusAlgorithm = Ekos::Focus::FOCUS_LINEAR1PASS; 0123 const int backlash = 200; 0124 const Ekos::CurveFitting::CurveFit curveFit = Ekos::CurveFitting::FOCUS_PARABOLA; 0125 const bool useWeights = false; 0126 const Ekos::Focus::StarMeasure starMeasure = Ekos::Focus::FOCUS_STAR_HFR; 0127 const Ekos::Focus::StarPSF starPSF = Ekos::Focus::FOCUS_STAR_GAUSSIAN; 0128 const bool refineCurveFit = false; 0129 const Ekos::Focus::FocusWalk focusWalk = Ekos::Focus::FOCUS_WALK_CLASSIC; 0130 const bool donutBuster = false; 0131 auto const optimisationDirection = Ekos::CurveFitting::OPTIMISATION_MINIMISE; 0132 auto const weightCalculation = Mathematics::RobustStatistics::SCALE_QESTIMATOR; 0133 0134 const FocusAlgorithmInterface::FocusParams params(nullptr, 0135 maxTravel, initialStepSize, startPosition, minPositionAllowed, 0136 maxPositionAllowed, maxIterations, focusTolerance, filterName, 0137 temperature, initialOutwardSteps, numSteps, focusAlgorithm, backlash, 0138 curveFit, useWeights, starMeasure, starPSF, refineCurveFit, focusWalk, 0139 donutBuster, optimisationDirection, weightCalculation); 0140 0141 return params; 0142 } 0143 0144 FocusAlgorithmInterface::FocusParams makeL1PQuadraticParams() 0145 { 0146 const int maxTravel = 100000; 0147 const int initialStepSize = 25; 0148 const int startPosition = 10000; 0149 const int minPositionAllowed = 0; 0150 const int maxPositionAllowed = 1000000; 0151 const int maxIterations = 30; 0152 const double focusTolerance = 0.05; 0153 const QString filterName = "Lum"; 0154 const double temperature = 20.0; 0155 const double initialOutwardSteps = 5; 0156 const int numSteps = 11; 0157 const Ekos::Focus::Algorithm focusAlgorithm = Ekos::Focus::FOCUS_LINEAR1PASS; 0158 const int backlash = 0; 0159 const Ekos::CurveFitting::CurveFit curveFit = Ekos::CurveFitting::FOCUS_QUADRATIC; 0160 const bool useWeights = false; 0161 const Ekos::Focus::StarMeasure starMeasure = Ekos::Focus::FOCUS_STAR_HFR; 0162 const Ekos::Focus::StarPSF starPSF = Ekos::Focus::FOCUS_STAR_GAUSSIAN; 0163 const bool refineCurveFit = false; 0164 const Ekos::Focus::FocusWalk focusWalk = Ekos::Focus::FOCUS_WALK_CLASSIC; 0165 const bool donutBuster = false; 0166 auto const optimisationDirection = Ekos::CurveFitting::OPTIMISATION_MINIMISE; 0167 auto const weightCalculation = Mathematics::RobustStatistics::SCALE_QESTIMATOR; 0168 0169 const FocusAlgorithmInterface::FocusParams params(nullptr, 0170 maxTravel, initialStepSize, startPosition, minPositionAllowed, 0171 maxPositionAllowed, maxIterations, focusTolerance, filterName, 0172 temperature, initialOutwardSteps, numSteps, focusAlgorithm, backlash, 0173 curveFit, useWeights, starMeasure, starPSF, refineCurveFit, focusWalk, 0174 donutBuster, optimisationDirection, weightCalculation); 0175 0176 return params; 0177 } 0178 0179 TestFocus::TestFocus() : QObject() 0180 { 0181 } 0182 0183 #define CompareFloat(d1,d2) QVERIFY(fabs((d1) - (d2)) < .0001) 0184 0185 void TestFocus::basicTest() 0186 { 0187 // Test initial position. Since we set it up so that the min/max PositionAllowed 0188 // are not near the start position, we should start out with 0189 // initial position + 0190 auto params = makeParams(); 0191 std::unique_ptr<FocusAlgorithmInterface> focuser(MakeLinearFocuser(params)); 0192 int position = focuser->initialPosition(); 0193 // The first position should be initialPosition + stepSize * initialOutwardSteps, 0194 // unless maxPositionAllowed or maxTravel doesn't allow that. 0195 QCOMPARE(position, static_cast <int> (params.startPosition + params.initialOutwardSteps * params.initialStepSize)); 0196 0197 params.maxTravel = 4 * params.initialStepSize; 0198 focuser.reset(MakeLinearFocuser(params)); 0199 position = focuser->initialPosition(); 0200 QCOMPARE(position, params.startPosition + params.maxTravel); 0201 0202 params.maxPositionAllowed = params.startPosition + 3 * params.initialStepSize; 0203 focuser.reset(MakeLinearFocuser(params)); 0204 position = focuser->initialPosition(); 0205 QCOMPARE(position, params.maxPositionAllowed); 0206 0207 // go back to the default params 0208 params = makeParams(); 0209 focuser.reset(MakeLinearFocuser(params)); 0210 int currentPosition = focuser->initialPosition(); 0211 0212 // Here we run the algorithm, feeding it a v-curve, and watching it solve. 0213 // First pass: Should see the position reducing by initialStepSize 0214 position = focuser->newMeasurement(currentPosition, 5, 1); 0215 QCOMPARE(position, currentPosition - params.initialStepSize); 0216 currentPosition = position; 0217 0218 position = focuser->newMeasurement(currentPosition, 4, 1); 0219 QCOMPARE(position, currentPosition - params.initialStepSize); 0220 currentPosition = position; 0221 0222 position = focuser->newMeasurement(currentPosition, 3, 1); 0223 QCOMPARE(position, currentPosition - params.initialStepSize); 0224 currentPosition = position; 0225 0226 position = focuser->newMeasurement(currentPosition, 2, 1); 0227 QCOMPARE(position, currentPosition - params.initialStepSize); 0228 currentPosition = position; 0229 0230 position = focuser->newMeasurement(currentPosition, 1, 1); 0231 QCOMPARE(position, currentPosition - params.initialStepSize); 0232 currentPosition = position; 0233 0234 // Level off and then increase. 0235 0236 position = focuser->newMeasurement(currentPosition, 1, 1); 0237 QCOMPARE(position, currentPosition - params.initialStepSize); 0238 currentPosition = position; 0239 0240 position = focuser->newMeasurement(currentPosition, 2, 1); 0241 QCOMPARE(position, currentPosition - params.initialStepSize); 0242 currentPosition = position; 0243 0244 position = focuser->newMeasurement(currentPosition, 3, 1); 0245 QCOMPARE(position, currentPosition - params.initialStepSize); 0246 currentPosition = position; 0247 0248 // At the point the focuser should end the first pass and start a new 2nd pass. 0249 // The position to start the 2nd pass is hardcoded here (it is a polynomial 0250 // curve-fit of the above data). 0251 int secondPassStart = 10064; 0252 position = focuser->newMeasurement(currentPosition, 4, 1); 0253 QCOMPARE(position, secondPassStart); 0254 currentPosition = position; 0255 0256 // The 2nd pass steps down by half step-size, and should terminate when we 0257 // pass in an HFR within tolerance of the best HFR in the first pass (which was 1.0). 0258 0259 position = focuser->newMeasurement(currentPosition, 1.4, 1); 0260 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0261 currentPosition = position; 0262 0263 // Save the state from here for testing the retry logic below. 0264 std::unique_ptr<FocusAlgorithmInterface> focuserRetry(focuser->Copy()); 0265 int retryPosition = currentPosition; 0266 0267 position = focuser->newMeasurement(currentPosition, 1.3, 1); 0268 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0269 currentPosition = position; 0270 0271 position = focuser->newMeasurement(currentPosition, 1.2, 1); 0272 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0273 currentPosition = position; 0274 0275 position = focuser->newMeasurement(currentPosition, 1.1, 1); 0276 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0277 currentPosition = position; 0278 0279 // Making a copy of the focuser state at this point, for testing a scenario below 0280 // where the system does not get close enough to the desired HFR. 0281 std::unique_ptr<FocusAlgorithmInterface> focuserMissTolerance(focuser->Copy()); 0282 int missTolerancePosition = currentPosition; 0283 0284 // 1.04 is within tolerance of 1.0 0285 // It would complete, but we now cross the 1st-pass-best position (10014) 0286 // and use even smaller steps. 0287 position = focuser->newMeasurement(currentPosition, 1.04, 1); 0288 QCOMPARE(position, currentPosition - params.initialStepSize / 4); 0289 QVERIFY(!focuser->isDone()); 0290 currentPosition = position; 0291 0292 // Now let it finally complete. 0293 position = focuser->newMeasurement(currentPosition, 1.3, 1); 0294 QCOMPARE(position, currentPosition); 0295 position = focuser->newMeasurement(currentPosition, 1.3, 1); 0296 // Since the focuser is past the 1st pass min, it only retries once then finishes. 0297 QCOMPARE(position, -1); 0298 QVERIFY(focuser->isDone()); 0299 QCOMPARE(focuser->solution(), currentPosition); 0300 0301 // Test the focuser retry logic. When the focuser gets within its tolerance of the solution 0302 // in its 2nd pass, but hasn't yet reached the 1st pass' minimum, it will continue to iterate 0303 // and move its position inward as the HFRs it measures continue to improve. 0304 // However, if the HFR sample got worse, it will resample at the same position a few times, 0305 // in case there was noise in the sample. 0306 0307 focuser.swap(focuserRetry); 0308 position = focuser->newMeasurement(retryPosition, 1.04, 1); 0309 QCOMPARE(position, retryPosition - params.initialStepSize / 2); 0310 currentPosition = position; 0311 0312 position = focuser->newMeasurement(currentPosition, 1.05, 1); 0313 // HFR got worse, we're within tolderance of the solution. It should retry the same position. 0314 QCOMPARE(position, currentPosition); 0315 0316 position = focuser->newMeasurement(currentPosition, 1.10, 1); 0317 QCOMPARE(position, currentPosition); 0318 0319 position = focuser->newMeasurement(currentPosition, 1.10, 1); 0320 QCOMPARE(position, currentPosition); 0321 0322 // Making a copy of the focuser state at this point, for later testing. 0323 std::unique_ptr<FocusAlgorithmInterface> focuserRetry2(focuser->Copy()); 0324 int retry2Position = currentPosition; 0325 0326 // Try 2 scenarious from this position. 0327 0328 // 1. HFR is worse again compared to the best value above (1.04), give up. 0329 position = focuser->newMeasurement(retry2Position, 1.05, 1); 0330 QCOMPARE(position, -1); 0331 QVERIFY(focuser->isDone()); 0332 QCOMPARE(focuser->solution(), currentPosition); 0333 0334 // 2. HFR gets better. Continue moving toward the pass1 solution. 0335 focuser.swap(focuserRetry2); 0336 position = focuser->newMeasurement(retry2Position, 1.03, 1); 0337 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0338 currentPosition = position; 0339 0340 position = focuser->newMeasurement(currentPosition, 1.02, 1); 0341 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0342 currentPosition = position; 0343 0344 // Finally we're close enough to the 1st pass best to finish. 0345 // Since we crossed the 1st pass best position, we use a smaller step size. 0346 position = focuser->newMeasurement(currentPosition, 1.01, 1); 0347 QCOMPARE(position, currentPosition - params.initialStepSize / 4); 0348 currentPosition = position; 0349 0350 // Fail a few times trying to get better 0351 position = focuser->newMeasurement(currentPosition, 1.05, 1); 0352 QCOMPARE(position, currentPosition); 0353 position = focuser->newMeasurement(currentPosition, 1.05, 1); 0354 // Since the focuser is past the 1st pass min, it only retries once then finishes. 0355 QCOMPARE(position, -1); 0356 QVERIFY(focuser->isDone()); 0357 QCOMPARE(focuser->solution(), currentPosition); 0358 0359 // Retry testing is done. 0360 0361 // We pick up from above just before the system reached the desired tolerance. 0362 // In this case, it misses the desired HFR value, and continues processing. 0363 focuser.swap(focuserMissTolerance); 0364 0365 // Sample HFR=1.06 instead of the 1.04 above--not within tolerance. 0366 position = focuser->newMeasurement(missTolerancePosition, 1.06, 1); 0367 QCOMPARE(position, missTolerancePosition - params.initialStepSize / 2); 0368 currentPosition = position; 0369 0370 // HFRs continue to get worse (the min on this v-curve missed the threshold). 0371 position = focuser->newMeasurement(currentPosition, 1.1, 1); 0372 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0373 currentPosition = position; 0374 0375 position = focuser->newMeasurement(currentPosition, 1.5, 1); 0376 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0377 currentPosition = position; 0378 0379 // At this point, the focuser realizes it missed the minimum and resets. 0380 // The value it goes back to is a polynomial fit, and hardcoded here. 0381 int returnPosition = 10038; 0382 position = focuser->newMeasurement(currentPosition, 2.0, 1); 0383 QCOMPARE(position, returnPosition); 0384 currentPosition = position; 0385 0386 position = focuser->newMeasurement(currentPosition, 1.5, 1); 0387 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0388 currentPosition = position; 0389 0390 position = focuser->newMeasurement(currentPosition, 1.1, 1); 0391 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0392 currentPosition = position; 0393 0394 // Making a copy of the focuser state at this point, for later testing. 0395 std::unique_ptr<FocusAlgorithmInterface> focuser2(focuser->Copy()); 0396 int currentPosition2 = currentPosition; 0397 0398 // This time we get within tolerance, 0399 // and we've crossed the 1st-pass min so smaller step size. 0400 position = focuser->newMeasurement(currentPosition, 1.03, 1); 0401 QCOMPARE(position, currentPosition - params.initialStepSize / 4); 0402 currentPosition = position; 0403 0404 // Start getting worse and eventually finish. 0405 position = focuser->newMeasurement(currentPosition, 1.10, 1); 0406 QCOMPARE(position, currentPosition); 0407 position = focuser->newMeasurement(currentPosition, 1.10, 1); 0408 // Since the focuser is past the 1st pass min, it only retries once then finishes. 0409 QCOMPARE(position, -1); 0410 QVERIFY(focuser->isDone()); 0411 QCOMPARE(focuser->solution(), currentPosition); 0412 0413 // Alternative reality. 0414 focuser.swap(focuser2); 0415 0416 // We miss the tolerance again. 0417 position = focuser->newMeasurement(currentPosition2, 1.06, 1); 0418 QCOMPARE(position, currentPosition2 - params.initialStepSize / 2); 0419 currentPosition = position; 0420 0421 position = focuser->newMeasurement(currentPosition, 1.1, 1); 0422 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0423 currentPosition = position; 0424 0425 position = focuser->newMeasurement(currentPosition, 1.2, 1); 0426 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0427 currentPosition = position; 0428 0429 // It should notice we're getting worse (3 consecutive) and reset again. 0430 int returnPosition2 = 10038; 0431 position = focuser->newMeasurement(currentPosition, 1.3, 1); 0432 QCOMPARE(position, returnPosition2); 0433 currentPosition = position; 0434 0435 position = focuser->newMeasurement(currentPosition2, 1.06, 1); 0436 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0437 currentPosition = position; 0438 0439 position = focuser->newMeasurement(currentPosition2, 1.1, 1); 0440 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0441 currentPosition = position; 0442 0443 position = focuser->newMeasurement(currentPosition2, 1.2, 1); 0444 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0445 currentPosition = position; 0446 0447 // Again it notices 3 bad in a row 0448 int returnPosition3 = 10038; 0449 position = focuser->newMeasurement(currentPosition, 1.4, 1); 0450 QCOMPARE(position, returnPosition3); 0451 0452 // Now we're within 3 of the max number of iterations. 0453 // It resets again, trying to place us near the best position seen. 0454 int returnPosition4 = 10031; 0455 position = focuser->newMeasurement(currentPosition2, 1.06, 1); 0456 QCOMPARE(position, returnPosition4); 0457 currentPosition = position; 0458 0459 position = focuser->newMeasurement(currentPosition2, 1.2, 1); 0460 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0461 currentPosition = position; 0462 0463 position = focuser->newMeasurement(currentPosition2, 1.3, 1); 0464 QCOMPARE(position, currentPosition - params.initialStepSize / 2); 0465 currentPosition = position; 0466 0467 // And at this point we exceed the allowed number of steps (30) and fail. 0468 position = focuser->newMeasurement(currentPosition2, 1.4, 1); 0469 QCOMPARE(position, -1); 0470 QVERIFY(focuser->isDone()); 0471 QCOMPARE(focuser->solution(), -1); 0472 } 0473 0474 // This test replays a situation from a log where the focuser started "too low" 0475 // and restarts a bit higher. 0476 void TestFocus::restartTest() 0477 { 0478 auto params = makeParams(); 0479 params.startPosition = 11592; 0480 std::unique_ptr<FocusAlgorithmInterface> focuser(MakeLinearFocuser(params)); 0481 0482 int currentPosition = focuser->initialPosition(); 0483 QCOMPARE(currentPosition, 11717); 0484 0485 int position = focuser->newMeasurement(currentPosition, 1.24586, 1); 0486 QCOMPARE(position, 11692); 0487 currentPosition = position; 0488 0489 position = focuser->newMeasurement(currentPosition, 1.22075, 1); 0490 QCOMPARE(position, 11667); 0491 currentPosition = position; 0492 0493 position = focuser->newMeasurement(currentPosition, 1.47694, 1); 0494 QCOMPARE(position, 11642); 0495 currentPosition = position; 0496 0497 position = focuser->newMeasurement(currentPosition, 1.71925, 1); 0498 QCOMPARE(position, 11617); 0499 currentPosition = position; 0500 0501 position = focuser->newMeasurement(currentPosition, 1.73312, 1); 0502 QCOMPARE(position, 11592); 0503 currentPosition = position; 0504 0505 position = focuser->newMeasurement(currentPosition, 1.90926, 1); 0506 QCOMPARE(position, 11567); 0507 currentPosition = position; 0508 0509 position = focuser->newMeasurement(currentPosition, 2.09901, 1); 0510 0511 // At this point it should restart with a higher initial position, but not too high. 0512 QCOMPARE(position, 11842); 0513 } 0514 0515 void TestFocus::L1PHyperbolaTest() 0516 { 0517 // Linear 1 Pass hyperbola curve test. 0518 auto params = makeL1PHyperbolaParams(); 0519 std::unique_ptr<FocusAlgorithmInterface> focuser(MakeLinearFocuser(params)); 0520 int position = focuser->initialPosition(); 0521 // The first position should be initialPosition + stepSize * initialOutwardSteps, 0522 // unless maxPositionAllowed or maxTravel doesn't allow that. 0523 QCOMPARE(position, static_cast <int> (params.startPosition + params.initialOutwardSteps * params.initialStepSize)); 0524 0525 params.maxTravel = 4 * params.initialStepSize; 0526 focuser.reset(MakeLinearFocuser(params)); 0527 position = focuser->initialPosition(); 0528 QCOMPARE(position, params.startPosition + params.maxTravel); 0529 0530 params.maxPositionAllowed = params.startPosition + 3 * params.initialStepSize; 0531 focuser.reset(MakeLinearFocuser(params)); 0532 position = focuser->initialPosition(); 0533 QCOMPARE(position, params.maxPositionAllowed); 0534 0535 // go back to the default params 0536 params = makeL1PHyperbolaParams(); 0537 focuser.reset(MakeLinearFocuser(params)); 0538 int currentPosition = focuser->initialPosition(); 0539 0540 // Here we run the algorithm, feeding it a v-curve, and watching it solve. 0541 // Should see the position reducing by initialStepSize 0542 position = focuser->newMeasurement(currentPosition, 5.01, 1); 0543 QCOMPARE(position, currentPosition - params.initialStepSize); 0544 currentPosition = position; 0545 0546 position = focuser->newMeasurement(currentPosition, 4.0067, 1); 0547 QCOMPARE(position, currentPosition - params.initialStepSize); 0548 currentPosition = position; 0549 0550 position = focuser->newMeasurement(currentPosition, 2.981, 1); 0551 QCOMPARE(position, currentPosition - params.initialStepSize); 0552 currentPosition = position; 0553 0554 position = focuser->newMeasurement(currentPosition, 2.03, 1); 0555 QCOMPARE(position, currentPosition - params.initialStepSize); 0556 currentPosition = position; 0557 0558 position = focuser->newMeasurement(currentPosition, 0.996, 1); 0559 QCOMPARE(position, currentPosition - params.initialStepSize); 0560 currentPosition = position; 0561 0562 position = focuser->newMeasurement(currentPosition, 0.9, 1); 0563 QCOMPARE(position, currentPosition - params.initialStepSize); 0564 currentPosition = position; 0565 0566 // Level off and then increase. 0567 0568 position = focuser->newMeasurement(currentPosition, 1.1, 1); 0569 QCOMPARE(position, currentPosition - params.initialStepSize); 0570 currentPosition = position; 0571 0572 position = focuser->newMeasurement(currentPosition, 2.03, 1); 0573 QCOMPARE(position, currentPosition - params.initialStepSize); 0574 currentPosition = position; 0575 0576 position = focuser->newMeasurement(currentPosition, 2.987, 1); 0577 QCOMPARE(position, currentPosition - params.initialStepSize); 0578 currentPosition = position; 0579 0580 position = focuser->newMeasurement(currentPosition, 4.006, 1); 0581 QCOMPARE(position, currentPosition - params.initialStepSize); 0582 currentPosition = position; 0583 0584 // Send in the last datapoint to complete the first pass. The focuser will move to the solution 0585 // found by the curve fitting process. 0586 int solution = 10000; 0587 position = focuser->newMeasurement(currentPosition, 5, 1); 0588 QCOMPARE(position, solution); 0589 0590 // Check the latestHDR method 0591 QCOMPARE(focuser->latestValue(), 5.0); 0592 0593 // Check the getMeasurements method 0594 QVector<int> pos; 0595 QVector<double> hfrs; 0596 QVector<double> weights; 0597 focuser->getMeasurements(&pos, &hfrs, &weights); 0598 QVERIFY(pos.size() == 11); 0599 QVERIFY(hfrs.size() == 11); 0600 QVERIFY(weights.size() == 11); 0601 QCOMPARE(pos.last(), currentPosition); 0602 QCOMPARE(hfrs.last(), 5.0); 0603 QCOMPARE(weights.last(), 1.0); 0604 currentPosition = position; 0605 0606 // Check the getPass1Measurements method - for L1P this is the same as getMeasurement 0607 QVector<int> posPass1; 0608 QVector<double> hfrsPass1; 0609 QVector<double> weightsPass1; 0610 QVector<bool> outliersPass1; 0611 focuser->getPass1Measurements(&posPass1, &hfrsPass1, &weightsPass1, &outliersPass1); 0612 QCOMPARE(pos.last(), posPass1.last()); 0613 QCOMPARE(hfrs.last(), hfrsPass1.last()); 0614 QCOMPARE(weights.last(), weightsPass1.last()); 0615 0616 // Check the getTextStatus method 0617 double R2 = 0.8; 0618 QCOMPARE(focuser->getTextStatus(R2), "L1P [Green]: Hyperbola (W). Moving to Solution"); 0619 0620 // Now let it complete. 0621 position = focuser->newMeasurement(currentPosition, 0.91, 1); 0622 // Focuser returns a position of -1 to indicate its done. 0623 QCOMPARE(position, -1); 0624 // Check the isDone method 0625 QVERIFY(focuser->isDone()); 0626 //Check the solution method 0627 QCOMPARE(focuser->solution(), currentPosition); 0628 // Check the doneReason method 0629 QCOMPARE(focuser->doneReason(), "Solution found."); 0630 } 0631 0632 void TestFocus::L1PParabolaTest() 0633 { 0634 // Linear 1 Pass parabola curve test. 0635 auto params = makeL1PParabolaParams(); 0636 std::unique_ptr<FocusAlgorithmInterface> focuser(MakeLinearFocuser(params)); 0637 int position = focuser->initialPosition(); 0638 // The first position should be initialPosition + stepSize * initialOutwardSteps, 0639 // unless maxPositionAllowed or maxTravel doesn't allow that. 0640 QCOMPARE(position, static_cast <int> (params.startPosition + params.initialOutwardSteps * params.initialStepSize)); 0641 0642 params.maxTravel = 4 * params.initialStepSize; 0643 focuser.reset(MakeLinearFocuser(params)); 0644 position = focuser->initialPosition(); 0645 QCOMPARE(position, params.startPosition + params.maxTravel); 0646 0647 params.maxPositionAllowed = params.startPosition + 3 * params.initialStepSize; 0648 focuser.reset(MakeLinearFocuser(params)); 0649 position = focuser->initialPosition(); 0650 QCOMPARE(position, params.maxPositionAllowed); 0651 0652 // go back to the default params 0653 params = makeL1PParabolaParams(); 0654 focuser.reset(MakeLinearFocuser(params)); 0655 int currentPosition = focuser->initialPosition(); 0656 0657 // Here we run the algorithm, feeding it a v-curve, and watching it solve. 0658 // Should see the position reducing by initialStepSize 0659 position = focuser->newMeasurement(currentPosition, 5.01, 1); 0660 QCOMPARE(position, currentPosition - params.initialStepSize); 0661 currentPosition = position; 0662 0663 position = focuser->newMeasurement(currentPosition, 4.0067, 1); 0664 QCOMPARE(position, currentPosition - params.initialStepSize); 0665 currentPosition = position; 0666 0667 position = focuser->newMeasurement(currentPosition, 2.981, 1); 0668 QCOMPARE(position, currentPosition - params.initialStepSize); 0669 currentPosition = position; 0670 0671 position = focuser->newMeasurement(currentPosition, 2.03, 1); 0672 QCOMPARE(position, currentPosition - params.initialStepSize); 0673 currentPosition = position; 0674 0675 position = focuser->newMeasurement(currentPosition, 0.996, 1); 0676 QCOMPARE(position, currentPosition - params.initialStepSize); 0677 currentPosition = position; 0678 0679 position = focuser->newMeasurement(currentPosition, 0.9, 1); 0680 QCOMPARE(position, currentPosition - params.initialStepSize); 0681 currentPosition = position; 0682 0683 // Level off and then increase. 0684 0685 position = focuser->newMeasurement(currentPosition, 1.1, 1); 0686 QCOMPARE(position, currentPosition - params.initialStepSize); 0687 currentPosition = position; 0688 0689 position = focuser->newMeasurement(currentPosition, 2.03, 1); 0690 QCOMPARE(position, currentPosition - params.initialStepSize); 0691 currentPosition = position; 0692 0693 position = focuser->newMeasurement(currentPosition, 2.987, 1); 0694 QCOMPARE(position, currentPosition - params.initialStepSize); 0695 currentPosition = position; 0696 0697 position = focuser->newMeasurement(currentPosition, 4.006, 1); 0698 QCOMPARE(position, currentPosition - params.initialStepSize); 0699 currentPosition = position; 0700 0701 // Send in the last datapoint to complete the first pass. The focuser will move to the solution 0702 // found by the curve fitting process. 0703 int solution = 10000; 0704 position = focuser->newMeasurement(currentPosition, 5, 1); 0705 QCOMPARE(position, solution); 0706 0707 // Check the latestHDR method 0708 QCOMPARE(focuser->latestValue(), 5.0); 0709 0710 // Check the getMeasurements method 0711 QVector<int> pos; 0712 QVector<double> hfrs; 0713 QVector<double> weights; 0714 focuser->getMeasurements(&pos, &hfrs, &weights); 0715 QVERIFY(pos.size() == 11); 0716 QVERIFY(hfrs.size() == 11); 0717 QVERIFY(weights.size() == 11); 0718 QCOMPARE(pos.last(), currentPosition); 0719 QCOMPARE(hfrs.last(), 5.0); 0720 QCOMPARE(weights.last(), 1.0); 0721 currentPosition = position; 0722 0723 // Check the getPass1Measurements method - for L1P this is the same as getMeasurement 0724 QVector<int> posPass1; 0725 QVector<double> hfrsPass1; 0726 QVector<double> weightsPass1; 0727 QVector<bool> outliersPass1; 0728 focuser->getPass1Measurements(&posPass1, &hfrsPass1, &weightsPass1, &outliersPass1); 0729 QCOMPARE(pos.last(), posPass1.last()); 0730 QCOMPARE(hfrs.last(), hfrsPass1.last()); 0731 QCOMPARE(weights.last(), weightsPass1.last()); 0732 0733 // Check the getTextStatus method 0734 double R2 = 0.8; 0735 QCOMPARE(focuser->getTextStatus(R2), "L1P [Blue]: Parabola (U). Moving to Solution"); 0736 0737 // Now let it complete. 0738 position = focuser->newMeasurement(currentPosition, 0.91, 1); 0739 // Focuser returns a position of -1 to indicate its done. 0740 QCOMPARE(position, -1); 0741 // Check the isDone method 0742 QVERIFY(focuser->isDone()); 0743 //Check the solution method 0744 QCOMPARE(focuser->solution(), currentPosition); 0745 // Check the doneReason method 0746 QCOMPARE(focuser->doneReason(), "Solution found."); 0747 } 0748 0749 void TestFocus::L1PQuadraticTest() 0750 { 0751 // Linear 1 Pass quadratic curve test - should be the same as parabola 0752 auto params = makeL1PQuadraticParams(); 0753 std::unique_ptr<FocusAlgorithmInterface> focuser(MakeLinearFocuser(params)); 0754 int position = focuser->initialPosition(); 0755 // The first position should be initialPosition + stepSize * initialOutwardSteps, 0756 // unless maxPositionAllowed or maxTravel doesn't allow that. 0757 QCOMPARE(position, static_cast <int> (params.startPosition + params.initialOutwardSteps * params.initialStepSize)); 0758 0759 params.maxTravel = 4 * params.initialStepSize; 0760 focuser.reset(MakeLinearFocuser(params)); 0761 position = focuser->initialPosition(); 0762 QCOMPARE(position, params.startPosition + params.maxTravel); 0763 0764 params.maxPositionAllowed = params.startPosition + 3 * params.initialStepSize; 0765 focuser.reset(MakeLinearFocuser(params)); 0766 position = focuser->initialPosition(); 0767 QCOMPARE(position, params.maxPositionAllowed); 0768 0769 // go back to the default params 0770 params = makeL1PQuadraticParams(); 0771 focuser.reset(MakeLinearFocuser(params)); 0772 int currentPosition = focuser->initialPosition(); 0773 0774 // Here we run the algorithm, feeding it a v-curve, and watching it solve. 0775 // Should see the position reducing by initialStepSize 0776 position = focuser->newMeasurement(currentPosition, 5, 1); 0777 QCOMPARE(position, currentPosition - params.initialStepSize); 0778 currentPosition = position; 0779 0780 position = focuser->newMeasurement(currentPosition, 4, 1); 0781 QCOMPARE(position, currentPosition - params.initialStepSize); 0782 currentPosition = position; 0783 0784 position = focuser->newMeasurement(currentPosition, 3, 1); 0785 QCOMPARE(position, currentPosition - params.initialStepSize); 0786 currentPosition = position; 0787 0788 position = focuser->newMeasurement(currentPosition, 2, 1); 0789 QCOMPARE(position, currentPosition - params.initialStepSize); 0790 currentPosition = position; 0791 0792 position = focuser->newMeasurement(currentPosition, 1, 1); 0793 QCOMPARE(position, currentPosition - params.initialStepSize); 0794 currentPosition = position; 0795 0796 position = focuser->newMeasurement(currentPosition, 0.9, 1); 0797 QCOMPARE(position, currentPosition - params.initialStepSize); 0798 currentPosition = position; 0799 0800 // Level off and then increase. 0801 0802 position = focuser->newMeasurement(currentPosition, 1.1, 1); 0803 QCOMPARE(position, currentPosition - params.initialStepSize); 0804 currentPosition = position; 0805 0806 position = focuser->newMeasurement(currentPosition, 2, 1); 0807 QCOMPARE(position, currentPosition - params.initialStepSize); 0808 currentPosition = position; 0809 0810 position = focuser->newMeasurement(currentPosition, 3, 1); 0811 QCOMPARE(position, currentPosition - params.initialStepSize); 0812 currentPosition = position; 0813 0814 position = focuser->newMeasurement(currentPosition, 4, 1); 0815 QCOMPARE(position, currentPosition - params.initialStepSize); 0816 currentPosition = position; 0817 0818 // Send in the last datapoint to complete the first pass. The focuser will move to the solution 0819 // found by the curve fitting process. 0820 int solution = 10000; 0821 position = focuser->newMeasurement(currentPosition, 5, 1); 0822 QCOMPARE(position, solution); 0823 0824 // Check the latestHDR method 0825 QCOMPARE(focuser->latestValue(), 5.0); 0826 0827 // Check the getMeasurements method 0828 QVector<int> pos; 0829 QVector<double> hfrs; 0830 QVector<double> weights; 0831 focuser->getMeasurements(&pos, &hfrs, &weights); 0832 QVERIFY(pos.size() == 11); 0833 QVERIFY(hfrs.size() == 11); 0834 QVERIFY(weights.size() == 11); 0835 QCOMPARE(pos.last(), currentPosition); 0836 QCOMPARE(hfrs.last(), 5.0); 0837 QCOMPARE(weights.last(), 1.0); 0838 currentPosition = position; 0839 0840 // Check the getPass1Measurements method - for L1P this is the same as getMeasurement 0841 QVector<int> posPass1; 0842 QVector<double> hfrsPass1; 0843 QVector<double> weightsPass1; 0844 QVector<bool> outliersPass1; 0845 focuser->getPass1Measurements(&posPass1, &hfrsPass1, &weightsPass1, &outliersPass1); 0846 QCOMPARE(pos.last(), posPass1.last()); 0847 QCOMPARE(hfrs.last(), hfrsPass1.last()); 0848 QCOMPARE(weights.last(), weightsPass1.last()); 0849 0850 // Check the getTextStatus method 0851 double R2 = 0.8; 0852 QCOMPARE(focuser->getTextStatus(R2), "L1P [Lum]: Quadratic. Moving to Solution"); 0853 0854 // Now let it complete. 0855 position = focuser->newMeasurement(currentPosition, 0.91, 1); 0856 // Focuser returns a position of -1 to indicate its done. 0857 QCOMPARE(position, -1); 0858 // Check the isDone method 0859 QVERIFY(focuser->isDone()); 0860 //Check the solution method 0861 QCOMPARE(focuser->solution(), currentPosition); 0862 // Check the doneReason method 0863 QCOMPARE(focuser->doneReason(), "Solution found."); 0864 } 0865 0866 QTEST_GUILESS_MAIN(TestFocus)