Fix impedance renormalization + add unit tests

This commit is contained in:
Jan Käberich 2025-02-09 12:59:11 +01:00
parent 523946447a
commit 50bde261af
9 changed files with 114 additions and 2 deletions

View file

@ -62,7 +62,19 @@ double Util::distanceToLine(QPointF point, QPointF l1, QPointF l2, QPointF *clos
}
std::complex<double> Util::SparamToImpedance(std::complex<double> d, std::complex<double> Z0) {
return Z0 * (1.0 + d) / (1.0 - d);
if (d != 1.0) {
return Z0 * (1.0 + d) / (1.0 - d);
} else {
return std::complex<double>(std::numeric_limits<double>::infinity(), 0.0);
}
}
std::complex<double> Util::ImpedanceToSparam(std::complex<double> Z, std::complex<double> Z0) {
if(std::isinf(Z.real())) {
return 1.0;
} else {
return (Z-Z0)/(Z+Z0);
}
}
double Util::dBmTodBuV(double dBm)

View file

@ -52,6 +52,7 @@ namespace Util {
return SparamToVSWR(abs(d));
}
std::complex<double> SparamToImpedance(std::complex<double> d, std::complex<double> Z0 = 50.0);
std::complex<double> ImpedanceToSparam(std::complex<double> Z, std::complex<double> Z0 = 50.0);
// all these conversions assume series connection of real and imag part
static inline double SparamToResistance(std::complex<double> d, std::complex<double> Z0 = 50.0) {
return SparamToImpedance(d, Z0).real();

View file

@ -3,6 +3,7 @@
#include "ui_impedancenormalizationdialog.h"
#include "Tools/parameters.h"
#include "appwindow.h"
#include "Util/util.h"
#include <complex>
@ -44,9 +45,11 @@ void ImpedanceRenormalization::transformDatapoint(DeviceDriver::VNAMeasurement &
name = "S"+QString::number(ports+1)+QString::number(ports+1);
}
for(auto i=1;i<=ports;i++) {
// handle reflection parameters
auto S11name = "S"+QString::number(i)+QString::number(i);
auto S11 = p.measurements[S11name];
transformed[S11name] = Sparam(ABCDparam(Sparam(S11, 0.1, 0.1, 1.0), p.Z0), impedance).m11;
transformed[S11name] = Util::ImpedanceToSparam(Util::SparamToImpedance(S11, p.Z0), impedance);
// handle transmission parameters
for(auto j=i+1;j<=ports;j++) {
auto S12name = "S"+QString::number(i)+QString::number(j);
auto S21name = "S"+QString::number(j)+QString::number(i);

View file

@ -152,6 +152,7 @@ SOURCES += \
../LibreVNA-GUI/touchstone.cpp \
../LibreVNA-GUI/unit.cpp \
ffttests.cpp \
impedancerenormalizationtests.cpp \
main.cpp \
parametertests.cpp \
portextensiontests.cpp \
@ -346,6 +347,7 @@ HEADERS += \
../LibreVNA-GUI/touchstone.h \
../LibreVNA-GUI/unit.h \
ffttests.h \
impedancerenormalizationtests.h \
parametertests.h \
portextensiontests.h \
utiltests.h

View file

@ -0,0 +1,42 @@
#include "impedancerenormalizationtests.h"
ImpedanceRenormalizationTests::ImpedanceRenormalizationTests()
{
renorm = new ImpedanceRenormalization();
// set it up to normalize to 75 Ohm
nlohmann::json j;
j["impedance"] = 75;
renorm->fromJSON(j);
}
ImpedanceRenormalizationTests::~ImpedanceRenormalizationTests()
{
delete renorm;
}
void ImpedanceRenormalizationTests::OnePortTests()
{
// Create dummy measurements
DeviceDriver::VNAMeasurement measShort;
measShort.pointNum = 0;
measShort.Z0 = 50.0;
measShort.measurements["S11"] = -1.0;
auto measLoad = measShort;
measLoad.measurements["S11"] = 0.0;
auto measOpen = measShort;
measOpen.measurements["S11"] = 1.0;
// perform renormalization
renorm->transformDatapoint(measShort);
renorm->transformDatapoint(measLoad);
renorm->transformDatapoint(measOpen);
QVERIFY(measShort.measurements["S11"] == -1.0);
// a Ohm load renormalized to 75 Ohm impedance has a reflection coefficient of -0.2
QVERIFY(measLoad.measurements["S11"] == -0.2);
QVERIFY(measOpen.measurements["S11"] == 1.0);
}

View file

@ -0,0 +1,21 @@
#ifndef IMPEDANCERENORMALIZATIONTESTS_H
#define IMPEDANCERENORMALIZATIONTESTS_H
#include <QtTest>
#include "impedancerenormalization.h"
class ImpedanceRenormalizationTests : public QObject
{
Q_OBJECT
public:
ImpedanceRenormalizationTests();
~ImpedanceRenormalizationTests();
private slots:
void OnePortTests();
private:
ImpedanceRenormalization *renorm;
};
#endif // IMPEDANCERENORMALIZATIONTESTS_H

View file

@ -2,6 +2,7 @@
#include "portextensiontests.h"
#include "parametertests.h"
#include "ffttests.h"
#include "impedancerenormalizationtests.h"
#include <QtTest>
@ -14,6 +15,7 @@ int main(int argc, char *argv[])
status |= QTest::qExec(new PortExtensionTests, argc, argv);
status |= QTest::qExec(new ParameterTests, argc, argv);
status |= QTest::qExec(new fftTests, argc, argv);
status |= QTest::qExec(new ImpedanceRenormalizationTests, argc, argv);
return status;
}

View file

@ -78,3 +78,31 @@ void UtilTests::FirmwareComparison()
QVERIFY(Util::firmwareEqualOrHigher("2.2.2", "2.3") == false);
QVERIFY(Util::firmwareEqualOrHigher("2.2", "2.3.1") == false);
}
void UtilTests::ImpedanceSparameterCalculation()
{
// Check impedance to S parameter conversion and back for different values
auto Z = std::complex<double>(50.0);
auto S = Util::ImpedanceToSparam(Z);
QVERIFY(S == 0.0);
QVERIFY(Util::SparamToImpedance(S) == Z);
Z = std::complex<double>(0.0);
S = Util::ImpedanceToSparam(Z);
QVERIFY(S == -1.0);
QVERIFY(Util::SparamToImpedance(S) == Z);
Z = std::complex<double>(100.0);
S = Util::ImpedanceToSparam(Z);
QVERIFY(qFuzzyCompare(S.real(), 1.0/3));
QVERIFY(S.imag() == 0.0);
QVERIFY(qFuzzyCompare(Util::SparamToImpedance(S).real(), Z.real()));
QVERIFY(qFuzzyCompare(Util::SparamToImpedance(S).imag(), Z.imag()));
// Edge case: convert S parameter to impedance at 1.0 (which will give a +inf impedance)
S = 1.0;
Z = Util::SparamToImpedance(S);
// convert back, we must land back at 1.0
auto S_from_Z = Util::ImpedanceToSparam(Z);
QVERIFY(S_from_Z == S);
}

View file

@ -14,6 +14,7 @@ private slots:
void IdealArcApproximation();
void NoisyCircleApproximation();
void FirmwareComparison();
void ImpedanceSparameterCalculation();
};
#endif // UTILTESTS_H