diff --git a/Software/PC_Application/Calibration/CalStandardLineEditDialog.ui b/Software/PC_Application/Calibration/CalStandardLineEditDialog.ui
new file mode 100644
index 0000000..92681e7
--- /dev/null
+++ b/Software/PC_Application/Calibration/CalStandardLineEditDialog.ui
@@ -0,0 +1,147 @@
+
+
+ CalStandardLineEditDialog
+
+
+
+ 0
+ 0
+ 383
+ 202
+
+
+
+ Edit Line Standard
+
+
+ true
+
+
+ -
+
+
-
+
+
+ Name:
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ Z0:
+
+
+
+ -
+
+
+ false
+
+
+
+ -
+
+
+ Delay:
+
+
+
+ -
+
+
+ -
+
+
+ Minimum usable frequency:
+
+
+
+ -
+
+
+ false
+
+
+
+ -
+
+
+ Maximum usable frequency:
+
+
+
+ -
+
+
+ false
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+ SIUnitEdit
+ QLineEdit
+ CustomWidgets/siunitedit.h
+
+
+
+
+
+ buttonBox
+ accepted()
+ CalStandardLineEditDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ CalStandardLineEditDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
+
+
+
diff --git a/Software/PC_Application/Calibration/CalStandardReflectEditDialog.ui b/Software/PC_Application/Calibration/CalStandardReflectEditDialog.ui
new file mode 100644
index 0000000..486ae8b
--- /dev/null
+++ b/Software/PC_Application/Calibration/CalStandardReflectEditDialog.ui
@@ -0,0 +1,106 @@
+
+
+ CalStandardReflectEditDialog
+
+
+
+ 0
+ 0
+ 291
+ 109
+
+
+
+ Edit Reflect Standard
+
+
+ true
+
+
+ -
+
+
-
+
+
+ Name:
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ Reflection type:
+
+
+
+ -
+
+
-
+
+ Open
+
+
+ -
+
+ Short
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ CalStandardReflectEditDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ CalStandardReflectEditDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/Software/PC_Application/Calibration/calibration.cpp b/Software/PC_Application/Calibration/calibration.cpp
index 00d23fe..b328a48 100644
--- a/Software/PC_Application/Calibration/calibration.cpp
+++ b/Software/PC_Application/Calibration/calibration.cpp
@@ -3,6 +3,7 @@
#include "CustomWidgets/informationbox.h"
#include "Util/app_common.h"
#include "unit.h"
+#include "Util/util.h"
#include "LibreCAL/librecaldialog.h"
#include "Eigen/Dense"
@@ -296,6 +297,7 @@ QString Calibration::TypeToString(Calibration::Type type)
case Type::None: return "None";
case Type::SOLT: return "SOLT";
case Type::ThroughNormalization: return "ThroughNormalization";
+ case Type::TRL: return "TRL";
case Type::Last: return "Invalid";
}
}
@@ -560,6 +562,12 @@ void Calibration::edit()
}
}
}
+ // update calibration (may have changed due to deleted measurement)
+ if(canCompute(caltype)) {
+ compute(caltype);
+ } else {
+ deactivate();
+ }
updateMeasurementTable();
updateCalibrationList();
});
@@ -605,6 +613,12 @@ void Calibration::edit()
for(auto s : selected) {
measurements[s.row()]->clearPoints();
}
+ // update calibration (may have changed due to deleted measurement)
+ if(canCompute(caltype)) {
+ compute(caltype);
+ } else {
+ deactivate();
+ }
updateMeasurementTable();
updateCalibrationList();
});
@@ -647,8 +661,11 @@ CalibrationMeasurement::Base *Calibration::newMeasurement(CalibrationMeasurement
case CalibrationMeasurement::Base::Type::Open: m = new CalibrationMeasurement::Open(this); break;
case CalibrationMeasurement::Base::Type::Short: m = new CalibrationMeasurement::Short(this); break;
case CalibrationMeasurement::Base::Type::Load: m = new CalibrationMeasurement::Load(this); break;
+ case CalibrationMeasurement::Base::Type::SlidingLoad: m = new CalibrationMeasurement::SlidingLoad(this); break;
+ case CalibrationMeasurement::Base::Type::Reflect: m = new CalibrationMeasurement::Reflect(this); break;
case CalibrationMeasurement::Base::Type::Through: m = new CalibrationMeasurement::Through(this); break;
case CalibrationMeasurement::Base::Type::Isolation: m = new CalibrationMeasurement::Isolation(this); break;
+ case CalibrationMeasurement::Base::Type::Line: m = new CalibrationMeasurement::Line(this); break;
}
return m;
}
@@ -679,13 +696,33 @@ Calibration::Point Calibration::computeSOLT(double f)
auto p = caltype.usedPorts[i];
auto _short = static_cast(findMeasurement(CalibrationMeasurement::Base::Type::Short, p));
auto open = static_cast(findMeasurement(CalibrationMeasurement::Base::Type::Open, p));
- auto load = static_cast(findMeasurement(CalibrationMeasurement::Base::Type::Load, p));
auto s_m = _short->getMeasured(f);
auto o_m = open->getMeasured(f);
- auto l_m = load->getMeasured(f);
auto s_c = _short->getActual(f);
auto o_c = open->getActual(f);
- auto l_c = load->getActual(f);
+ complex l_c, l_m;
+ auto slidingMeasurements = findMeasurements(CalibrationMeasurement::Base::Type::SlidingLoad, p);
+ if(slidingMeasurements.size() >= 3) {
+ // use sliding load
+ vector> slidingMeasured;
+ for(auto m : slidingMeasurements) {
+ auto slidingLoad = static_cast(m);
+ auto value = slidingLoad->getMeasured(f);
+ if(isnan(abs(value))) {
+ throw runtime_error("missing sliding load measurement");
+ }
+ slidingMeasured.push_back(value);
+ }
+ // use center of measurement for ideal load measurement
+ l_m = Util::findCenterOfCircle(slidingMeasured);
+ // assume perfect sliding load
+ l_c = 0.0;
+ } else {
+ // use normal load standard
+ auto load = static_cast(findMeasurement(CalibrationMeasurement::Base::Type::Load, p));
+ l_c = load->getActual(f);
+ l_m = load->getMeasured(f);
+ }
auto denom = l_c * o_c * (o_m - l_m) + l_c * s_c * (l_m - s_m) + o_c * s_c * (s_m - o_m);
point.D[i] = (l_c * o_m * (s_m * (o_c - s_c) + l_m * s_c) - l_c * o_c * l_m * s_m + o_c * l_m * s_c * (s_m - o_m)) / denom;
point.S[i] = (l_c * (o_m - s_m) + o_c * (s_m - l_m) + s_c * (l_m - o_m)) / denom;
@@ -1203,7 +1240,13 @@ bool Calibration::canCompute(Calibration::CalType type, double *startFreq, doubl
for(auto p : type.usedPorts) {
required.push_back({.type = CalibrationMeasurement::Base::Type::Short, .port1 = p});
required.push_back({.type = CalibrationMeasurement::Base::Type::Open, .port1 = p});
- required.push_back({.type = CalibrationMeasurement::Base::Type::Load, .port1 = p});
+ if(findMeasurements(CalibrationMeasurement::Base::Type::SlidingLoad, p).size() >= 3) {
+ // got enough sliding load measurements, use these
+ required.push_back({.type = CalibrationMeasurement::Base::Type::SlidingLoad, .port1 = p});
+ } else {
+ // not enough sliding load measurement, use normal load
+ required.push_back({.type = CalibrationMeasurement::Base::Type::Load, .port1 = p});
+ }
}
// through measurements between all ports
for(int i=1;i<=type.usedPorts.size();i++) {
@@ -1220,6 +1263,19 @@ bool Calibration::canCompute(Calibration::CalType type, double *startFreq, doubl
}
}
break;
+ case Type::TRL:
+ // Reflect measurement for every port
+ for(auto p : type.usedPorts) {
+ required.push_back({.type = CalibrationMeasurement::Base::Type::Reflect, .port1 = p});
+ }
+ // through and line measurements between all ports
+ for(int i=1;i<=type.usedPorts.size();i++) {
+ for(int j=i+1;j<=type.usedPorts.size();j++) {
+ required.push_back({.type = CalibrationMeasurement::Base::Type::Through, .port1 = i, .port2 = j});
+ required.push_back({.type = CalibrationMeasurement::Base::Type::Line, .port1 = i, .port2 = j});
+ }
+ }
+ break;
}
if(required.size() > 0) {
vector foundMeasurements;
@@ -1278,6 +1334,7 @@ int Calibration::minimumPorts(Calibration::Type type)
switch(type) {
case Type::SOLT: return 1;
case Type::ThroughNormalization: return 2;
+ case Type::TRL: return 2;
}
return -1;
}
@@ -1415,8 +1472,9 @@ bool Calibration::hasFrequencyOverlap(std::vector Calibration::findMeasurements(CalibrationMeasurement::Base::Type type, int port1, int port2)
{
+ vector ret;
for(auto m : measurements) {
if(m->getType() != type) {
continue;
@@ -1434,9 +1492,19 @@ CalibrationMeasurement::Base *Calibration::findMeasurement(CalibrationMeasuremen
}
}
// if we get here, we have a match
- return m;
+ ret.push_back(m);
+ }
+ return ret;
+}
+
+CalibrationMeasurement::Base *Calibration::findMeasurement(CalibrationMeasurement::Base::Type type, int port1, int port2)
+{
+ auto meas = findMeasurements(type, port1, port2);
+ if(meas.size() > 0) {
+ return meas[0];
+ } else {
+ return nullptr;
}
- return nullptr;
}
QString Calibration::CalType::getReadableDescription()
diff --git a/Software/PC_Application/Calibration/calibration.h b/Software/PC_Application/Calibration/calibration.h
index 2d49efa..b082fec 100644
--- a/Software/PC_Application/Calibration/calibration.h
+++ b/Software/PC_Application/Calibration/calibration.h
@@ -19,6 +19,7 @@ public:
None,
SOLT,
ThroughNormalization,
+ TRL,
Last,
};
class CalType {
@@ -121,8 +122,10 @@ private:
void deleteMeasurements();
bool hasFrequencyOverlap(std::vector m, double *startFreq = nullptr, double *stopFreq = nullptr, int *points = nullptr);
+ // returns all measurements that match the paramaters
+ std::vector findMeasurements(CalibrationMeasurement::Base::Type type, int port1 = 0, int port2 = 0);
+ // returns the first measurement in the list that matches the parameters
CalibrationMeasurement::Base* findMeasurement(CalibrationMeasurement::Base::Type type, int port1 = 0, int port2 = 0);
-
CalibrationMeasurement::Base *newMeasurement(CalibrationMeasurement::Base::Type type);
class Point {
diff --git a/Software/PC_Application/Calibration/calibrationmeasurement.cpp b/Software/PC_Application/Calibration/calibrationmeasurement.cpp
index 35d616c..2d04fc6 100644
--- a/Software/PC_Application/Calibration/calibrationmeasurement.cpp
+++ b/Software/PC_Application/Calibration/calibrationmeasurement.cpp
@@ -86,8 +86,11 @@ QString CalibrationMeasurement::Base::TypeToString(CalibrationMeasurement::Base:
case Type::Open: return "Open";
case Type::Short: return "Short";
case Type::Load: return "Load";
+ case Type::SlidingLoad: return "SlidingLoad";
+ case Type::Reflect: return "Reflect";
case Type::Through: return "Through";
case Type::Isolation: return "Isolation";
+ case Type::Line: return "Line";
case Type::Last: return "Invalid";
}
}
@@ -678,3 +681,8 @@ std::vector CalibrationMeasurement::Is
{
return points;
}
+
+QWidget *CalibrationMeasurement::SlidingLoad::createStandardWidget()
+{
+ return new QLabel("Connect sliding load");
+}
diff --git a/Software/PC_Application/Calibration/calibrationmeasurement.h b/Software/PC_Application/Calibration/calibrationmeasurement.h
index 985417c..c77fadc 100644
--- a/Software/PC_Application/Calibration/calibrationmeasurement.h
+++ b/Software/PC_Application/Calibration/calibrationmeasurement.h
@@ -21,8 +21,11 @@ public:
Open,
Short,
Load,
+ SlidingLoad,
+ Reflect,
Through,
Isolation,
+ Line,
Last,
};
@@ -138,6 +141,31 @@ public:
virtual Type getType() override {return Type::Load;}
};
+class SlidingLoad : public OnePort
+{
+ Q_OBJECT
+public:
+ SlidingLoad(Calibration *cal) :
+ OnePort(cal){setFirstSupportedStandard();}
+
+ virtual QWidget* createStandardWidget() override;
+
+ virtual std::set supportedStandardTypes() override {return {};}
+ virtual Type getType() override {return Type::SlidingLoad;}
+};
+
+class Reflect : public OnePort
+{
+ Q_OBJECT
+public:
+ Reflect(Calibration *cal) :
+ OnePort(cal){setFirstSupportedStandard();}
+
+ virtual std::set supportedStandardTypes() override {return {CalStandard::Virtual::Type::Open,
+ CalStandard::Virtual::Type::Short, CalStandard::Virtual::Type::Reflect};}
+ virtual Type getType() override {return Type::Reflect;}
+};
+
class TwoPort : public Base
{
Q_OBJECT
@@ -234,5 +262,15 @@ protected:
std::vector points;
};
+class Line : public TwoPort
+{
+ Q_OBJECT
+public:
+ Line(Calibration *cal) :
+ TwoPort(cal){setFirstSupportedStandard();}
+ virtual std::set supportedStandardTypes() override {return {CalStandard::Virtual::Type::Line};}
+ virtual Type getType() override {return Type::Line;}
+};
+
}
#endif // CALIBRATIONMEASUREMENT_H
diff --git a/Software/PC_Application/Calibration/calstandard.cpp b/Software/PC_Application/Calibration/calstandard.cpp
index 7f731b7..c1fd8d4 100644
--- a/Software/PC_Application/Calibration/calstandard.cpp
+++ b/Software/PC_Application/Calibration/calstandard.cpp
@@ -2,7 +2,9 @@
#include "ui_CalStandardOpenEditDialog.h"
#include "ui_CalStandardShortEditDialog.h"
#include "ui_CalStandardLoadEditDialog.h"
+#include "ui_CalStandardReflectEditDialog.h"
#include "ui_CalStandardThroughEditDialog.h"
+#include "ui_CalStandardLineEditDialog.h"
#include "unit.h"
#include "Util/util.h"
@@ -23,8 +25,9 @@ Virtual *Virtual::create(Virtual::Type type)
case Type::Open: return new Open;
case Type::Short: return new Short;
case Type::Load: return new Load;
+ case Type::Reflect: return new Reflect;
case Type::Through: return new Through;
- case Type::Line: // TODO
+ case Type::Line: return new Line;
case Type::Last:
break;
}
@@ -46,6 +49,7 @@ QString Virtual::TypeToString(Virtual::Type type)
case Type::Open: return "Open";
case Type::Short: return "Short";
case Type::Load: return "Load";
+ case Type::Reflect: return "Reflect";
case Type::Through: return "Through";
case Type::Line: return "Line";
case Type::Last: return "Invalid";
@@ -677,3 +681,123 @@ void Through::fromJSON(nlohmann::json j)
delay = j.value("delay", 0.0);
loss = j.value("loss", 0.0);
}
+
+Reflect::Reflect()
+{
+ isShort = true;
+}
+
+std::complex Reflect::toS11(double freq)
+{
+ Q_UNUSED(freq)
+ return std::numeric_limits>::quiet_NaN();
+}
+
+void Reflect::edit(std::function finishedCallback)
+{
+ auto d = new QDialog;
+ auto ui = new Ui::CalStandardReflectEditDialog;
+ ui->setupUi(d);
+
+ ui->name->setText(name);
+ ui->type->setCurrentIndex(isShort ? 1 : 0);
+
+ QObject::connect(d, &QDialog::accepted, [=](){
+ name = ui->name->text();
+ isShort = ui->type->currentIndex() == 1;
+ if(finishedCallback) {
+ finishedCallback();
+ }
+ });
+
+ d->show();
+}
+
+nlohmann::json Reflect::toJSON()
+{
+ auto j = OnePort::toJSON();
+ j["isShort"] = isShort;
+ return j;
+}
+
+void Reflect::fromJSON(nlohmann::json j)
+{
+ OnePort::fromJSON(j);
+ isShort = j.value("isShort", true);
+}
+
+Line::Line()
+{
+ Z0 = 50.0;
+ setDelay(0.0);
+}
+
+Sparam Line::toSparam(double freq)
+{
+ Sparam ret;
+ ret.m11 = numeric_limits>::quiet_NaN();
+ ret.m12 = numeric_limits>::quiet_NaN();
+ ret.m21 = numeric_limits>::quiet_NaN();
+ ret.m22 = numeric_limits>::quiet_NaN();
+ return ret;
+}
+
+void Line::edit(std::function finishedCallback)
+{
+ auto d = new QDialog;
+ auto ui = new Ui::CalStandardLineEditDialog;
+ ui->setupUi(d);
+
+ ui->name->setText(name);
+ ui->Z0->setUnit("Ω");
+ ui->Z0->setPrecision(2);
+ ui->Z0->setValue(Z0);
+ ui->delay->setValue(delay);
+ ui->delay->setUnit("s");
+ ui->delay->setPrefixes("pnum ");
+ ui->delay->setPrecision(4);
+ ui->minFreq->setUnit("Hz");
+ ui->minFreq->setPrecision(3);
+ ui->minFreq->setPrefixes(" kMG");
+ ui->minFreq->setValue(minFreq);
+ ui->maxFreq->setUnit("Hz");
+ ui->maxFreq->setPrecision(3);
+ ui->maxFreq->setPrefixes(" kMG");
+ ui->maxFreq->setValue(maxFreq);
+
+ QObject::connect(ui->delay, &SIUnitEdit::valueChanged, [=](double val){
+ ui->minFreq->setValue(1.0 / val * 20 / 360);
+ ui->maxFreq->setValue(1.0 / val * 160 / 360);
+ });
+
+ QObject::connect(d, &QDialog::accepted, [=](){
+ name = ui->name->text();
+ Z0 = ui->Z0->value();
+ setDelay(ui->delay->value());
+ if(finishedCallback) {
+ finishedCallback();
+ }
+ });
+
+ d->show();
+}
+
+nlohmann::json Line::toJSON()
+{
+ auto j = TwoPort::toJSON();
+ j["delay"] = delay;
+ return j;
+}
+
+void Line::fromJSON(nlohmann::json j)
+{
+ TwoPort::fromJSON(j);
+ setDelay(j.value("delay", 0.0));
+}
+
+void Line::setDelay(double delay)
+{
+ this->delay = delay;
+ minFreq = 1.0 / delay * 20 / 360;
+ maxFreq = 1.0 / delay * 160 / 360;
+}
diff --git a/Software/PC_Application/Calibration/calstandard.h b/Software/PC_Application/Calibration/calstandard.h
index daeed38..029040c 100644
--- a/Software/PC_Application/Calibration/calstandard.h
+++ b/Software/PC_Application/Calibration/calstandard.h
@@ -20,6 +20,7 @@ public:
Open,
Short,
Load,
+ Reflect,
Through,
Line,
Last
@@ -126,6 +127,23 @@ private:
bool Cfirst;
};
+class Reflect : public OnePort
+{
+public:
+ Reflect();
+ Reflect(QString name, bool isShort)
+ : OnePort(name), isShort(isShort){}
+
+ virtual std::complex toS11(double freq) override;
+ virtual void edit(std::function finishedCallback = nullptr) override;
+ virtual Type getType() override {return Type::Reflect;}
+ virtual nlohmann::json toJSON() override;
+ virtual void fromJSON(nlohmann::json j) override;
+private:
+ bool isShort;
+};
+
+
class TwoPort : public Virtual
{
public:
@@ -161,6 +179,23 @@ private:
double Z0, delay, loss;
};
+class Line : public TwoPort
+{
+public:
+ Line();
+ Line(QString name, double Z0, double delay)
+ : TwoPort(name), Z0(Z0), delay(delay){}
+
+ virtual Sparam toSparam(double freq) override;
+ virtual void edit(std::function finishedCallback = nullptr) override;
+ virtual Type getType() override {return Type::Line;}
+ virtual nlohmann::json toJSON() override;
+ virtual void fromJSON(nlohmann::json j) override;
+private:
+ void setDelay(double delay);
+ double Z0, delay;
+};
+
}
#endif // CALSTANDARD_H
diff --git a/Software/PC_Application/LibreVNA-GUI.pro b/Software/PC_Application/LibreVNA-GUI.pro
index 4e3837e..075df2f 100644
--- a/Software/PC_Application/LibreVNA-GUI.pro
+++ b/Software/PC_Application/LibreVNA-GUI.pro
@@ -278,8 +278,10 @@ osx:LIBS += $(shell pkg-config --libs libusb-1.0)
QT += widgets network
FORMS += \
+ Calibration/CalStandardLineEditDialog.ui \
Calibration/CalStandardLoadEditDialog.ui \
Calibration/CalStandardOpenEditDialog.ui \
+ Calibration/CalStandardReflectEditDialog.ui \
Calibration/CalStandardShortEditDialog.ui \
Calibration/CalStandardThroughEditDialog.ui \
Calibration/LibreCAL/librecaldialog.ui \
diff --git a/Software/PC_Application/Util/util.cpp b/Software/PC_Application/Util/util.cpp
index a762c0a..610e254 100644
--- a/Software/PC_Application/Util/util.cpp
+++ b/Software/PC_Application/Util/util.cpp
@@ -90,3 +90,82 @@ unsigned long long Util::random(unsigned long long max)
std::uniform_int_distribution distribute(0, max);
return distribute(generator);
}
+
+std::complex Util::findCenterOfCircle(const std::vector > &points)
+{
+ int i,iter,IterMAX=99;
+
+ double Xi,Yi,Zi;
+ double Mz,Mxy,Mxx,Myy,Mxz,Myz,Mzz,Cov_xy,Var_z;
+ double A0,A1,A2,A22;
+ double Dy,xnew,x,ynew,y;
+ double DET,Xcenter,Ycenter;
+
+ // find means
+ double meanX = 0.0, meanY = 0.0;
+ for(auto p : points) {
+ meanX += p.real();
+ meanY += p.imag();
+ }
+ meanX /= points.size();
+ meanY /= points.size();
+
+ // computing moments
+
+ Mxx=Myy=Mxy=Mxz=Myz=Mzz=0.;
+
+ for (i=0; i<(int) points.size(); i++)
+ {
+ Xi = points[i].real() - meanX; // centered x-coordinates
+ Yi = points[i].imag() - meanY; // centered y-coordinates
+ Zi = Xi*Xi + Yi*Yi;
+
+ Mxy += Xi*Yi;
+ Mxx += Xi*Xi;
+ Myy += Yi*Yi;
+ Mxz += Xi*Zi;
+ Myz += Yi*Zi;
+ Mzz += Zi*Zi;
+ }
+ Mxx /= points.size();
+ Myy /= points.size();
+ Mxy /= points.size();
+ Mxz /= points.size();
+ Myz /= points.size();
+ Mzz /= points.size();
+
+ // computing the coefficients of the characteristic polynomial
+
+ Mz = Mxx + Myy;
+ Cov_xy = Mxx*Myy - Mxy*Mxy;
+ Var_z = Mzz - Mz*Mz;
+
+ A2 = 4.0*Cov_xy - 3.0*Mz*Mz - Mzz;
+ A1 = Var_z*Mz + 4.0*Cov_xy*Mz - Mxz*Mxz - Myz*Myz;
+ A0 = Mxz*(Mxz*Myy - Myz*Mxy) + Myz*(Myz*Mxx - Mxz*Mxy) - Var_z*Cov_xy;
+ A22 = A2 + A2;
+
+ // finding the root of the characteristic polynomial
+ // using Newton's method starting at x=0
+ // (it is guaranteed to converge to the right root)
+
+ for (x=0.,y=A0,iter=0; iter=abs(y)) break;
+ x = xnew; y = ynew;
+ }
+
+ // computing paramters of the fitting circle
+
+ DET = x*x - x*Mz + Cov_xy;
+ Xcenter = (Mxz*(Myy - x) - Myz*Mxy)/DET/2.0;
+ Ycenter = (Myz*(Mxx - x) - Mxz*Mxy)/DET/2.0;
+
+ // assembling the output
+
+ return std::complex(Xcenter + meanX, Ycenter + meanY);
+}
diff --git a/Software/PC_Application/Util/util.h b/Software/PC_Application/Util/util.h
index 244e0f1..485ddac 100644
--- a/Software/PC_Application/Util/util.h
+++ b/Software/PC_Application/Util/util.h
@@ -77,6 +77,8 @@ namespace Util {
double distanceToLine(QPointF point, QPointF l1, QPointF l2, QPointF *closestLinePoint = nullptr, double *pointRatio = nullptr);
unsigned long long random(unsigned long long max);
+
+ std::complex findCenterOfCircle(const std::vector> &points);
}
#endif // UTILH_H