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

0001 #include "polynomialfit.h"
0002 
0003 #include "ekos/ekos.h"
0004 #include <gsl/gsl_fit.h>
0005 #include <gsl/gsl_vector.h>
0006 #include <gsl/gsl_min.h>
0007 #include <ekos_focus_debug.h>
0008 
0009 namespace Ekos
0010 {
0011 
0012 PolynomialFit::PolynomialFit(int degree_, uint8_t maxCount, const QVector<double> &x_, const QVector<double> &y_)
0013     : degree(degree_), x(x_), y(y_)
0014 {
0015     Q_ASSERT(x_.size() == y_.size());
0016     QVector<QPointF> values;
0017     for (int i = 0; i < x.count(); i++)
0018         values << QPointF(x[i], y[i]);
0019 
0020     std::sort(values.begin(), values.end(), [](const QPointF & a, const QPointF & b)
0021     {
0022         return a.y() < b.y();
0023     });
0024 
0025     while(values.count() > maxCount)
0026         values.takeLast();
0027 
0028     x.clear();
0029     y.clear();
0030 
0031     for (const auto &onePoint : values)
0032     {
0033         x << onePoint.x();
0034         y << onePoint.y();
0035     }
0036 
0037     solve(x, y);
0038 }
0039 
0040 PolynomialFit::PolynomialFit(int degree_, const QVector<int> &x_, const QVector<double> &y_)
0041     : degree(degree_), y(y_)
0042 {
0043     Q_ASSERT(x_.size() == y_.size());
0044     for (int i = 0; i < x_.size(); ++i)
0045     {
0046         x.push_back(static_cast<double>(x_[i]));
0047     }
0048     solve(x, y);
0049 }
0050 
0051 void PolynomialFit::solve(const QVector<double> &x, const QVector<double> &y)
0052 {
0053     double chisq = 0;
0054     coefficients = gsl_polynomial_fit(x.data(), y.data(), x.count(), degree, chisq);
0055 }
0056 
0057 double PolynomialFit::polynomialFunction(double x, void *params)
0058 {
0059     PolynomialFit *instance = static_cast<PolynomialFit *>(params);
0060 
0061     if (instance && !instance->coefficients.empty())
0062         return instance->f(x);
0063     else
0064         return -1;
0065 }
0066 
0067 double PolynomialFit::f(double x)
0068 {
0069     const int order = coefficients.size() - 1;
0070     double sum = 0;
0071     for (int i = 0; i <= order; ++i)
0072         sum += coefficients[i] * pow(x, i);
0073     return sum;
0074 }
0075 
0076 bool PolynomialFit::findMinimum(double expected, double minPosition, double maxPosition, double *position, double *value)
0077 {
0078     int status;
0079     int iter = 0, max_iter = 100;
0080     const gsl_min_fminimizer_type *T;
0081     gsl_min_fminimizer *s;
0082     double m = expected;
0083 
0084     gsl_function F;
0085     F.function = &PolynomialFit::polynomialFunction;
0086     F.params   = this;
0087 
0088     // Must turn off error handler or it aborts on error
0089     gsl_set_error_handler_off();
0090 
0091     T      = gsl_min_fminimizer_brent;
0092     s      = gsl_min_fminimizer_alloc(T);
0093     status = gsl_min_fminimizer_set(s, &F, expected, minPosition, maxPosition);
0094 
0095     if (status != GSL_SUCCESS)
0096     {
0097         qCWarning(KSTARS_EKOS_FOCUS) << "Focus GSL error:" << gsl_strerror(status);
0098         return false;
0099     }
0100 
0101     do
0102     {
0103         iter++;
0104         status = gsl_min_fminimizer_iterate(s);
0105 
0106         m = gsl_min_fminimizer_x_minimum(s);
0107         minPosition = gsl_min_fminimizer_x_lower(s);
0108         maxPosition = gsl_min_fminimizer_x_upper(s);
0109 
0110         status = gsl_min_test_interval(minPosition, maxPosition, 0.01, 0.0);
0111 
0112         if (status == GSL_SUCCESS)
0113         {
0114             *position = m;
0115             *value    = polynomialFunction(m, this);
0116         }
0117     }
0118     while (status == GSL_CONTINUE && iter < max_iter);
0119 
0120     gsl_min_fminimizer_free(s);
0121     return (status == GSL_SUCCESS);
0122 }
0123 }  // namespace
0124