Fix calibration measurement interpolation bug

This commit is contained in:
Jan Käberich 2022-11-02 22:42:06 +01:00
parent aaea3cb3a3
commit e400f62f04
6 changed files with 530845 additions and 27 deletions

View File

@ -1,6 +1,7 @@
#include "calibrationmeasurement.h" #include "calibrationmeasurement.h"
#include "unit.h" #include "unit.h"
#include "calibration.h" #include "calibration.h"
#include "Util/util.h"
#include <QDateTime> #include <QDateTime>
#include <QComboBox> #include <QComboBox>
@ -336,14 +337,10 @@ std::complex<double> CalibrationMeasurement::OnePort::getMeasured(double frequen
return numeric_limits<complex<double>>::quiet_NaN(); return numeric_limits<complex<double>>::quiet_NaN();
} }
// frequency within points, interpolate // frequency within points, interpolate
auto lower = lower_bound(points.begin(), points.end(), frequency, [](const Point &lhs, double rhs) -> bool { Point interp = Util::interpolate<Point, double>(points, frequency, [](const Point &p)->double{
return lhs.frequency < rhs; return p.frequency;
}); });
auto highPoint = *lower; return interp.S;
auto lowPoint = *prev(lower);
double alpha = (frequency - lowPoint.frequency) / (highPoint.frequency - lowPoint.frequency);
complex<double> ret;
return lowPoint.S * (1.0 - alpha) + highPoint.S * alpha;
} }
std::complex<double> CalibrationMeasurement::OnePort::getActual(double frequency) std::complex<double> CalibrationMeasurement::OnePort::getActual(double frequency)
@ -522,19 +519,10 @@ Sparam CalibrationMeasurement::TwoPort::getMeasured(double frequency)
return Sparam(); return Sparam();
} }
// frequency within points, interpolate // frequency within points, interpolate
auto lower = lower_bound(points.begin(), points.end(), frequency, [](const Point &lhs, double rhs) -> bool { Point interp = Util::interpolate<Point, double>(points, frequency, [](const Point &p)->double{
return lhs.frequency < rhs; return p.frequency;
}); });
auto lowPoint = *lower; return interp.S;
advance(lower, 1);
auto highPoint = *lower;
double alpha = (frequency - lowPoint.frequency) / (highPoint.frequency - lowPoint.frequency);
Sparam ret;
ret.m11 = lowPoint.S.m11 * (1.0 - alpha) + highPoint.S.m11 * alpha;
ret.m12 = lowPoint.S.m12 * (1.0 - alpha) + highPoint.S.m12 * alpha;
ret.m21 = lowPoint.S.m21 * (1.0 - alpha) + highPoint.S.m21 * alpha;
ret.m22 = lowPoint.S.m22 * (1.0 - alpha) + highPoint.S.m22 * alpha;
return ret;
} }
Sparam CalibrationMeasurement::TwoPort::getActual(double frequency) Sparam CalibrationMeasurement::TwoPort::getActual(double frequency)
@ -699,15 +687,14 @@ std::complex<double> CalibrationMeasurement::Isolation::getMeasured(double frequ
} }
portRcv--; portRcv--;
portSrc--; portSrc--;
// find correct point, no interpolation yet // find correct point, interpolate
auto lower = lower_bound(points.begin(), points.end(), frequency, [](const Point &lhs, double rhs) -> bool { Point interp = Util::interpolate<Point, double>(points, frequency, [](const Point &p)->double{
return lhs.frequency < rhs; return p.frequency;
}); });
Point p = *lower; if(portRcv >= interp.S.size() || portSrc >= interp.S[portRcv].size()) {
if(portRcv >= p.S.size() || portSrc >= p.S[portRcv].size()) {
return numeric_limits<complex<double>>::quiet_NaN(); return numeric_limits<complex<double>>::quiet_NaN();
} else { } else {
return p.S[portRcv][portSrc]; return interp.S[portRcv][portSrc];
} }
} }

View File

