Commit cbd71a55 authored by Stefan Gerlach's avatar Stefan Gerlach

[fit] Calculate and show correlation matrix

parent 65c9a884
......@@ -2001,14 +2001,14 @@ void XYFitCurvePrivate::recalculate() {
fitResult.bic = nsl_stats_bic(fitResult.sse, n, np, 1);
//parameter values
// GSL: const double c = GSL_MAX_DBL(1., sqrt(fitResult.rms)); // increase error for poor fit
// NIST: const double c = sqrt(fitResult.rms); // increase error for poor fit, decrease for good fit
const double c = sqrt(fitResult.rms);
fitResult.paramValues.resize(np);
fitResult.errorValues.resize(np);
fitResult.tdist_tValues.resize(np);
fitResult.tdist_pValues.resize(np);
fitResult.tdist_marginValues.resize(np);
// GSL: cerr = GSL_MAX_DBL(1., sqrt(fitResult.rms)); // increase error for poor fit
// NIST: cerr = sqrt(fitResult.rms); // increase error for poor fit, decrease for good fit
const double cerr = sqrt(fitResult.rms);
// CI = 100* (1 - alpha)
const double alpha = 1.0 - fitData.confidenceInterval/100.;
for (unsigned int i = 0; i < np; i++) {
......@@ -2019,10 +2019,12 @@ void XYFitCurvePrivate::recalculate() {
fitData.paramStartValues.data()[i] = fitResult.paramValues[i];
DEBUG(" saving parameter " << i << ": " << fitResult.paramValues[i] << ' ' << fitData.paramStartValues.data()[i]);
}
fitResult.errorValues[i] = c*sqrt(gsl_matrix_get(covar, i, i));
fitResult.errorValues[i] = cerr * sqrt(gsl_matrix_get(covar, i, i));
fitResult.tdist_tValues[i] = nsl_stats_tdist_t(fitResult.paramValues.at(i), fitResult.errorValues.at(i));
fitResult.tdist_pValues[i] = nsl_stats_tdist_p(fitResult.tdist_tValues.at(i), fitResult.dof);
fitResult.tdist_marginValues[i] = nsl_stats_tdist_margin(alpha, fitResult.dof, fitResult.errorValues.at(i));
for (unsigned int j = 0; j <= i; j++)
fitResult.correlationMatrix << gsl_matrix_get(covar, i, j)/sqrt(gsl_matrix_get(covar, i, i))/sqrt(gsl_matrix_get(covar, j, j));
}
// fill residuals vector. To get residuals on the correct x values, fill the rest with zeros.
......@@ -2285,6 +2287,11 @@ void XYFitCurve::save(QXmlStreamWriter* writer) const {
writer->writeTextElement("tdist_margin", QString::number(value, 'g', 15));
writer->writeEndElement();
writer->writeStartElement("correlationMatrix");
foreach (const double &value, d->fitResult.correlationMatrix)
writer->writeTextElement("correlation", QString::number(value, 'g', 15));
writer->writeEndElement();
//save calculated columns if available
if (d->xColumn && d->yColumn && d->residualsColumn) {
d->xColumn->save(writer);
......@@ -2382,6 +2389,8 @@ bool XYFitCurve::load(XmlStreamReader* reader, bool preview) {
d->fitResult.tdist_pValues << reader->readElementText().toDouble();
} else if (!preview && reader->name() == "tdist_margin") {
d->fitResult.tdist_marginValues << reader->readElementText().toDouble();
} else if (!preview && reader->name() == "correlation") {
d->fitResult.correlationMatrix << reader->readElementText().toDouble();
} else if (!preview && reader->name() == "fitResult") {
attribs = reader->attributes();
......@@ -2457,6 +2466,8 @@ bool XYFitCurve::load(XmlStreamReader* reader, bool preview) {
d->fitResult.tdist_pValues.resize(np);
if (d->fitResult.tdist_marginValues.size() == 0)
d->fitResult.tdist_marginValues.resize(np);
if (d->fitResult.correlationMatrix.size() == 0)
d->fitResult.correlationMatrix.resize(np*(np+1)/2);
// Loading done. Check some parameter
DEBUG("XYFitCurve::load() model type = " << d->fitData.modelType);
......
......@@ -105,6 +105,7 @@ public:
QVector<double> tdist_tValues;
QVector<double> tdist_pValues;
QVector<double> tdist_marginValues;
QVector<double> correlationMatrix;
QString solverOutput;
};
......
......@@ -228,7 +228,6 @@ void XYFitCurveDock::setupGeneral() {
* load curve settings
*/
void XYFitCurveDock::initGeneralTab() {
DEBUG("XYFitCurveDock::initGeneralTab()");
//if there are more then one curve in the list, disable the tab "general"
if (m_curvesList.size() == 1) {
uiGeneralTab.lName->setEnabled(true);
......@@ -278,9 +277,9 @@ void XYFitCurveDock::initGeneralTab() {
uiGeneralTab.sbDegree->setValue(m_fitData.degree);
if (m_fitData.paramStartValues.size() > 0)
DEBUG(" start value 1 = " << m_fitData.paramStartValues.at(0));
DEBUG(Q_FUNC_INFO << ", start value 1 = " << m_fitData.paramStartValues.at(0));
DEBUG(" model degree = " << m_fitData.degree);
DEBUG(Q_FUNC_INFO << ", model degree = " << m_fitData.degree);
uiGeneralTab.chkVisible->setChecked(m_curve->isVisible());
......@@ -298,11 +297,9 @@ void XYFitCurveDock::initGeneralTab() {
connect(fitParametersWidget, &FitParametersWidget::parametersChanged, this, &XYFitCurveDock::parametersChanged);
connect(fitParametersWidget, &FitParametersWidget::parametersValid, this, &XYFitCurveDock::parametersValid);
DEBUG("XYFitCurveDock::initGeneralTab() DONE");
}
void XYFitCurveDock::setModel() {
DEBUG("XYFitCurveDock::setModel()");
QList<AspectType> list{AspectType::Folder, AspectType::Datapicker, AspectType::Worksheet,
AspectType::CartesianPlot, AspectType::XYCurve, AspectType::XYAnalysisCurve};
cbDataSourceCurve->setTopLevelClasses(list);
......@@ -326,14 +323,12 @@ void XYFitCurveDock::setModel() {
cbYErrorColumn->setModel(m_aspectTreeModel);
XYCurveDock::setModel();
DEBUG("XYFitCurveDock::setModel() DONE");
}
/*!
sets the curves. The properties of the curves in the list \c list can be edited in this widget.
*/
void XYFitCurveDock::setCurves(QList<XYCurve*> list) {
DEBUG("XYFitCurveDock::setCurves()");
m_initializing = true;
m_curvesList = list;
m_curve = list.first();
......@@ -343,11 +338,11 @@ void XYFitCurveDock::setCurves(QList<XYCurve*> list) {
this->setModel();
m_fitData = m_fitCurve->fitData();
DEBUG("XYFitCurveDock::setCurves() model type = " << m_fitData.modelType);
DEBUG("XYFitCurveDock::setCurves() model = " << STDSTRING(m_fitData.model));
DEBUG("XYFitCurveDock::setCurves() model degree = " << m_fitData.degree);
DEBUG("XYFitCurveDock::setCurves() # params = " << m_fitData.paramNames.size());
DEBUG("XYFitCurveDock::setCurves() # start values = " << m_fitData.paramStartValues.size());
DEBUG(Q_FUNC_INFO << ", model type = " << m_fitData.modelType);
DEBUG(Q_FUNC_INFO << ", model = " << STDSTRING(m_fitData.model));
DEBUG(Q_FUNC_INFO << ", model degree = " << m_fitData.degree);
DEBUG(Q_FUNC_INFO << ", # params = " << m_fitData.paramNames.size());
DEBUG(Q_FUNC_INFO << ", # start values = " << m_fitData.paramStartValues.size());
//for (auto startValue: m_fitData.paramStartValues)
// DEBUG("XYFitCurveDock::setCurves() start value = " << startValue);
......@@ -582,7 +577,7 @@ void XYFitCurveDock::showResults(bool checked) {
///////////////////////////////////////////////////////////////////////////
void XYFitCurveDock::xWeightChanged(int index) {
DEBUG("xWeightChanged() weight = " << nsl_fit_weight_type_name[index]);
DEBUG(Q_FUNC_INFO << ", weight = " << nsl_fit_weight_type_name[index]);
m_fitData.xWeightsType = (nsl_fit_weight_type)index;
......@@ -607,7 +602,7 @@ void XYFitCurveDock::xWeightChanged(int index) {
}
void XYFitCurveDock::yWeightChanged(int index) {
DEBUG("yWeightChanged() weight = " << nsl_fit_weight_type_name[index]);
DEBUG(Q_FUNC_INFO << ", weight = " << nsl_fit_weight_type_name[index]);
m_fitData.yWeightsType = (nsl_fit_weight_type)index;
......@@ -638,9 +633,9 @@ void XYFitCurveDock::yWeightChanged(int index) {
*/
void XYFitCurveDock::categoryChanged(int index) {
if (index == nsl_fit_model_custom) {
DEBUG("categoryChanged() category = \"nsl_fit_model_custom\"");
DEBUG(Q_FUNC_INFO << ", category = \"nsl_fit_model_custom\"");
} else {
DEBUG("categoryChanged() category = \"" << nsl_fit_model_category_name[index] << "\"");
DEBUG(Q_FUNC_INFO << ", category = \"" << nsl_fit_model_category_name[index] << "\"");
}
bool hasChanged = true;
......@@ -1244,21 +1239,35 @@ void XYFitCurveDock::showFitResult() {
uiGeneralTab.twLog->item(5, 1)->setText(numberLocale.toString(fitResult.paramValues.size()));
uiGeneralTab.twLog->item(6, 1)->setText(m_fitData.fitRange.toString());
// show all iterations
QString str;
const int np = m_fitData.paramNames.size();
// correlation matrix
QString sCorr;
for (const auto &s : m_fitData.paramNamesUtf8)
sCorr += '\t' + s;
int index{0};
DEBUG(Q_FUNC_INFO << ", correlation values size = " << fitResult.correlationMatrix.size())
for (int i = 0; i < np; i++) {
sCorr += '\n' + m_fitData.paramNamesUtf8.at(i);
for (int j = 0; j <= i; j++)
sCorr += '\t' + numberLocale.toString(fitResult.correlationMatrix.at(index++), 'f');
}
uiGeneralTab.twLog->item(7, 1)->setText(sCorr);
// iterations
QString sIter;
for (const auto &s : m_fitData.paramNamesUtf8)
str += s + '\t';
str += UTF8_QSTRING("χ²");
sIter += s + '\t';
sIter += UTF8_QSTRING("χ²");
const QStringList iterations = fitResult.solverOutput.split(';');
for (const auto &s : iterations)
if (!s.isEmpty())
str += '\n' + s;
uiGeneralTab.twLog->item(7, 1)->setText(str);
sIter += '\n' + s;
uiGeneralTab.twLog->item(8, 1)->setText(sIter);
uiGeneralTab.twLog->resizeRowsToContents();
// Parameters
const int np = m_fitData.paramNames.size();
uiGeneralTab.twParameters->setRowCount(np);
for (int i = 0; i < np; i++) {
......
......@@ -255,7 +255,7 @@
<bool>true</bool>
</property>
<property name="currentIndex">
<number>1</number>
<number>2</number>
</property>
<widget class="QWidget" name="tab_3">
<attribute name="title">
......@@ -463,7 +463,7 @@
<bool>true</bool>
</property>
<property name="rowCount">
<number>8</number>
<number>9</number>
</property>
<property name="columnCount">
<number>2</number>
......@@ -491,6 +491,7 @@
<row/>
<row/>
<row/>
<row/>
<column/>
<column/>
<item row="0" column="0">
......@@ -565,7 +566,7 @@
</item>
<item row="7" column="0">
<property name="text">
<string>Iterations</string>
<string>Correlation</string>
</property>
</item>
<item row="7" column="1">
......@@ -573,6 +574,16 @@
<string/>
</property>
</item>
<item row="8" column="0">
<property name="text">
<string>Iterations</string>
</property>
</item>
<item row="8" column="1">
<property name="text">
<string/>
</property>
</item>
</widget>
</item>
</layout>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment