Kstars
curvefit.cpp
25// The functions here fit a number of different curves to the incoming data points using the Lehvensberg-Marquart
26// solver with geodesic acceleration as provided the Gnu Science Library (GSL). The following sources of information are useful:
27// www.wikipedia.org/wiki/Levenberg–Marquardt_algorithm - overview of the mathematics behind the algo
28// www.gnu.org/software/gsl/doc/html/nls.html - GSL manual describing Nonlinear Least-Squares fitting.
32// The Levensberg-Marquart algorithm is a non-linear least-squares solver and thus suitable for mnay
33// different equations. The basic is idea is to adjust the equation y = f(x,P) so that the computed
34// y values are as close as possible to the y values of the datapoints provided, so that the resultant
35// curve fits the data as best as it can. P is a set of parameters that are varied by the solver in order
36// to find the best fit. The solver measures how far away the curve is at each data point, squares the
39// The solver is supplied with an initial guess for the parameters, P. It calculates S, makes an adjustment
40// P and calculates a new S1. Provided S1 < S the solver has moved in the right direction and reduced S.
46// The solver is capable of solving either an unweighted or weighted set of datapoints. In essence, an
47// unweighted set of data gives equal weight to each datapoint when trying to fit a curve. An alternative is to
48// weight each datapoint with a measure that corresponds to how accurate the measurement of the datapoint
49// actually is. Given we are calculating HFRs of stars we can calculate the variance (standard deviation
50// squared) in the measurement of HFR and use 1 / SD^2 as weighting. What this means is that if we have a
51// datapoint where the SD in HFR measurements is small we would give this datapoint a relatively high
52// weighting when fitting the curve, and if there was a datapoint with a higher SD in HFR measurements
55// There are several optimisations to LM that speed up convergence for certain types of equations. This
56// code uses the LM solver with geodesic acceleration; a technique to accelerate convergence by using the
57// second derivative of the fitted function. An optimisation that has been implemented is that since, in normal
58// operation, the solver is run multiple times with the same or similar parameters, the initial guess for
61// The documents referenced provide the maths of the LM algorithm. What is required is the function to be
62// used f(x) and the derivative of f(x) with respect to the parameters of f(x). This partial derivative forms
63// a matrix called the Jacobian, J(x). LM then finds a minimum. Mathematically it will find a minimum local
64// to the initial guess, but not necessarily the global minimum but for the equations used this is not a
65// problem under normal operation as there will only be 1 minimum. If the data is poor, however, the
66// solver may find an "n" solution rather than a "u" especially at the start of the process where there
67// are a small number of points and the error in measurement is high. We'll ignore and continue and this
70// The original algorithm used in Ekos is a quadratic equation, which represents a parabolic curve. In order
71// not to disturb historic code the original solution will be called Quadratic. It uses a linear least-squares
116// 2. b must be > 0 for a V shaped curve (b < 0 for an inverted V and b = 0 for a horizontal line).
129// 2. b must be > 0 for a V shaped curve (b < 0 for an inverted V and b = 0 for a horizontal line).
199// The matrix is symmetric, as ddf/dParm1dParm2 = ddf/dParm2dParm1 so we only need to differentiate
249// The matrix is symmetric, as ddf/dParm1dParm2 = ddf/dParm2dParm1 so we only need to differentiate
264// There following are key parameters that drive the LM solver. Currently these settings are coded into
265// the program. It would be better to store them in a configuration file somewhere, but they aren't the
432 double sum = va * va * Daa + 2 * (va * vb * Dab + va * vc * Dac + vb * vc * Dbc) + vc * vc * Dcc;
501// Calculates the second directional derivative vector for the parabola equation f(x) = a + b*(x-c)^2
553// Calculates the Jacobian (derivative) matrix for the 2D gaussian equation f(x) = a + b.exp-((x-c)^2/2d^2)
588// Calculates the second directional derivative vector for the gaussian equation f(x) = a + b.exp-((x-c)^2/2d^2)
644double gaufxy(double x, double y, double a, double x0, double y0, double A, double B, double C, double b)
646 return b + a * exp(-(A * (pow(x - x0, 2.0)) + 2.0 * B * (x - x0) * (y - y0) + C * (pow(y - y0, 2.0))));
720// The matrix is symmetric, as ddf/dParm1dParm2 = ddf/dParm2dParm1 so we only need to differentiate
817 double sum = 2 * va * ((vx0 * Dax0) + (vy0 * Day0) + (vA * DaA) + (vB * DaB) + (vC * DaC)) + // a diffs
818 vx0 * ((vx0 * Dx0x0) + 2 * ((vy0 * Dx0y0) + (vA * Dx0A) + (vB * Dx0B) + (vC * Dx0C))) + // x0 diffs
885// The matrix is symmetric, as ddf/dParm1dParm2 = ddf/dParm2dParm1 so we only need to differentiate
940void CurveFitting::fitCurve(const FittingGoal goal, const QVector<int> &x_, const QVector<double> &y_,
944 if ((x_.size() != y_.size()) || (x_.size() != weight_.size()) || (x_.size() != outliers_.size()))
945 qCDebug(KSTARS_EKOS_FOCUS) << QString("CurveFitting::fitCurve inconsistent parameters. x=%1, y=%2, weight=%3, outliers=%4")
978 // Something went wrong, log an error and reset state so solver starts from scratch if called again
979 qCDebug(KSTARS_EKOS_FOCUS) << QString("CurveFitting::fitCurve called with curveFit=%1").arg(curveFit);
992 qCDebug(KSTARS_EKOS_FOCUS) << QString("CurveFitting::fitCurve3D called with useWeights = true. Not currently supported");
1007 // Something went wrong, log an error and reset state so solver starts from scratch if called again
1008 qCDebug(KSTARS_EKOS_FOCUS) << QString("CurveFitting::fitCurve3D called with curveFit=%1").arg(curveFit);
1037 y = hypfx(x, m_coefficients[A_IDX], m_coefficients[B_IDX], m_coefficients[C_IDX], m_coefficients[D_IDX]);
1041 y = gau2Dfx(x, m_coefficients[A_IDX], m_coefficients[B_IDX], m_coefficients[C_IDX], m_coefficients[D_IDX]);
1043 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error: CurveFitting::f called with m_CurveType = %1 m_coefficients.size = %2")
1053 x = hypfy(y, m_coefficients[A_IDX], m_coefficients[B_IDX], m_coefficients[C_IDX], m_coefficients[D_IDX]);
1057 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error: CurveFitting::fy called with m_CurveType = %1 m_coefficients.size = %2")
1067 z = gaufxy(x, y, m_coefficients[A_IDX], m_coefficients[B_IDX], m_coefficients[C_IDX], m_coefficients[D_IDX],
1072 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error: CurveFitting::f3D called with m_CurveType = %1 m_coefficients.size = %2")
1078QVector<double> CurveFitting::polynomial_fit(const double *const data_x, const double *const data_y, const int n,
1126QVector<double> CurveFitting::hyperbola_fit(FittingGoal goal, const QVector<double> data_x, const QVector<double> data_y,
1127 const QVector<double> data_weights, const QVector<bool> outliers, const bool useWeights, const OptimisationDirection optDir)
1145 gsl_multifit_nlinear_workspace *w = gsl_multifit_nlinear_alloc(gsl_multifit_nlinear_trust, ¶ms, dataPoints.dps.size(),
1162 // To activate, uncomment the callback lambda and change the call to gsl_multifit_nlinear_driver
1175 qCDebug(KSTARS_EKOS_FOCUS) << QString("iter %1: A=%2, B=%3, C=%4, D=%5 rcond(J)=%6, avratio=%7, |f(x)|=%8")
1193 // fails on its first step where we will always retry after adjusting parameters. It helps with
1213 qCDebug(KSTARS_EKOS_FOCUS) << QString("Starting LM solver, fit=hyperbola, solver=%1, scale=%2, trs=%3, iters=%4, xtol=%5,"
1237 QString("LM solver (Hyperbola): Failed after %1ms iters=%2 [attempt=%3] with status=%4 [%5] and info=%6 [%7], retry=%8")
1238 .arg(timer.elapsed()).arg(gsl_multifit_nlinear_niter(w)).arg(attempt + 1).arg(status).arg(gsl_strerror(status))
1251 QString("LM Solver (Hyperbola): Solution found after %1ms %2 iters (%3). A=%4, B=%5, C=%6, D=%7")
1252 .arg(timer.elapsed()).arg(gsl_multifit_nlinear_niter(w)).arg(getLMReasonCode(info)).arg(vc[A_IDX]).arg(vc[B_IDX])
1284void CurveFitting::hypSetupParams(FittingGoal goal, gsl_multifit_nlinear_parameters *params, int *numIters, double *xtol,
1296 // - gsl_multifit_nlinear_scale_more uses. More strategy. Good for problems with parameters with widely different scales
1297 // - gsl_multifit_nlinear_scale_levenberg. Levensberg strategy. Can be good but not scale invariant.
1298 // - gsl_multifit_nlinear_scale_marquardt. Marquardt strategy. Considered inferior to More and Levensberg
1302 // - gsl_multifit_nlinear_solver_qr produces reliable results but needs more iterations than Cholesky
1306 // avmax is the max allowed ratio of 2nd order term (acceleration, a) to the 1st order term (velocity, v)
1342// Initialise parameters before starting the solver. Its important to start with a guess as near to the solution as possible
1343// If we found a solution before and we're just adding more datapoints use the last solution as the guess.
1344// If we don't have a solution use the datapoints to approximate. Work out the min and max points and use these
1346void CurveFitting::hypMakeGuess(const int attempt, const DataPointT &dataPoints, gsl_vector * guess)
1348 // If we are retrying then perturb the initial conditions. The hope is that by doing this the solver
1352 if (!m_FirstSolverRun && (m_LastCurveType == FOCUS_HYPERBOLA) && (m_LastCoefficients.size() == NUM_HYPERBOLA_PARAMS))
1432 qCDebug(KSTARS_EKOS_FOCUS) << QString("LM solver (hyp) initial params: perturbation=%1, A=%2, B=%3, C=%4, D=%5")
1442QVector<double> CurveFitting::parabola_fit(FittingGoal goal, const QVector<double> data_x, const QVector<double> data_y,
1443 const QVector<double> data_weights, const QVector<bool> outliers, bool useWeights, const OptimisationDirection optDir)
1461 gsl_multifit_nlinear_workspace* w = gsl_multifit_nlinear_alloc (gsl_multifit_nlinear_trust, ¶ms, dataPoints.dps.size(),
1478 // To activate, uncomment the callback lambda and change the call to gsl_multifit_nlinear_driver
1491 qCDebug(KSTARS_EKOS_FOCUS) << QString("iter %1: A=%2, B=%3, C=%4, rcond(J)=%5, avratio=%6 |f(x)|=%7")
1507 // fails on its first step where we will always retry after adjusting parameters. It helps with
1527 qCDebug(KSTARS_EKOS_FOCUS) << QString("Starting LM solver, fit=parabola, solver=%1, scale=%2, trs=%3, iters=%4, xtol=%5,"
1551 QString("LM solver (Parabola): Failed after %1ms iters=%2 [attempt=%3] with status=%4 [%5] and info=%6 [%7], retry=%8")
1552 .arg(timer.elapsed()).arg(gsl_multifit_nlinear_niter(w)).arg(attempt + 1).arg(status).arg(gsl_strerror(status))
1564 qCDebug(KSTARS_EKOS_FOCUS) << QString("LM Solver (Parabola): Solution found after %1ms %2 iters (%3). A=%4, B=%5, C=%6")
1565 .arg(timer.elapsed()).arg(gsl_multifit_nlinear_niter(w)).arg(getLMReasonCode(info)).arg(vc[A_IDX]).arg(vc[B_IDX])
1583void CurveFitting::parSetupParams(FittingGoal goal, gsl_multifit_nlinear_parameters *params, int *numIters, double *xtol,
1595 // - gsl_multifit_nlinear_scale_more uses. More strategy. Good for problems with parameters with widely different scales
1596 // - gsl_multifit_nlinear_scale_levenberg. Levensberg strategy. Can be good but not scale invariant.
1597 // - gsl_multifit_nlinear_scale_marquardt. Marquardt strategy. Considered inferior to More and Levensberg
1601 // - gsl_multifit_nlinear_solver_qr produces reliable results but needs more iterations than Cholesky
1605 // avmax is the max allowed ratio of 2nd order term (acceleration, a) to the 1st order term (velocity, v)
1641// Initialise parameters before starting the solver. Its important to start with a guess as near to the solution as possible
1642// If we found a solution before and we're just adding more datapoints use the last solution as the guess.
1643// If we don't have a solution use the datapoints to approximate. Work out the min and max points and use these
1645void CurveFitting::parMakeGuess(const int attempt, const DataPointT &dataPoints, gsl_vector * guess)
1647 // If we are retrying then perturb the initial conditions. The hope is that by doing this the solver
1651 if (!m_FirstSolverRun && (m_LastCurveType == FOCUS_PARABOLA) && (m_LastCoefficients.size() == NUM_PARABOLA_PARAMS))
1699 qCDebug(KSTARS_EKOS_FOCUS) << QString("LM solver (par) initial params: perturbation=%1, A=%2, B=%3, C=%4")
1708QVector<double> CurveFitting::gaussian2D_fit(FittingGoal goal, const QVector<double> data_x, const QVector<double> data_y,
1709 const QVector<double> data_weights, const QVector<bool> outliers, bool useWeights, const OptimisationDirection optDir)
1727 gsl_multifit_nlinear_workspace* w = gsl_multifit_nlinear_alloc (gsl_multifit_nlinear_trust, ¶ms, dataPoints.dps.size(),
1749 // fails on its first step where we will always retry after adjusting parameters. It helps with
1769 qCDebug(KSTARS_EKOS_FOCUS) << QString("Starting LM solver, fit=2DGaussian, solver=%1, scale=%2, trs=%3, iters=%4, xtol=%5,"
1793 QString("LM solver (2D Gaussian): Failed after %1ms iters=%2 [attempt=%3] with status=%4 [%5] and info=%6 [%7], retry=%8")
1794 .arg(timer.elapsed()).arg(gsl_multifit_nlinear_niter(w)).arg(attempt + 1).arg(status).arg(gsl_strerror(status))
1807 QString("LM Solver (2D Gaussian): Solution found after %1ms %2 iters (%3). A=%4, B=%5, C=%6, D=%7")
1808 .arg(timer.elapsed()).arg(gsl_multifit_nlinear_niter(w)).arg(getLMReasonCode(info)).arg(vc[A_IDX]).arg(vc[B_IDX])
1826void CurveFitting::gau2DSetupParams(FittingGoal goal, gsl_multifit_nlinear_parameters *params, int *numIters, double *xtol,
1838 // - gsl_multifit_nlinear_scale_more uses. More strategy. Good for problems with parameters with widely different scales
1839 // - gsl_multifit_nlinear_scale_levenberg. Levensberg strategy. Can be good but not scale invariant.
1840 // - gsl_multifit_nlinear_scale_marquardt. Marquardt strategy. Considered inferior to More and Levensberg
1844 // - gsl_multifit_nlinear_solver_qr produces reliable results but needs more iterations than Cholesky
1848 // avmax is the max allowed ratio of 2nd order term (acceleration, a) to the 1st order term (velocity, v)
1884// Initialise parameters before starting the solver. Its important to start with a guess as near to the solution as possible
1885// If we found a solution before and we're just adding more datapoints use the last solution as the guess.
1886// If we don't have a solution use the datapoints to approximate. Work out the min and max points and use these
1888void CurveFitting::gau2DMakeGuess(const int attempt, const DataPointT &dataPoints, gsl_vector * guess)
1890 // If we are retrying then perturb the initial conditions. The hope is that by doing this the solver
1894 if (!m_FirstSolverRun && (m_LastCurveType == FOCUS_2DGAUSSIAN) && (m_LastCoefficients.size() == NUM_2DGAUSSIAN_PARAMS))
1953 qCDebug(KSTARS_EKOS_FOCUS) << QString("LM solver (2D gaussian) initial params: perturbation=%1, A=%2, B=%3, C=%4, D=%5")
1972 gsl_multifit_nlinear_workspace* w = gsl_multifit_nlinear_alloc (gsl_multifit_nlinear_trust, ¶ms, data.dps.size(),
1995 // Setup for multiple solve attempts. We won't worry too much if the solver fails as there should be
1996 // plenty of stars, but if the solver fails on its first step then adjust parameters and retry as this
2018 // To activate, uncomment the callback lambda and change the call to gsl_multifit_nlinear_driver
2019 /*auto callback = [](const size_t iter, void* _params, const gsl_multifit_nlinear_workspace * w)
2050 qCDebug(KSTARS_EKOS_FOCUS) << QString("Starting LM solver, fit=gaussian, solver=%1, scale=%2, trs=%3, iters=%4, xtol=%5,"
2061 QString("LM solver (Gaussian): Failed after %1ms iters=%2 [attempt=%3] with status=%4 [%5] and info=%6 [%7]")
2062 .arg(timer.elapsed()).arg(gsl_multifit_nlinear_niter(w)).arg(attempt + 1).arg(status).arg(gsl_strerror(status))
2074 qCDebug(KSTARS_EKOS_FOCUS) << QString("LM Solver (Gaussian): Solution found after %1ms %2 iters (%3). A=%4, B=%5, C=%6, "
2075 "D=%7, E=%8, F=%9, G=%10").arg(timer.elapsed()).arg(gsl_multifit_nlinear_niter(w)).arg(getLMReasonCode(info))
2093// Initialise parameters before starting the solver. Its important to start with a guess as near to the solution as possible
2094// Since we have already run some HFR calcs on the star, use these values to calculate the guess
2095void CurveFitting::gauMakeGuess(const int attempt, const StarParams &starParams, gsl_vector * guess)
2097 // If we are retrying then perturb the initial conditions. The hope is that by doing this the solver
2121 QString("LM Solver (Gaussian): Guess perturbation=%1, A=%2, B=%3, C=%4, D=%5, E=%6, F=%7, G=%8")
2134void CurveFitting::gauSetupParams(gsl_multifit_nlinear_parameters *params, int *numIters, double *xtol, double *gtol,
2145 // avmax is the max allowed ratio of 2nd order term (acceleration, a) to the 1st order term (velocity, v)
2150 // - gsl_multifit_nlinear_scale_more uses. More strategy. Good for problems with parameters with widely different scales
2151 // - gsl_multifit_nlinear_scale_levenberg. Levensberg strategy. Can be good but not scale invariant.
2152 // - gsl_multifit_nlinear_scale_marquardt. Marquardt strategy. Considered inferior to More and Levensberg
2156 // - gsl_multifit_nlinear_solver_qr produces reliable results but needs more iterations than Cholesky
2177 gsl_multifit_nlinear_workspace* w = gsl_multifit_nlinear_alloc (gsl_multifit_nlinear_trust, ¶ms, data.dps.size(),
2221 // To activate, uncomment the callback lambda and change the call to gsl_multifit_nlinear_driver
2222 /*auto callback = [](const size_t iter, void* _params, const gsl_multifit_nlinear_workspace * w)
2249 qCDebug(KSTARS_EKOS_FOCUS) << QString("Starting LM solver, fit=plane, solver=%1, scale=%2, trs=%3, iters=%4, xtol=%5,"
2260 QString("LM solver (Plane): Failed after %1ms iters=%2 [attempt=%3] with status=%4 [%5] and info=%6 [%7]")
2261 .arg(timer.elapsed()).arg(gsl_multifit_nlinear_niter(w)).arg(attempt + 1).arg(status).arg(gsl_strerror(status))
2273 qCDebug(KSTARS_EKOS_FOCUS) << QString("LM Solver (Plane): Solution found after %1ms %2 iters (%3). A=%4, B=%5, C=%6")
2291// Initialise parameters before starting the solver. Its important to start with a guess as near to the solution as possible
2295 // If we are retrying then perturb the initial conditions. The hope is that by doing this the solver
2299 if (!m_FirstSolverRun && (m_LastCurveType == FOCUS_PLANE) && (m_LastCoefficients.size() == NUM_PLANE_PARAMS) && attempt < 3)
2313 qCDebug(KSTARS_EKOS_FOCUS) << QString("LM Solver (Plane): Guess perturbation=%1, A=%2, B=%3, C=%4")
2322void CurveFitting::plaSetupParams(gsl_multifit_nlinear_parameters *params, int *numIters, double *xtol, double *gtol,
2333 // avmax is the max allowed ratio of 2nd order term (acceleration, a) to the 1st order term (velocity, v)
2338 // - gsl_multifit_nlinear_scale_more uses. More strategy. Good for problems with parameters with widely different scales
2339 // - gsl_multifit_nlinear_scale_levenberg. Levensberg strategy. Can be good but not scale invariant.
2340 // - gsl_multifit_nlinear_scale_marquardt. Marquardt strategy. Considered inferior to More and Levensberg
2344 // - gsl_multifit_nlinear_solver_qr produces reliable results but needs more iterations than Cholesky
2355bool CurveFitting::findMinMax(double expected, double minPosition, double maxPosition, double *position, double *value,
2378 // If we couldn't fit a curve then something's wrong so reset coefficients which will force the next run of the LM solver to start from scratch
2383bool CurveFitting::minimumQuadratic(double expected, double minPosition, double maxPosition, double *position,
2432bool CurveFitting::minMaxHyperbola(double expected, double minPosition, double maxPosition, double *position,
2439 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::minimumHyperbola coefficients.size()=%1").arg(
2450 // Check 2: At the minimum position (=c), the value of f(x) (which is the HFR) given by b+d is > 0
2454 ((optDir == OPTIMISATION_MINIMISE && b > 0.0) || (optDir == OPTIMISATION_MAXIMISE && b < 0.0)))
2464bool CurveFitting::minMaxParabola(double expected, double minPosition, double maxPosition, double *position,
2471 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::minimumParabola coefficients.size()=%1").arg(
2482 // Check 2: At the minimum position (=c), the value of f(x) (which is the HFR) given by a is > 0
2486 ((optDir == OPTIMISATION_MINIMISE && b > 0.0) || (optDir == OPTIMISATION_MAXIMISE && b < 0.0)))
2496bool CurveFitting::minMax2DGaussian(double expected, double minPosition, double maxPosition, double *position,
2506 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::minMax2DGaussian coefficients.size()=%1").arg(
2519 // Check 2: At the max/min position (=c), the value of f(x) (which is the HFR) given by a + b is > 0
2523 ((optDir == OPTIMISATION_MINIMISE && b < 0.0) || (optDir == OPTIMISATION_MAXIMISE && b > 0.0)))
2546 // If we couldn't fit a curve then something's wrong so reset coefficients which will force the next run of the LM solver to start from scratch
2557 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::getGaussianParams coefficients.size()=%1").arg(
2573 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::getGaussianParams a=%1 b=%2 x0=%3 y0=%4").arg(a).arg(b)
2595 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::getGaussianParams FWHM=%1").arg(FWHM);
2611// R2 (R squared) is the coefficient of determination gives a measure of how well the curve fits the datapoints.
2612// It lies between 0 and 1. 1 means that all datapoints will lie on the curve which therefore exactly describes the
2625 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::calculateR2 called for Quadratic");
2632 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::calculateR2 hyperbola coefficients.size()=").arg(
2642 curvePoints.push_back(hypfx(m_x[i], m_coefficients[A_IDX], m_coefficients[B_IDX], m_coefficients[C_IDX],
2655 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::calculateR2 parabola coefficients.size()=").arg(
2665 curvePoints.push_back(parfx(m_x[i], m_coefficients[A_IDX], m_coefficients[B_IDX], m_coefficients[C_IDX]));
2677 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::calculateR2 2D gaussian coefficients.size()=").arg(
2687 curvePoints.push_back(gau2Dfx(m_x[i], m_coefficients[A_IDX], m_coefficients[B_IDX], m_coefficients[C_IDX],
2700 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::calculateR2 gaussian coefficients.size()=").arg(
2708 curvePoints.push_back(gaufxy(m_dataPoints.dps[i].x, m_dataPoints.dps[i].y, m_coefficients[A_IDX],
2722 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::calculateR2 plane coefficients.size()=").arg(
2730 curvePoints.push_back(plafxy(m_dataPoints.dps[i].x, m_dataPoints.dps[i].y, m_coefficients[A_IDX],
2740 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::calculateR2 curveFit=%1").arg(curveFit);
2749double CurveFitting::calcR2(const QVector<double> dataPoints, const QVector<double> curvePoints,
2773 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::calcR2 tss=%1").arg(totalSumSquares);
2781void CurveFitting::calculateCurveDeltas(CurveFit curveFit, std::vector<std::pair<int, double>> &curveDeltas)
2789 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::calculateCurveDeltas called for Quadratic");
2795 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::calculateCurveDeltas hyperbola coefficients.size()=").arg(
2802 curveDeltas.push_back(std::make_pair(i, abs(m_y[i] - hypfx(m_x[i], m_coefficients[A_IDX], m_coefficients[B_IDX],
2809 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::calculateCurveDeltas parabola coefficients.size()=").arg(
2816 curveDeltas.push_back(std::make_pair(i, abs(m_y[i] - parfx(m_x[i], m_coefficients[A_IDX], m_coefficients[B_IDX],
2823 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::calculateCurveDeltas 2D gaussian coefficients.size()=").arg(
2830 curveDeltas.push_back(std::make_pair(i, abs(m_y[i] - gau2Dfx(m_x[i], m_coefficients[A_IDX], m_coefficients[B_IDX],
2836 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::calculateCurveDeltas called for 3D Gaussian");
2840 qCDebug(KSTARS_EKOS_FOCUS) << QString("Error in CurveFitting::calculateCurveDeltas curveFit=%1").arg(curveFit);
KGuiItem ok()
NETWORKMANAGERQT_EXPORT NetworkManager::Status status()
void start()
void append(QList< T > &&value)
void clear()
void push_back(parameter_type value)
qsizetype size() const const
QString & append(QChar ch)
QString arg(Args &&... args) const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:04:46 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:04:46 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.