@ -94,6 +94,19 @@ public:
public: public:
double frequency; double frequency;
std::complex<double> S; std::complex<double> S;
Point operator*(double scalar) const {
Point ret;
ret.frequency = frequency * scalar;
ret.S = S * scalar;
return ret;
}
Point operator+(const Point &p) const {
Point ret;
ret.frequency = frequency + p.frequency;
ret.S = S + p.S;
return ret;
}
}; };
std::vector<Point> getPoints() const; std::vector<Point> getPoints() const;
@ -195,6 +208,19 @@ public:
public: public:
double frequency; double frequency;
Sparam S; Sparam S;
Point operator*(double scalar) const {
Point ret;
ret.frequency = frequency * scalar;
ret.S = S * scalar;
return ret;
}
Point operator+(const Point &p) const {
Point ret;
ret.frequency = frequency + p.frequency;
ret.S = S + p.S;
return ret;
}
}; };
std::vector<Point> getPoints() const; std::vector<Point> getPoints() const;
@ -254,6 +280,37 @@ public:
public: public:
double frequency; double frequency;
std::vector<std::vector<std::complex<double>>> S; std::vector<std::vector<std::complex<double>>> S;
Point operator*(double scalar) const {
Point ret;
ret.frequency = frequency * scalar;
for(const auto &v1 : S) {
std::vector<std::complex<double>> v;
for(const auto &s : v1) {
v.push_back(s * scalar);
}
ret.S.push_back(v);
}
return ret;
}
Point operator+(const Point &p) const {
Point ret;
ret.frequency = frequency + p.frequency;
if(S.size() != p.S.size()) {
throw std::runtime_error("Points to not have the same number of measurements");
}
for(unsigned int i=0;i<S.size();i++) {
std::vector<std::complex<double>> v;
if(S[i].size() != p.S[i].size()) {
throw std::runtime_error("Points to not have the same number of measurements");
}
for(unsigned int j=0;j<S[i].size();j++) {
v.push_back(S[i][j] + p.S[i][j]);
}
ret.S.push_back(v);
}
return ret;
}
}; };
std::vector<Point> getPoints() const; std::vector<Point> getPoints() const;

View File

@ -30,7 +30,7 @@ public:
Sparam(const Tparam &t); Sparam(const Tparam &t);
Sparam(const ABCDparam &a, Type Z01, Type Z02); Sparam(const ABCDparam &a, Type Z01, Type Z02);
Sparam(const ABCDparam &a, Type Z0); Sparam(const ABCDparam &a, Type Z0);
Sparam operator+(const Sparam &r) { Sparam operator+(const Sparam &r) const {
Sparam p; Sparam p;
p.m11 = this->m11+r.m11; p.m11 = this->m11+r.m11;
p.m12 = this->m12+r.m12; p.m12 = this->m12+r.m12;
@ -38,7 +38,7 @@ public:
p.m22 = this->m22+r.m22; p.m22 = this->m22+r.m22;
return p; return p;
} }
Sparam operator*(const Type &r) { Sparam operator*(const Type &r) const {
Sparam p(m11*r, m12*r, m21*r, m22*r); Sparam p(m11*r, m12*r, m21*r, m22*r);
return p; return p;
} }

View File

@ -11,6 +11,7 @@ TraceModel::TraceModel(QObject *parent)
{ {
traces.clear(); traces.clear();
source = DataSource::Unknown; source = DataSource::Unknown;
lastSweepPosition = 0.0;
} }
TraceModel::~TraceModel() TraceModel::~TraceModel()

View File

@ -69,6 +69,42 @@ namespace Util {
return brightness > 0.6 ? Qt::black : Qt::white; return brightness > 0.6 ? Qt::black : Qt::white;
} }
/*
* Performs interpolation of a list of sorted values.
* T: type of the elements in the list. Must contain a value by which these elements are sorted in the list.
* C: Target value of the interpolation (e.g. frequency).
* extract: A function returning the "sorted by"-value of the element
*
* The following operators must be defined:
* T*double
* T+T
*
* Will return an interpolated element T. If no interpolation is possible because target is outside
* of the list, either the first or last element in the list is returned instead.
*/
template<typename T, typename C>
T interpolate(const std::vector<T> &list, C target, std::function<C(const T &lhs)> extract) {
T ret = {};
if(list.size() > 0) {
auto it = std::lower_bound(list.begin(), list.end(), target, [=](const T &lhs, C rhs)->bool{
return extract(lhs) < rhs;
});
if(it == list.begin()) {
// just return the first element
ret = list.front();
} else if(it == list.end()) {
// outside of the list of provided values, just use the last one
ret = list.back();
} else {
// needs to interpolate
auto highPoint = *it;
auto lowPoint = *std::prev(it);
double alpha = (target - extract(lowPoint)) / (extract(highPoint) - extract(lowPoint));
ret = lowPoint * (1.0 - alpha) + highPoint * alpha;
}
}
return ret;
}
void unwrapPhase(std::vector<double> &phase, unsigned int start_index = 0); void unwrapPhase(std::vector<double> &phase, unsigned int start_index = 0);
// input values are Y coordinates, assumes evenly spaced linear X values from 0 to input.size() - 1 // input values are Y coordinates, assumes evenly spaced linear X values from 0 to input.size() - 1

File diff suppressed because one or more lines are too long