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

View File

@ -94,6 +94,19 @@ public:
public:
double frequency;
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;
@ -195,6 +208,19 @@ public:
public:
double frequency;
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;
@ -254,6 +280,37 @@ public:
public:
double frequency;
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;

View File

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

View File

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

View File

@ -69,6 +69,42 @@ namespace Util {
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);
// 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