2020-08-31 04:03:41 +08:00
# include "calibration.h"
2022-08-30 02:07:07 +08:00
# include "ui_calibrationdialogui.h"
2021-10-21 19:00:34 +08:00
# include "CustomWidgets/informationbox.h"
2022-08-30 02:07:07 +08:00
# include "Util/app_common.h"
# include "unit.h"
2022-09-10 06:06:54 +08:00
# include "LibreCAL/librecaldialog.h"
2022-08-30 02:07:07 +08:00
# include "Eigen/Dense"
# include <fstream>
# include <iomanip>
2021-10-21 19:00:34 +08:00
2022-08-30 02:07:07 +08:00
# include <QDialog>
# include <QMenu>
# include <QStyle>
2021-10-21 19:00:34 +08:00
# include <QDebug>
2020-08-31 04:03:41 +08:00
# include <QFileDialog>
using namespace std ;
2022-08-30 02:07:07 +08:00
using Eigen : : MatrixXcd ;
2020-08-31 04:03:41 +08:00
2022-08-30 02:07:07 +08:00
bool operator = = ( const Calibration : : CalType & lhs , const Calibration : : CalType & rhs ) {
if ( lhs . type ! = rhs . type ) {
return false ;
2021-09-03 19:13:33 +08:00
}
2022-08-30 02:07:07 +08:00
if ( lhs . usedPorts . size ( ) ! = rhs . usedPorts . size ( ) ) {
return false ;
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
for ( unsigned int i = 0 ; i < lhs . usedPorts . size ( ) ; i + + ) {
if ( lhs . usedPorts [ i ] ! = rhs . usedPorts [ i ] ) {
return false ;
}
2021-09-03 19:13:33 +08:00
}
2022-08-30 02:07:07 +08:00
// all fields are equal
return true ;
2021-09-03 19:13:33 +08:00
}
2022-08-30 02:07:07 +08:00
Calibration : : Calibration ( )
2020-08-31 04:03:41 +08:00
{
2022-08-30 02:07:07 +08:00
caltype . type = Type : : None ;
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
QString Calibration : : TypeToString ( Calibration : : Type type )
2020-08-31 04:03:41 +08:00
{
2022-08-30 02:07:07 +08:00
switch ( type ) {
case Type : : None : return " None " ;
case Type : : SOLT : return " SOLT " ;
case Type : : Last : return " Invalid " ;
}
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
Calibration : : Type Calibration : : TypeFromString ( QString s )
2021-09-03 19:13:33 +08:00
{
2022-08-30 02:07:07 +08:00
for ( int i = 0 ; i < ( int ) Type : : Last ; i + + ) {
if ( TypeToString ( ( Type ) i ) = = s ) {
return ( Type ) i ;
}
2021-09-03 19:13:33 +08:00
}
2022-08-30 02:07:07 +08:00
return Type : : None ;
2021-09-03 19:13:33 +08:00
}
2022-08-30 02:07:07 +08:00
void Calibration : : correctMeasurement ( VirtualDevice : : VNAMeasurement & d )
2020-08-31 04:03:41 +08:00
{
2022-08-30 02:07:07 +08:00
if ( caltype . type = = Type : : None ) {
// no calibration active, nothing to do
return ;
2020-11-11 02:16:16 +08:00
}
2022-08-30 02:07:07 +08:00
// formulas from "Multi-Port Calibration Techniques for Differential Parameter Measurements with Network Analyzers", variable names also losely follow this document
MatrixXcd S ( caltype . usedPorts . size ( ) , caltype . usedPorts . size ( ) ) ;
MatrixXcd a ( caltype . usedPorts . size ( ) , caltype . usedPorts . size ( ) ) ;
MatrixXcd b ( caltype . usedPorts . size ( ) , caltype . usedPorts . size ( ) ) ;
// gab point and interpolate
Point p ;
if ( d . frequency < = points . front ( ) . frequency ) {
p = points . front ( ) ;
} else if ( d . frequency > = points . back ( ) . frequency ) {
p = points . back ( ) ;
2020-11-12 02:13:53 +08:00
} else {
2022-08-30 02:07:07 +08:00
// needs to interpolate
auto lower = lower_bound ( points . begin ( ) , points . end ( ) , d . frequency , [ ] ( const Point & lhs , double rhs ) - > bool {
return lhs . frequency < rhs ;
} ) ;
auto highPoint = * lower ;
auto lowPoint = * prev ( lower ) ;
double alpha = ( d . frequency - lowPoint . frequency ) / ( highPoint . frequency - lowPoint . frequency ) ;
p = lowPoint . interpolate ( highPoint , alpha ) ;
2020-11-12 02:13:53 +08:00
}
2022-08-30 02:07:07 +08:00
// Grab measurements (easier to access by index later)
for ( unsigned int i = 0 ; i < caltype . usedPorts . size ( ) ; i + + ) {
for ( unsigned int j = 0 ; j < caltype . usedPorts . size ( ) ; j + + ) {
auto pSrc = caltype . usedPorts [ i ] ;
auto pRcv = caltype . usedPorts [ j ] ;
auto name = " S " + QString : : number ( pRcv ) + QString : : number ( pSrc ) ;
if ( d . measurements . count ( name ) = = 0 ) {
qWarning ( ) < < " Missing measurement for calibration: " < < name ;
return ;
} else {
// grab measurement and remove isolation here
S ( j , i ) = d . measurements [ name ] ;
if ( j ! = i ) {
S ( j , i ) - = p . I [ i ] [ j ] ;
}
}
}
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
// assemble a (L) and b (K) matrices
for ( unsigned int i = 0 ; i < caltype . usedPorts . size ( ) ; i + + ) {
for ( unsigned int j = 0 ; j < caltype . usedPorts . size ( ) ; j + + ) {
if ( i = = j ) {
// calculate incident and reflected wave at the exciting port
a ( j , i ) = 1.0 + p . S [ i ] / p . R [ i ] * ( S ( j , i ) - p . D [ i ] * 1.0 ) ;
b ( j , i ) = ( 1.0 / p . R [ i ] ) * ( S ( j , i ) - p . D [ i ] * 1.0 ) ;
} else {
// calculate incident and reflected wave at the receiving port
a ( j , i ) = p . L [ i ] [ j ] * S ( j , i ) / p . T [ i ] [ j ] ;
b ( j , i ) = S ( j , i ) / p . T [ i ] [ j ] ;
}
}
2021-12-02 06:21:13 +08:00
}
2022-08-30 02:07:07 +08:00
S = b * a . inverse ( ) ;
// extract measurement from matrix and store back into VNAMeasurement
for ( unsigned int i = 0 ; i < caltype . usedPorts . size ( ) ; i + + ) {
for ( unsigned int j = 0 ; j < caltype . usedPorts . size ( ) ; j + + ) {
auto pSrc = caltype . usedPorts [ i ] ;
auto pRcv = caltype . usedPorts [ j ] ;
auto name = " S " + QString : : number ( pRcv ) + QString : : number ( pSrc ) ;
d . measurements [ name ] = S ( j , i ) ;
}
2021-12-03 05:41:51 +08:00
}
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
void Calibration : : edit ( )
2020-08-31 04:03:41 +08:00
{
2022-08-30 02:07:07 +08:00
auto d = new QDialog ( ) ;
d - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
auto ui = new Ui : : CalibrationDialog ;
ui - > setupUi ( d ) ;
ui - > calMinFreq - > setUnit ( " Hz " ) ;
ui - > calMinFreq - > setPrecision ( 4 ) ;
ui - > calMinFreq - > setPrefixes ( " kMG " ) ;
ui - > calMaxFreq - > setUnit ( " Hz " ) ;
ui - > calMaxFreq - > setPrecision ( 4 ) ;
ui - > calMaxFreq - > setPrefixes ( " kMG " ) ;
// generate all possible calibration with the connected device
vector < CalType > availableCals = getAvailableCalibrations ( ) ;
for ( auto c : availableCals ) {
ui - > calibrationList - > addItem ( c . getReadableDescription ( ) ) ;
}
2020-08-31 04:03:41 +08:00
2022-08-30 02:07:07 +08:00
auto updateCalStatistics = [ = ] ( ) {
ui - > activeCalibration - > setText ( caltype . getReadableDescription ( ) ) ;
ui - > calPoints - > setValue ( points . size ( ) ) ;
if ( points . size ( ) > 0 ) {
ui - > calMinFreq - > setValue ( points . front ( ) . frequency ) ;
ui - > calMaxFreq - > setValue ( points . back ( ) . frequency ) ;
} else {
ui - > calMinFreq - > setValue ( 0 ) ;
ui - > calMaxFreq - > setValue ( 0 ) ;
}
} ;
2020-08-31 04:03:41 +08:00
2022-08-30 02:07:07 +08:00
auto updateCalButtons = [ = ] ( ) {
auto row = ui - > calibrationList - > currentRow ( ) ;
if ( row < 0 ) {
ui - > activate - > setEnabled ( false ) ;
ui - > deactivate - > setEnabled ( false ) ;
} else {
if ( caltype = = availableCals [ row ] ) {
ui - > deactivate - > setEnabled ( true ) ;
ui - > activate - > setEnabled ( false ) ;
} else {
ui - > deactivate - > setEnabled ( false ) ;
ui - > activate - > setEnabled ( canCompute ( availableCals [ row ] ) ) ;
}
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
} ;
auto updateCalibrationList = [ = ] ( ) {
auto style = QApplication : : style ( ) ;
for ( int i = 0 ; i < availableCals . size ( ) ; i + + ) {
QIcon icon ;
if ( canCompute ( availableCals [ i ] ) ) {
icon = style - > standardIcon ( QStyle : : SP_DialogApplyButton ) ;
} else {
icon = style - > standardIcon ( QStyle : : SP_MessageBoxCritical ) ;
}
ui - > calibrationList - > item ( i ) - > setIcon ( icon ) ;
2021-12-03 05:41:51 +08:00
}
2022-08-30 02:07:07 +08:00
updateCalButtons ( ) ;
} ;
2021-12-03 05:41:51 +08:00
2022-08-30 02:07:07 +08:00
updateCalibrationList ( ) ;
updateCalStatistics ( ) ;
updateCalButtons ( ) ;
2021-12-05 04:16:45 +08:00
2022-08-30 02:07:07 +08:00
connect ( ui - > calibrationList , & QListWidget : : doubleClicked , [ = ] ( const QModelIndex & index ) {
ui - > activate - > clicked ( ) ;
} ) ;
2021-12-05 04:16:45 +08:00
2022-08-30 02:07:07 +08:00
connect ( ui - > calibrationList , & QListWidget : : currentRowChanged , [ = ] ( ) {
updateCalButtons ( ) ;
} ) ;
2021-12-05 04:16:45 +08:00
2022-09-12 05:22:11 +08:00
connect ( this , & Calibration : : activated , d , [ = ] ( ) {
updateCalibrationList ( ) ;
updateCalStatistics ( ) ;
updateCalButtons ( ) ;
2022-08-30 02:07:07 +08:00
} ) ;
2020-08-31 04:03:41 +08:00
2022-09-12 05:22:11 +08:00
connect ( this , & Calibration : : deactivated , d , [ = ] ( ) {
2022-08-30 02:07:07 +08:00
updateCalibrationList ( ) ;
updateCalStatistics ( ) ;
updateCalButtons ( ) ;
} ) ;
2020-08-31 04:03:41 +08:00
2022-09-12 05:22:11 +08:00
connect ( ui - > activate , & QPushButton : : clicked , [ = ] ( ) {
auto cal = availableCals [ ui - > calibrationList - > currentRow ( ) ] ;
compute ( cal ) ;
} ) ;
connect ( ui - > deactivate , & QPushButton : : clicked , this , & Calibration : : deactivate ) ;
2022-08-30 02:07:07 +08:00
ui - > table - > horizontalHeader ( ) - > setSectionResizeMode ( QHeaderView : : ResizeToContents ) ;
auto updateTableEditButtons = [ = ] ( ) {
ui - > bDelete - > setEnabled ( ui - > table - > currentRow ( ) > = 0 ) ;
ui - > bMoveUp - > setEnabled ( ui - > table - > currentRow ( ) > = 1 ) ;
ui - > bMoveDown - > setEnabled ( ui - > table - > currentRow ( ) > = 0 & & ui - > table - > currentRow ( ) < ui - > table - > rowCount ( ) - 1 ) ;
} ;
auto updateMeasurementTable = [ = ] ( ) {
int row = ui - > table - > currentRow ( ) ;
ui - > table - > clear ( ) ;
ui - > table - > setColumnCount ( 5 ) ;
ui - > table - > setHorizontalHeaderItem ( 0 , new QTableWidgetItem ( " Type " ) ) ;
ui - > table - > setHorizontalHeaderItem ( 1 , new QTableWidgetItem ( " Calkit Standard " ) ) ;
ui - > table - > setHorizontalHeaderItem ( 2 , new QTableWidgetItem ( " Settings " ) ) ;
ui - > table - > setHorizontalHeaderItem ( 3 , new QTableWidgetItem ( " Statistics " ) ) ;
ui - > table - > setHorizontalHeaderItem ( 4 , new QTableWidgetItem ( " Timestamp " ) ) ;
ui - > table - > setRowCount ( measurements . size ( ) ) ;
for ( unsigned int i = 0 ; i < measurements . size ( ) ; i + + ) {
ui - > table - > setItem ( i , 0 , new QTableWidgetItem ( CalibrationMeasurement : : Base : : TypeToString ( measurements [ i ] - > getType ( ) ) ) ) ;
ui - > table - > setCellWidget ( i , 1 , measurements [ i ] - > createStandardWidget ( ) ) ;
ui - > table - > setCellWidget ( i , 2 , measurements [ i ] - > createSettingsWidget ( ) ) ;
ui - > table - > setItem ( i , 3 , new QTableWidgetItem ( measurements [ i ] - > getStatistics ( ) ) ) ;
ui - > table - > setItem ( i , 4 , new QTableWidgetItem ( measurements [ i ] - > getTimestamp ( ) . toString ( ) ) ) ;
}
ui - > table - > selectRow ( row ) ;
updateTableEditButtons ( ) ;
} ;
2020-08-31 04:03:41 +08:00
2022-08-30 02:07:07 +08:00
ui - > createDefault - > addItem ( " " ) ;
for ( unsigned int i = 0 ; i < ( int ) DefaultMeasurements : : Last ; i + + ) {
ui - > createDefault - > addItem ( DefaultMeasurementsToString ( ( DefaultMeasurements ) i ) ) ;
2020-10-03 19:01:59 +08:00
}
2022-08-30 02:07:07 +08:00
QObject : : connect ( ui - > createDefault , qOverload < int > ( & QComboBox : : currentIndexChanged ) , [ = ] ( ) {
if ( measurements . size ( ) > 0 ) {
if ( ! InformationBox : : AskQuestion ( " Create default entries? " , " Do you want to remove all existing entries and create default calibration measurements instead? " , true ) ) {
// user aborted
2022-09-12 05:22:11 +08:00
ui - > createDefault - > blockSignals ( true ) ;
ui - > createDefault - > setCurrentIndex ( 0 ) ;
ui - > createDefault - > blockSignals ( false ) ;
2022-08-30 02:07:07 +08:00
return ;
}
measurements . clear ( ) ;
}
createDefaultMeasurements ( ( DefaultMeasurements ) ( ui - > createDefault - > currentIndex ( ) - 1 ) ) ;
updateMeasurementTable ( ) ;
updateCalibrationList ( ) ;
ui - > createDefault - > blockSignals ( true ) ;
ui - > createDefault - > setCurrentIndex ( 0 ) ;
ui - > createDefault - > blockSignals ( false ) ;
} ) ;
2020-10-03 19:01:59 +08:00
2022-08-30 02:07:07 +08:00
QObject : : connect ( ui - > bDelete , & QPushButton : : clicked , [ = ] ( ) {
auto selected = ui - > table - > selectionModel ( ) - > selectedRows ( ) ;
set < CalibrationMeasurement : : Base * > toDelete ;
for ( auto s : selected ) {
toDelete . insert ( measurements [ s . row ( ) ] ) ;
}
while ( toDelete . size ( ) > 0 ) {
for ( unsigned int i = 0 ; i < measurements . size ( ) ; i + + ) {
if ( toDelete . count ( measurements [ i ] ) ) {
// this measurement should be deleted
delete measurements [ i ] ;
toDelete . erase ( measurements [ i ] ) ;
measurements . erase ( measurements . begin ( ) + i ) ;
}
}
}
updateMeasurementTable ( ) ;
updateCalibrationList ( ) ;
} ) ;
QObject : : connect ( ui - > bMoveUp , & QPushButton : : clicked , [ = ] ( ) {
auto row = ui - > table - > currentRow ( ) ;
if ( row > = 1 ) {
swap ( measurements [ row ] , measurements [ row - 1 ] ) ;
ui - > table - > selectRow ( row - 1 ) ;
updateMeasurementTable ( ) ;
}
} ) ;
QObject : : connect ( ui - > bMoveDown , & QPushButton : : clicked , [ = ] ( ) {
auto row = ui - > table - > currentRow ( ) ;
if ( row > = 0 ) {
swap ( measurements [ row ] , measurements [ row + 1 ] ) ;
ui - > table - > selectRow ( row + 1 ) ;
updateMeasurementTable ( ) ;
}
} ) ;
connect ( ui - > measure , & QPushButton : : clicked , [ = ] ( ) {
std : : set < CalibrationMeasurement : : Base * > m ;
auto selected = ui - > table - > selectionModel ( ) - > selectedRows ( ) ;
for ( auto s : selected ) {
m . insert ( measurements [ s . row ( ) ] ) ;
2020-10-03 19:01:59 +08:00
}
2022-08-30 02:07:07 +08:00
if ( ! CalibrationMeasurement : : Base : : canMeasureSimultaneously ( m ) ) {
InformationBox : : ShowError ( " Unable to measure " , " Different selected measurements require the same port, unable to perform measurement " ) ;
return ;
2020-10-03 19:01:59 +08:00
}
2022-08-30 02:07:07 +08:00
emit startMeasurements ( m ) ;
} ) ;
connect ( this , & Calibration : : measurementsUpdated , d , [ = ] ( ) {
updateMeasurementTable ( ) ;
updateCalibrationList ( ) ;
} ) ;
connect ( ui - > clearMeasurement , & QPushButton : : clicked , [ = ] ( ) {
auto selected = ui - > table - > selectionModel ( ) - > selectedRows ( ) ;
for ( auto s : selected ) {
measurements [ s . row ( ) ] - > clearPoints ( ) ;
2020-10-03 19:01:59 +08:00
}
2022-08-30 02:07:07 +08:00
updateMeasurementTable ( ) ;
updateCalibrationList ( ) ;
} ) ;
2022-09-10 06:06:54 +08:00
connect ( ui - > eCal , & QPushButton : : clicked , [ = ] ( ) {
auto d = new LibreCALDialog ( this ) ;
d - > show ( ) ;
} ) ;
2022-09-12 05:22:11 +08:00
connect ( ui - > editCalkit , & QPushButton : : clicked , [ = ] ( ) {
kit . edit ( ) ;
} ) ;
2022-08-30 02:07:07 +08:00
QObject : : connect ( ui - > table , & QTableWidget : : currentCellChanged , updateTableEditButtons ) ;
auto addMenu = new QMenu ( ) ;
for ( auto t : CalibrationMeasurement : : Base : : availableTypes ( ) ) {
auto action = new QAction ( CalibrationMeasurement : : Base : : TypeToString ( t ) ) ;
QObject : : connect ( action , & QAction : : triggered , [ = ] ( ) {
auto newMeas = newMeasurement ( t ) ;
if ( newMeas ) {
measurements . push_back ( newMeas ) ;
updateMeasurementTable ( ) ;
}
} ) ;
addMenu - > addAction ( action ) ;
2020-10-03 19:01:59 +08:00
}
2022-08-30 02:07:07 +08:00
ui - > bAdd - > setMenu ( addMenu ) ;
updateMeasurementTable ( ) ;
d - > show ( ) ;
2020-10-03 19:01:59 +08:00
}
2022-08-30 02:07:07 +08:00
CalibrationMeasurement : : Base * Calibration : : newMeasurement ( CalibrationMeasurement : : Base : : Type type )
2020-08-31 04:03:41 +08:00
{
2022-08-30 02:07:07 +08:00
CalibrationMeasurement : : Base * m = nullptr ;
switch ( type ) {
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 : : Through : m = new CalibrationMeasurement : : Through ( this ) ; break ;
case CalibrationMeasurement : : Base : : Type : : Isolation : m = new CalibrationMeasurement : : Isolation ( this ) ; break ;
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
return m ;
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
Calibration : : Point Calibration : : computeSOLT ( double f )
2021-03-12 04:52:58 +08:00
{
2022-08-30 02:07:07 +08:00
Point point ;
point . frequency = f ;
// resize vectors
point . D . resize ( caltype . usedPorts . size ( ) ) ;
point . R . resize ( caltype . usedPorts . size ( ) ) ;
point . S . resize ( caltype . usedPorts . size ( ) ) ;
point . L . resize ( caltype . usedPorts . size ( ) ) ;
point . T . resize ( caltype . usedPorts . size ( ) ) ;
point . I . resize ( caltype . usedPorts . size ( ) ) ;
fill ( point . L . begin ( ) , point . L . end ( ) , vector < complex < double > > ( caltype . usedPorts . size ( ) ) ) ;
fill ( point . T . begin ( ) , point . T . end ( ) , vector < complex < double > > ( caltype . usedPorts . size ( ) ) ) ;
fill ( point . I . begin ( ) , point . I . end ( ) , vector < complex < double > > ( caltype . usedPorts . size ( ) ) ) ;
// Calculate SOL coefficients
for ( unsigned int i = 0 ; i < caltype . usedPorts . size ( ) ; i + + ) {
auto p = caltype . usedPorts [ i ] ;
auto _short = static_cast < CalibrationMeasurement : : Short * > ( findMeasurement ( CalibrationMeasurement : : Base : : Type : : Short , p ) ) ;
auto open = static_cast < CalibrationMeasurement : : Open * > ( findMeasurement ( CalibrationMeasurement : : Base : : Type : : Open , p ) ) ;
auto load = static_cast < CalibrationMeasurement : : Load * > ( 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 ) ;
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 ;
auto delta = ( l_c * l_m * ( o_m - s_m ) + o_c * o_m * ( s_m - l_m ) + s_c * s_m * ( l_m - o_m ) ) / denom ;
point . R [ i ] = point . D [ i ] * point . S [ i ] - delta ;
}
// calculate forward match and transmission
for ( unsigned int i = 0 ; i < caltype . usedPorts . size ( ) ; i + + ) {
for ( unsigned int j = 0 ; j < caltype . usedPorts . size ( ) ; j + + ) {
if ( i = = j ) {
// this is the exciting port, SOL error box used here
continue ;
}
auto p1 = caltype . usedPorts [ i ] ;
auto p2 = caltype . usedPorts [ j ] ;
// grab measurement and calkit through definitions
auto throughForward = static_cast < CalibrationMeasurement : : Through * > ( findMeasurement ( CalibrationMeasurement : : Base : : Type : : Through , p1 , p2 ) ) ;
auto throughReverse = static_cast < CalibrationMeasurement : : Through * > ( findMeasurement ( CalibrationMeasurement : : Base : : Type : : Through , p2 , p1 ) ) ;
complex < double > S11 , S21 ;
Sparam Sideal ;
if ( throughForward ) {
S11 = throughForward - > getMeasured ( f ) . m11 ;
S21 = throughForward - > getMeasured ( f ) . m21 ;
Sideal = throughForward - > getActual ( f ) ;
} else if ( throughReverse ) {
S11 = throughReverse - > getMeasured ( f ) . m22 ;
S21 = throughReverse - > getMeasured ( f ) . m12 ;
Sideal = throughReverse - > getActual ( f ) ;
swap ( Sideal . m11 , Sideal . m22 ) ;
swap ( Sideal . m12 , Sideal . m21 ) ;
}
auto isoMeas = static_cast < CalibrationMeasurement : : Isolation * > ( findMeasurement ( CalibrationMeasurement : : Base : : Type : : Isolation ) ) ;
auto isolation = complex < double > ( 0.0 , 0.0 ) ;
if ( isoMeas ) {
isolation = isoMeas - > getMeasured ( f , p2 , p1 ) ;
}
auto deltaS = Sideal . m11 * Sideal . m22 - Sideal . m21 * Sideal . m12 ;
point . L [ i ] [ j ] = ( ( S11 - point . D [ i ] ) * ( 1.0 - point . S [ i ] * Sideal . m11 ) - Sideal . m11 * point . R [ i ] )
/ ( ( S11 - point . D [ i ] ) * ( Sideal . m22 - point . S [ i ] * deltaS ) - deltaS * point . R [ i ] ) ;
point . T [ i ] [ j ] = ( S21 - isolation ) * ( 1.0 - point . S [ i ] * Sideal . m11 - point . L [ i ] [ j ] * Sideal . m22 + point . S [ i ] * point . L [ i ] [ j ] * deltaS ) / Sideal . m21 ;
point . I [ i ] [ j ] = isolation ;
2021-03-12 04:52:58 +08:00
}
}
2022-08-30 02:07:07 +08:00
return point ;
}
Calibration : : CalType Calibration : : getCaltype ( ) const
{
return caltype ;
2021-03-12 04:52:58 +08:00
}
2021-07-10 04:26:44 +08:00
Calibration : : InterpolationType Calibration : : getInterpolation ( double f_start , double f_stop , int npoints )
2020-08-31 04:03:41 +08:00
{
if ( ! points . size ( ) ) {
return InterpolationType : : NoCalibration ;
}
2021-07-10 04:26:44 +08:00
if ( f_start < points . front ( ) . frequency | | f_stop > points . back ( ) . frequency ) {
2020-08-31 04:03:41 +08:00
return InterpolationType : : Extrapolate ;
}
// Either exact or interpolation, check individual frequencies
2020-09-16 05:22:08 +08:00
uint32_t f_step ;
2021-07-10 04:26:44 +08:00
if ( npoints > 1 ) {
f_step = ( f_stop - f_start ) / ( npoints - 1 ) ;
2020-09-16 05:22:08 +08:00
} else {
2021-07-10 04:26:44 +08:00
f_step = f_stop - f_start ;
2020-09-16 05:22:08 +08:00
}
2021-07-10 04:26:44 +08:00
uint64_t f = f_start ;
do {
2020-08-31 04:03:41 +08:00
if ( find_if ( points . begin ( ) , points . end ( ) , [ & f ] ( const Point & p ) {
return abs ( f - p . frequency ) < 100 ;
} ) = = points . end ( ) ) {
return InterpolationType : : Interpolate ;
}
2021-07-10 04:26:44 +08:00
f + = f_step ;
2021-07-10 20:04:05 +08:00
} while ( f < = f_stop & & f_step > std : : numeric_limits < double > : : epsilon ( ) ) ;
2021-07-10 04:26:44 +08:00
2020-08-31 04:03:41 +08:00
// if we get here all frequency points were matched
2021-07-10 04:26:44 +08:00
if ( points . front ( ) . frequency = = f_start & & points . back ( ) . frequency = = f_stop ) {
2020-08-31 04:03:41 +08:00
return InterpolationType : : Unchanged ;
} else {
return InterpolationType : : Exact ;
}
}
2022-08-30 02:07:07 +08:00
std : : vector < Trace * > Calibration : : getErrorTermTraces ( )
2021-04-16 01:24:11 +08:00
{
2022-08-30 02:07:07 +08:00
return vector < Trace * > ( ) ; // TODO
2021-04-16 01:24:11 +08:00
}
2022-08-30 02:07:07 +08:00
std : : vector < Trace * > Calibration : : getMeasurementTraces ( )
2020-08-31 04:03:41 +08:00
{
2022-08-30 02:07:07 +08:00
return vector < Trace * > ( ) ; // TODO
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
QString Calibration : : getCurrentCalibrationFile ( )
2021-04-16 01:24:11 +08:00
{
2022-08-30 02:07:07 +08:00
return currentCalFile ;
}
double Calibration : : getMinFreq ( )
{
if ( points . size ( ) > 0 ) {
return points . front ( ) . frequency ;
} else {
return numeric_limits < double > : : quiet_NaN ( ) ;
2021-04-16 01:24:11 +08:00
}
}
2022-08-30 02:07:07 +08:00
double Calibration : : getMaxFreq ( )
2020-08-31 04:03:41 +08:00
{
2022-08-30 02:07:07 +08:00
if ( points . size ( ) > 0 ) {
return points . back ( ) . frequency ;
} else {
return numeric_limits < double > : : quiet_NaN ( ) ;
2020-08-31 04:03:41 +08:00
}
}
2022-08-30 02:07:07 +08:00
int Calibration : : getNumPoints ( )
2020-08-31 04:03:41 +08:00
{
2022-08-30 02:07:07 +08:00
return points . size ( ) ;
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
QString Calibration : : descriptiveCalName ( )
2020-08-31 04:03:41 +08:00
{
2022-08-30 02:07:07 +08:00
if ( points . size ( ) = = 0 ) {
return QString ( ) ;
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
int precision = 3 ;
QString lo = Unit : : ToString ( points . front ( ) . frequency , " " , " kMG " , precision ) ;
QString hi = Unit : : ToString ( points . back ( ) . frequency , " " , " kMG " , precision ) ;
// due to rounding up 123.66M and 123.99M -> we get lo="124M" and hi="124M"
// so let's add some precision
if ( lo = = hi ) {
// Only in case of 123.66M and 123.69M we would need 5 digits, but that kind of narrow cal. is very unlikely.
precision = 4 ;
lo = Unit : : ToString ( points . front ( ) . frequency , " " , " kMG " , precision ) ;
hi = Unit : : ToString ( points . back ( ) . frequency , " " , " kMG " , precision ) ;
}
QString tmp =
caltype . getReadableDescription ( )
+ " "
+ lo + " - " + hi
+ " "
+ QString : : number ( this - > points . size ( ) ) + " pt " ;
return tmp ;
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
Calkit & Calibration : : getKit ( )
2020-08-31 04:03:41 +08:00
{
2022-08-30 02:07:07 +08:00
return kit ;
}
nlohmann : : json Calibration : : toJSON ( )
{
nlohmann : : json j ;
nlohmann : : json jmeasurements ;
for ( auto m : measurements ) {
nlohmann : : json jmeas ;
jmeas [ " type " ] = CalibrationMeasurement : : Base : : TypeToString ( m - > getType ( ) ) . toStdString ( ) ;
jmeas [ " data " ] = m - > toJSON ( ) ;
jmeasurements . push_back ( jmeas ) ;
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
j [ " measurements " ] = jmeasurements ;
j [ " calkit " ] = kit . toJSON ( ) ;
j [ " type " ] = TypeToString ( caltype . type ) . toStdString ( ) ;
nlohmann : : json jports ;
for ( auto p : caltype . usedPorts ) {
jports . push_back ( p ) ;
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
j [ " ports " ] = jports ;
j [ " version " ] = qlibrevnaApp - > applicationVersion ( ) . toStdString ( ) ;
if ( VirtualDevice : : getConnected ( ) ) {
j [ " device " ] = VirtualDevice : : getConnected ( ) - > serial ( ) . toStdString ( ) ;
}
return j ;
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
void Calibration : : fromJSON ( nlohmann : : json j )
2020-08-31 04:03:41 +08:00
{
2022-08-30 02:07:07 +08:00
reset ( ) ;
if ( j . contains ( " calkit " ) ) {
kit . fromJSON ( j [ " calkit " ] ) ;
}
if ( j . contains ( " measurements " ) ) {
for ( auto jm : j [ " measurements " ] ) {
auto type = CalibrationMeasurement : : Base : : TypeFromString ( QString : : fromStdString ( jm . value ( " type " , " " ) ) ) ;
auto m = newMeasurement ( type ) ;
m - > fromJSON ( jm [ " data " ] ) ;
measurements . push_back ( m ) ;
}
}
CalType ct ;
ct . type = TypeFromString ( QString : : fromStdString ( j . value ( " type " , " " ) ) ) ;
if ( j . contains ( " ports " ) ) {
for ( auto jp : j [ " ports " ] ) {
ct . usedPorts . push_back ( jp ) ;
2020-08-31 04:03:41 +08:00
}
}
2022-08-30 02:07:07 +08:00
if ( ct . type ! = Type : : None ) {
compute ( ct ) ;
}
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
bool Calibration : : toFile ( QString filename )
2020-11-28 01:18:31 +08:00
{
2022-08-30 02:07:07 +08:00
if ( filename . isEmpty ( ) ) {
QString fn = descriptiveCalName ( ) ;
filename = QFileDialog : : getSaveFileName ( nullptr , " Save calibration data " , fn , " Calibration files (*.cal) " , nullptr , QFileDialog : : DontUseNativeDialog ) ;
if ( filename . isEmpty ( ) ) {
// aborted selection
return false ;
2020-11-28 01:18:31 +08:00
}
}
2022-08-30 02:07:07 +08:00
if ( filename . toLower ( ) . endsWith ( " .cal " ) ) {
filename . chop ( 4 ) ;
}
auto calibration_file = filename + " .cal " ;
ofstream file ;
file . open ( calibration_file . toStdString ( ) ) ;
file < < setw ( 1 ) < < toJSON ( ) ;
auto calkit_file = filename + " .calkit " ;
qDebug ( ) < < " Saving associated calibration kit to file " < < calkit_file ;
kit . toFile ( calkit_file ) ;
this - > currentCalFile = calibration_file ; // if all ok, remember this
return true ;
2020-11-28 01:18:31 +08:00
}
2022-08-30 02:07:07 +08:00
bool Calibration : : fromFile ( QString filename )
2020-08-31 04:03:41 +08:00
{
if ( filename . isEmpty ( ) ) {
filename = QFileDialog : : getOpenFileName ( nullptr , " Load calibration data " , " " , " Calibration files (*.cal) " , nullptr , QFileDialog : : DontUseNativeDialog ) ;
if ( filename . isEmpty ( ) ) {
// aborted selection
return false ;
}
}
2021-10-13 03:58:44 +08:00
// force correct file ending
if ( filename . toLower ( ) . endsWith ( " .cal " ) ) {
filename . chop ( 4 ) ;
filename + = " .cal " ;
}
2020-12-01 00:05:15 +08:00
qDebug ( ) < < " Attempting to open calibration from file " < < filename ;
2020-08-31 04:03:41 +08:00
ifstream file ;
2021-10-13 03:58:44 +08:00
2020-08-31 04:03:41 +08:00
file . open ( filename . toStdString ( ) ) ;
2021-10-13 03:58:44 +08:00
if ( ! file . good ( ) ) {
QString msg = " Unable to open file: " + filename ;
InformationBox : : ShowError ( " Error " , msg ) ;
qWarning ( ) < < msg ;
return false ;
}
2020-08-31 04:03:41 +08:00
try {
2021-12-02 06:21:13 +08:00
nlohmann : : json j ;
file > > j ;
2022-08-30 02:07:07 +08:00
currentCalFile = filename ; // if all ok, remember this
2021-12-02 06:21:13 +08:00
fromJSON ( j ) ;
2022-03-17 19:53:13 +08:00
} catch ( exception & e ) {
2022-08-30 02:07:07 +08:00
currentCalFile . clear ( ) ;
2022-08-05 02:12:15 +08:00
InformationBox : : ShowError ( " File parsing error " , e . what ( ) ) ;
qWarning ( ) < < " Calibration file parsing failed: " < < e . what ( ) ;
return false ;
2020-08-31 04:03:41 +08:00
}
return true ;
}
2022-08-30 02:07:07 +08:00
std : : vector < Calibration : : CalType > Calibration : : getAvailableCalibrations ( )
2020-08-31 04:03:41 +08:00
{
2022-08-30 02:07:07 +08:00
int ports = 2 ;
if ( VirtualDevice : : getConnected ( ) ) {
ports = VirtualDevice : : getConnected ( ) - > getInfo ( ) . ports ;
}
vector < CalType > ret ;
for ( auto t : getTypes ( ) ) {
CalType cal ;
cal . type = t ;
auto minPorts = minimumPorts ( t ) ;
for ( int pnum = minPorts ; pnum < = ports ; pnum + + ) {
std : : string bitmask ( pnum , 1 ) ;
bitmask . resize ( ports , 0 ) ;
// assemble selected ports and permute bitmask
do {
vector < int > usedPorts ;
for ( int i = 0 ; i < ports ; + + i ) {
if ( bitmask [ i ] ) {
usedPorts . push_back ( i + 1 ) ;
}
}
cal . usedPorts = usedPorts ;
ret . push_back ( cal ) ;
} while ( std : : prev_permutation ( bitmask . begin ( ) , bitmask . end ( ) ) ) ;
2020-08-31 04:03:41 +08:00
}
}
2022-08-30 02:07:07 +08:00
return ret ;
}
2020-11-11 02:16:16 +08:00
2022-08-30 02:07:07 +08:00
std : : vector < Calibration : : Type > Calibration : : getTypes ( )
{
vector < Type > types ;
// Start at index 1, skip Type::None
for ( int i = 1 ; i < ( int ) Type : : Last ; i + + ) {
types . push_back ( ( Type ) i ) ;
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
return types ;
}
2020-08-31 04:03:41 +08:00
2022-08-30 02:07:07 +08:00
bool Calibration : : canCompute ( Calibration : : CalType type , double * startFreq , double * stopFreq , int * points )
{
switch ( type . type ) {
case Type : : None :
return true ; // Always possible to reset the calibration
case Type : : SOLT : {
using RequiredMeasurements = struct {
CalibrationMeasurement : : Base : : Type type ;
int port1 , port2 ;
} ;
vector < RequiredMeasurements > required ;
// SOL measurements for every port
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 } ) ;
}
// through 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 } ) ;
}
}
vector < CalibrationMeasurement : : Base * > foundMeasurements ;
for ( auto m : required ) {
auto meas = findMeasurement ( m . type , m . port1 , m . port2 ) ;
if ( ! meas ) {
// missing measurement
return false ;
} else {
foundMeasurements . push_back ( meas ) ;
}
}
return hasFrequencyOverlap ( foundMeasurements , startFreq , stopFreq , points ) ;
}
break ;
}
return false ;
}
2020-08-31 04:03:41 +08:00
2022-08-30 02:07:07 +08:00
bool Calibration : : compute ( Calibration : : CalType type )
{
if ( type . type = = Type : : None ) {
deactivate ( ) ;
return true ;
}
double start , stop ;
int numPoints ;
if ( ! canCompute ( type , & start , & stop , & numPoints ) ) {
return false ;
}
caltype = type ;
try {
points . clear ( ) ;
for ( int i = 0 ; i < numPoints ; i + + ) {
double f = start + ( stop - start ) * i / ( numPoints - 1 ) ;
Point p ;
switch ( type . type ) {
case Type : : SOLT : p = computeSOLT ( f ) ; break ;
}
points . push_back ( p ) ;
}
} catch ( exception & e ) {
points . clear ( ) ;
caltype . usedPorts . clear ( ) ;
}
emit activated ( caltype ) ;
2020-08-31 04:03:41 +08:00
return true ;
}
2022-08-30 02:07:07 +08:00
void Calibration : : reset ( )
{
for ( auto m : measurements ) {
delete m ;
2020-12-07 09:44:25 +08:00
}
2022-08-30 02:07:07 +08:00
measurements . clear ( ) ;
deactivate ( ) ;
2020-12-01 00:05:15 +08:00
}
2022-08-30 02:07:07 +08:00
int Calibration : : minimumPorts ( Calibration : : Type type )
2021-12-03 05:41:51 +08:00
{
2022-08-30 02:07:07 +08:00
switch ( type ) {
case Type : : SOLT : return 1 ;
}
return - 1 ;
2021-12-03 05:41:51 +08:00
}
2022-08-30 02:07:07 +08:00
void Calibration : : addMeasurements ( std : : set < CalibrationMeasurement : : Base * > m , const VirtualDevice : : VNAMeasurement & data )
2021-12-03 05:41:51 +08:00
{
2022-08-30 02:07:07 +08:00
for ( auto meas : m ) {
meas - > addPoint ( data ) ;
}
2021-12-03 05:41:51 +08:00
}
2022-08-30 02:07:07 +08:00
void Calibration : : clearMeasurements ( std : : set < CalibrationMeasurement : : Base * > m )
{
for ( auto meas : m ) {
meas - > clearPoints ( ) ;
}
2020-12-07 23:04:59 +08:00
}
2022-08-30 02:07:07 +08:00
void Calibration : : measurementsComplete ( )
{
emit measurementsUpdated ( ) ;
2020-12-07 23:04:59 +08:00
}
2022-08-30 02:07:07 +08:00
void Calibration : : deactivate ( )
{
points . clear ( ) ;
caltype . type = Type : : None ;
caltype . usedPorts . clear ( ) ;
emit deactivated ( ) ;
2020-12-07 23:04:59 +08:00
}
2021-12-02 06:21:13 +08:00
2022-08-30 02:07:07 +08:00
QString Calibration : : DefaultMeasurementsToString ( Calibration : : DefaultMeasurements dm )
2021-12-02 06:21:13 +08:00
{
2022-08-30 02:07:07 +08:00
switch ( dm ) {
case DefaultMeasurements : : SOL1Port : return " 1 Port SOL " ;
case DefaultMeasurements : : SOLT2Port : return " 2 Port SOLT " ;
case DefaultMeasurements : : SOLT3Port : return " 3 Port SOLT " ;
case DefaultMeasurements : : SOLT4Port : return " 4 Port SOLT " ;
2021-12-02 06:21:13 +08:00
}
2022-08-30 02:07:07 +08:00
}
2021-12-02 06:21:13 +08:00
2022-08-30 02:07:07 +08:00
void Calibration : : createDefaultMeasurements ( Calibration : : DefaultMeasurements dm )
{
auto createSOL = [ = ] ( int port ) {
auto _short = new CalibrationMeasurement : : Short ( this ) ;
_short - > setPort ( port ) ;
measurements . push_back ( _short ) ;
auto open = new CalibrationMeasurement : : Open ( this ) ;
open - > setPort ( port ) ;
measurements . push_back ( open ) ;
auto load = new CalibrationMeasurement : : Load ( this ) ;
load - > setPort ( port ) ;
measurements . push_back ( load ) ;
} ;
auto createThrough = [ = ] ( int port1 , int port2 ) {
auto through = new CalibrationMeasurement : : Through ( this ) ;
through - > setPort1 ( port1 ) ;
through - > setPort2 ( port2 ) ;
measurements . push_back ( through ) ;
} ;
switch ( dm ) {
case DefaultMeasurements : : SOL1Port :
createSOL ( 1 ) ;
break ;
case DefaultMeasurements : : SOLT2Port :
createSOL ( 1 ) ;
createSOL ( 2 ) ;
createThrough ( 1 , 2 ) ;
break ;
case DefaultMeasurements : : SOLT3Port :
createSOL ( 1 ) ;
createSOL ( 2 ) ;
createSOL ( 3 ) ;
createThrough ( 1 , 2 ) ;
createThrough ( 1 , 3 ) ;
createThrough ( 2 , 3 ) ;
break ;
case DefaultMeasurements : : SOLT4Port :
createSOL ( 1 ) ;
createSOL ( 2 ) ;
createSOL ( 3 ) ;
createSOL ( 4 ) ;
createThrough ( 1 , 2 ) ;
createThrough ( 1 , 3 ) ;
createThrough ( 1 , 4 ) ;
createThrough ( 2 , 3 ) ;
createThrough ( 2 , 4 ) ;
createThrough ( 3 , 4 ) ;
break ;
}
2021-12-02 06:21:13 +08:00
}
2022-08-30 02:07:07 +08:00
bool Calibration : : hasFrequencyOverlap ( std : : vector < CalibrationMeasurement : : Base * > m , double * startFreq , double * stopFreq , int * points )
2021-12-02 06:21:13 +08:00
{
2022-08-30 02:07:07 +08:00
double minResolution = std : : numeric_limits < double > : : max ( ) ;
double minFreq = 0 ;
double maxFreq = std : : numeric_limits < double > : : max ( ) ;
for ( auto meas : m ) {
if ( meas - > numPoints ( ) < 2 ) {
return false ;
2021-12-02 06:21:13 +08:00
}
2022-08-30 02:07:07 +08:00
auto resolution = ( meas - > maxFreq ( ) - meas - > minFreq ( ) ) / ( meas - > numPoints ( ) - 1 ) ;
if ( meas - > maxFreq ( ) < maxFreq ) {
maxFreq = meas - > maxFreq ( ) ;
2021-12-02 06:21:13 +08:00
}
2022-08-30 02:07:07 +08:00
if ( meas - > minFreq ( ) > minFreq ) {
minFreq = meas - > minFreq ( ) ;
}
if ( resolution < minResolution ) {
minResolution = resolution ;
2021-12-02 06:21:13 +08:00
}
}
2022-08-30 02:07:07 +08:00
if ( startFreq ) {
* startFreq = minFreq ;
}
if ( stopFreq ) {
* stopFreq = maxFreq ;
}
if ( points ) {
* points = ( maxFreq - minFreq ) / minResolution + 1 ;
}
if ( maxFreq > minFreq ) {
return true ;
} else {
return false ;
}
2021-12-02 06:21:13 +08:00
}
2022-08-30 02:07:07 +08:00
CalibrationMeasurement : : Base * Calibration : : findMeasurement ( CalibrationMeasurement : : Base : : Type type , int port1 , int port2 )
2020-08-31 04:03:41 +08:00
{
2022-08-30 02:07:07 +08:00
for ( auto m : measurements ) {
if ( m - > getType ( ) ! = type ) {
continue ;
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
auto onePort = dynamic_cast < CalibrationMeasurement : : OnePort * > ( m ) ;
if ( onePort ) {
if ( onePort - > getPort ( ) ! = port1 ) {
continue ;
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
}
auto twoPort = dynamic_cast < CalibrationMeasurement : : TwoPort * > ( m ) ;
if ( twoPort ) {
if ( twoPort - > getPort1 ( ) ! = port1 | | twoPort - > getPort2 ( ) ! = port2 ) {
continue ;
2020-08-31 04:03:41 +08:00
}
}
2022-08-30 02:07:07 +08:00
// if we get here, we have a match
return m ;
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
return nullptr ;
2020-08-31 04:03:41 +08:00
}
2022-08-30 02:07:07 +08:00
QString Calibration : : CalType : : getReadableDescription ( )
2020-08-31 04:03:41 +08:00
{
2022-08-30 02:07:07 +08:00
QString ret = TypeToString ( this - > type ) ;
if ( usedPorts . size ( ) = = 1 ) {
ret + = " , Port: " + QString : : number ( usedPorts [ 0 ] ) ;
} else if ( usedPorts . size ( ) > 0 ) {
ret + = " , Ports: [ " ;
for ( auto p : usedPorts ) {
ret + = QString : : number ( p ) + " , " ;
}
// remove the last trailing comma
ret . chop ( 1 ) ;
ret + = " ] " ;
2020-08-31 04:03:41 +08:00
}
return ret ;
}
2022-08-30 02:07:07 +08:00
QString Calibration : : CalType : : getShortString ( )
2021-12-02 06:21:13 +08:00
{
2022-08-30 02:07:07 +08:00
QString ret = TypeToString ( this - > type ) ;
if ( usedPorts . size ( ) > 0 ) {
ret + = " _ " ;
2021-12-02 06:21:13 +08:00
}
2022-08-30 02:07:07 +08:00
for ( auto p : usedPorts ) {
ret + = QString : : number ( p ) ;
}
return ret ;
2021-12-02 06:21:13 +08:00
}
2022-08-30 02:07:07 +08:00
Calibration : : CalType Calibration : : CalType : : fromShortString ( QString s )
2021-12-02 06:21:13 +08:00
{
2022-08-30 02:07:07 +08:00
CalType ret ;
auto list = s . split ( " _ " ) ;
if ( list . size ( ) ! = 2 ) {
ret . type = Type : : None ;
2021-12-02 06:21:13 +08:00
} else {
2022-08-30 02:07:07 +08:00
ret . type = TypeFromString ( list [ 0 ] ) ;
for ( auto c : list [ 1 ] ) {
ret . usedPorts . push_back ( QString ( c ) . toInt ( ) ) ;
}
2021-12-02 06:21:13 +08:00
}
2022-08-30 02:07:07 +08:00
return ret ;
2021-12-02 06:21:13 +08:00
}
2022-08-30 02:07:07 +08:00
Calibration : : Point Calibration : : Point : : interpolate ( const Calibration : : Point & to , double alpha )
2020-08-31 04:03:41 +08:00
{
2022-08-30 02:07:07 +08:00
Point ret ;
ret . frequency = frequency * ( 1.0 - alpha ) + to . frequency * alpha ;
ret . D . resize ( D . size ( ) ) ;
for ( unsigned int i = 0 ; i < D . size ( ) ; i + + ) {
ret . D [ i ] = D [ i ] * ( 1.0 - alpha ) + to . D [ i ] * alpha ;
}
ret . R . resize ( R . size ( ) ) ;
for ( unsigned int i = 0 ; i < R . size ( ) ; i + + ) {
ret . R [ i ] = R [ i ] * ( 1.0 - alpha ) + to . R [ i ] * alpha ;
}
ret . S . resize ( S . size ( ) ) ;
for ( unsigned int i = 0 ; i < S . size ( ) ; i + + ) {
ret . S [ i ] = S [ i ] * ( 1.0 - alpha ) + to . S [ i ] * alpha ;
}
ret . T . resize ( T . size ( ) ) ;
for ( unsigned int i = 0 ; i < T . size ( ) ; i + + ) {
ret . T [ i ] . resize ( T [ i ] . size ( ) ) ;
for ( unsigned int j = 0 ; j < T [ i ] . size ( ) ; j + + ) {
ret . T [ i ] [ j ] = T [ i ] [ j ] * ( 1.0 - alpha ) + to . T [ i ] [ j ] * alpha ;
}
}
ret . L . resize ( L . size ( ) ) ;
for ( unsigned int i = 0 ; i < L . size ( ) ; i + + ) {
ret . L [ i ] . resize ( L [ i ] . size ( ) ) ;
for ( unsigned int j = 0 ; j < L [ i ] . size ( ) ; j + + ) {
ret . L [ i ] [ j ] = L [ i ] [ j ] * ( 1.0 - alpha ) + to . L [ i ] [ j ] * alpha ;
}
}
ret . I . resize ( I . size ( ) ) ;
for ( unsigned int i = 0 ; i < I . size ( ) ; i + + ) {
ret . I [ i ] . resize ( I [ i ] . size ( ) ) ;
for ( unsigned int j = 0 ; j < I [ i ] . size ( ) ; j + + ) {
ret . I [ i ] [ j ] = I [ i ] [ j ] * ( 1.0 - alpha ) + to . I [ i ] [ j ] * alpha ;
}
}
return ret ;
2020-08-31 04:03:41 +08:00
}