diff --git a/apps/regression/model/model.cpp b/apps/regression/model/model.cpp index 2d223ec7e..8aec7709a 100644 --- a/apps/regression/model/model.cpp +++ b/apps/regression/model/model.cpp @@ -35,6 +35,7 @@ void Model::fit(Store * store, int series, double * modelCoefficients, Poincare: if (dataSuitableForFit(store, series)) { initCoefficientsForFit(modelCoefficients, k_initialCoefficientValue, false, store, series); fitLevenbergMarquardt(store, series, modelCoefficients, context); + uniformizeCoefficientsFromFit(modelCoefficients); } else { initCoefficientsForFit(modelCoefficients, NAN, true); } diff --git a/apps/regression/model/model.h b/apps/regression/model/model.h index 78f14aab6..1b36fa6a8 100644 --- a/apps/regression/model/model.h +++ b/apps/regression/model/model.h @@ -64,6 +64,7 @@ private: int solveLinearSystem(double * solutions, double * coefficients, double * constants, int solutionDimension, Poincare::Context * context); void initCoefficientsForFit(double * modelCoefficients, double defaultValue, bool forceDefaultValue, Store * store = nullptr, int series = -1) const; virtual void specializedInitCoefficientsForFit(double * modelCoefficients, double defaultValue, Store * store = nullptr, int series = -1) const; + virtual void uniformizeCoefficientsFromFit(double * modelCoefficients) const {} }; } diff --git a/apps/regression/model/trigonometric_model.cpp b/apps/regression/model/trigonometric_model.cpp index aba971665..b8338964e 100644 --- a/apps/regression/model/trigonometric_model.cpp +++ b/apps/regression/model/trigonometric_model.cpp @@ -104,6 +104,29 @@ void TrigonometricModel::specializedInitCoefficientsForFit(double * modelCoeffic modelCoefficients[2] = 0.0; } +void TrigonometricModel::uniformizeCoefficientsFromFit(double * modelCoefficients) const { + // Coefficients must be unique. + double piInAngleUnit = M_PI / toRadians(Poincare::Preferences::sharedPreferences()->angleUnit()); + // A must be positive. + if (modelCoefficients[0] < 0) { + // A * sin(B * x + C) + D = -A * sin(B * x + C + π) + D + modelCoefficients[0] *= -1; + modelCoefficients[2] += piInAngleUnit; + } + // B must be positive. + if (modelCoefficients[1] < 0) { + // A * sin(B * x + C) + D = -A * sin(-B * x - C) + D + // -A * sin(-B * x - C) + D = A * sin(-B * x - C + π) + D + modelCoefficients[1] *= -1; + modelCoefficients[2] *= -1; + modelCoefficients[2] += piInAngleUnit; + } + // C must be between -π and π. + // A * sin(B * x + C) + D = A * sin(B * x + C - 2π) = A * sin(B * x + C + 2π) + // Using remainder(C,2π) = C - 2π * round(C / 2π) + modelCoefficients[2] -= 2 * piInAngleUnit * round(modelCoefficients[2] / (2 * piInAngleUnit)); +} + Expression TrigonometricModel::expression(double * modelCoefficients) { double a = modelCoefficients[0]; double b = modelCoefficients[1]; diff --git a/apps/regression/model/trigonometric_model.h b/apps/regression/model/trigonometric_model.h index 83ed05113..124a6353c 100644 --- a/apps/regression/model/trigonometric_model.h +++ b/apps/regression/model/trigonometric_model.h @@ -17,6 +17,7 @@ public: private: static constexpr int k_numberOfCoefficients = 4; void specializedInitCoefficientsForFit(double * modelCoefficients, double defaultValue, Store * store, int series) const override; + void uniformizeCoefficientsFromFit(double * modelCoefficients) const override; Poincare::Expression expression(double * modelCoefficients) override; };