[apps/regression] Ensure unicity for trigonometric regression

This commit is contained in:
Hugo Saint-Vignes
2020-12-09 12:04:01 +01:00
committed by LeaNumworks
parent 94b2da8e60
commit 79e59f525e
4 changed files with 26 additions and 0 deletions

View File

@@ -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);
}

View File

@@ -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 {}
};
}

View File

@@ -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];

View File

@@ -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;
};