2022-10-01 23:10:44 +08:00
# include "calibration.h"
# include "ui_calibrationdialogui.h"
# include "CustomWidgets/informationbox.h"
# include "Util/app_common.h"
# include "unit.h"
# include "Util/util.h"
# include "LibreCAL/librecaldialog.h"
# include "Eigen/Dense"
# include <fstream>
# include <iomanip>
# include <QDialog>
# include <QMenu>
# include <QStyle>
# include <QDebug>
# include <QFileDialog>
using namespace std ;
using Eigen : : MatrixXcd ;
bool operator = = ( const Calibration : : CalType & lhs , const Calibration : : CalType & rhs ) {
if ( lhs . type ! = rhs . type ) {
return false ;
}
if ( lhs . usedPorts . size ( ) ! = rhs . usedPorts . size ( ) ) {
return false ;
}
for ( unsigned int i = 0 ; i < lhs . usedPorts . size ( ) ; i + + ) {
if ( lhs . usedPorts [ i ] ! = rhs . usedPorts [ i ] ) {
return false ;
}
}
// all fields are equal
return true ;
}
Calibration : : Calibration ( )
: SCPINode ( " CALibration " )
{
caltype . type = Type : : None ;
unsavedChanges = false ;
// create SCPI commands
add ( new SCPICommand ( " ACTivate " , [ = ] ( QStringList params ) - > QString {
if ( params . size ( ) ! = 1 ) {
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
auto availableCals = getAvailableCalibrations ( ) ;
for ( auto caltype : availableCals ) {
if ( caltype . getShortString ( ) . compare ( params [ 0 ] , Qt : : CaseInsensitive ) = = 0 ) {
// found a match
// check if calibration can be activated
if ( canCompute ( caltype ) ) {
compute ( caltype ) ;
} else {
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
}
}
// if we get here, the supplied parameter did not match any of the available calibrations
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
} , [ = ] ( QStringList ) - > QString {
auto availableCals = getAvailableCalibrations ( ) ;
if ( availableCals . size ( ) = = 0 ) {
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
auto ret = availableCals [ 0 ] . getShortString ( ) ;
for ( unsigned int i = 1 ; i < availableCals . size ( ) ; i + + ) {
ret + = " , " ;
ret + = availableCals [ i ] . getShortString ( ) ;
}
return ret ;
} ) ) ;
add ( new SCPICommand ( " NUMber " , nullptr , [ = ] ( QStringList ) - > QString {
return QString : : number ( measurements . size ( ) ) ;
} ) ) ;
add ( new SCPICommand ( " RESET " , [ = ] ( QStringList ) - > QString {
reset ( ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
} , nullptr ) ) ;
add ( new SCPICommand ( " ADD " , [ = ] ( QStringList params ) - > QString {
if ( params . size ( ) < 1 ) {
// no measurement type specified
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
// parse measurement type
auto type = CalibrationMeasurement : : Base : : TypeFromString ( params [ 0 ] ) ;
auto newMeas = newMeasurement ( type ) ;
if ( ! newMeas ) {
// failed to create this type of measurement
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
if ( params . size ( ) = = 2 ) {
// standard name given
CalStandard : : Virtual * standard = nullptr ;
for ( auto s : newMeas - > supportedStandards ( ) ) {
if ( s - > getName ( ) . compare ( params [ 1 ] , Qt : : CaseInsensitive ) = = 0 ) {
// use this standard
standard = s ;
}
}
if ( ! standard ) {
// specified standard not available
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
newMeas - > setStandard ( standard ) ;
}
measurements . push_back ( newMeas ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
} , nullptr ) ) ;
add ( new SCPICommand ( " TYPE " , nullptr , [ = ] ( QStringList params ) - > QString {
if ( params . size ( ) < 1 ) {
// no measurement number specified
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
bool okay ;
unsigned int number = params [ 0 ] . toUInt ( & okay ) ;
if ( ! okay | | number > = measurements . size ( ) ) {
// invalid measurement specified
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
return CalibrationMeasurement : : Base : : TypeToString ( measurements [ number ] - > getType ( ) ) ;
}
} ) ) ;
add ( new SCPICommand ( " PORT " , [ = ] ( QStringList params ) - > QString {
if ( params . size ( ) < 1 ) {
// invalid number of parameters
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
bool okay ;
unsigned int number = params [ 0 ] . toUInt ( & okay ) ;
if ( ! okay | | number > = measurements . size ( ) ) {
// invalid measurement specified
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
auto meas = measurements [ number ] ;
auto onePort = dynamic_cast < CalibrationMeasurement : : OnePort * > ( meas ) ;
if ( onePort ) {
if ( params . size ( ) ! = 2 ) {
// invalid number of parameters
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
bool okay ;
int number = params [ 1 ] . toInt ( & okay ) ;
if ( ! okay | | number < 1 | | number > VirtualDevice : : getInfo ( VirtualDevice : : getConnected ( ) ) . ports ) {
// invalid port specified
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
onePort - > setPort ( number ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
auto twoPort = dynamic_cast < CalibrationMeasurement : : TwoPort * > ( meas ) ;
if ( twoPort ) {
if ( params . size ( ) ! = 3 ) {
// invalid number of parameters
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
bool okay1 ;
int port1 = params [ 1 ] . toInt ( & okay1 ) ;
bool okay2 ;
int port2 = params [ 2 ] . toInt ( & okay2 ) ;
if ( ! okay1 | | ! okay2 | | port1 < 1 | | port2 > VirtualDevice : : getInfo ( VirtualDevice : : getConnected ( ) ) . ports
| | port2 < 1 | | port2 > VirtualDevice : : getInfo ( VirtualDevice : : getConnected ( ) ) . ports ) {
// invalid port specified
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
twoPort - > setPort1 ( port1 ) ;
twoPort - > setPort2 ( port2 ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
} , [ = ] ( QStringList params ) - > QString {
if ( params . size ( ) ! = 1 ) {
// invalid number of parameters
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
bool okay ;
unsigned int number = params [ 0 ] . toUInt ( & okay ) ;
if ( ! okay | | number > = measurements . size ( ) ) {
// invalid measurement specified
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
auto meas = measurements [ number ] ;
auto onePort = dynamic_cast < CalibrationMeasurement : : OnePort * > ( meas ) ;
if ( onePort ) {
return QString : : number ( onePort - > getPort ( ) ) ;
}
auto twoPort = dynamic_cast < CalibrationMeasurement : : TwoPort * > ( meas ) ;
if ( twoPort ) {
return QString : : number ( twoPort - > getPort1 ( ) ) + " " + QString : : number ( twoPort - > getPort2 ( ) ) ;
}
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
} ) ) ;
add ( new SCPICommand ( " STANDARD " , [ = ] ( QStringList params ) - > QString {
if ( params . size ( ) ! = 2 ) {
// invalid number of parameters
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
bool okay ;
unsigned int number = params [ 0 ] . toUInt ( & okay ) ;
if ( ! okay | | number > = measurements . size ( ) ) {
// invalid measurement specified
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
auto meas = measurements [ number ] ;
for ( auto s : meas - > supportedStandards ( ) ) {
if ( s - > getName ( ) . compare ( params [ 1 ] , Qt : : CaseInsensitive ) = = 0 ) {
// use this standard
meas - > setStandard ( s ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
}
// specified standard not available
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
} , [ = ] ( QStringList params ) - > QString {
if ( params . size ( ) ! = 1 ) {
// invalid number of parameters
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
bool okay ;
unsigned int number = params [ 0 ] . toUInt ( & okay ) ;
if ( ! okay | | number > = measurements . size ( ) ) {
// invalid measurement specified
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
auto s = measurements [ number ] - > getStandard ( ) ;
if ( s ) {
s - > getName ( ) ;
} else {
// no standard set
return " None " ;
}
}
} ) ) ;
add ( new SCPICommand ( " MEASure " , [ = ] ( QStringList params ) - > QString {
if ( params . size ( ) < 1 ) {
// no measurement specified
// TODO check if measurement is already running
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
// assemble list of measurements to take
std : : set < CalibrationMeasurement : : Base * > m ;
for ( QString p : params ) {
bool okay = false ;
unsigned int number = p . toUInt ( & okay ) ;
if ( ! okay | | number > = measurements . size ( ) ) {
// invalid measurement specified
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
m . insert ( measurements [ number ] ) ;
}
}
if ( CalibrationMeasurement : : Base : : canMeasureSimultaneously ( m ) ) {
emit startMeasurements ( m ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
} else {
// can't start these measurements simultaneously
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
}
} , nullptr ) ) ;
add ( new SCPICommand ( " SAVE " , [ = ] ( QStringList params ) - > QString {
if ( params . size ( ) ! = 1 | | getCaltype ( ) . type = = Calibration : : Type : : None ) {
// no filename given or no calibration active
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
if ( ! toFile ( params [ 0 ] ) ) {
// some error when writing the calibration file
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
}
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
} , nullptr ) ) ;
add ( new SCPICommand ( " LOAD " , nullptr , [ = ] ( QStringList params ) - > QString {
if ( params . size ( ) ! = 1 ) {
// no filename given or no calibration active
return SCPI : : getResultName ( SCPI : : Result : : False ) ;
}
if ( ! fromFile ( params [ 0 ] ) ) {
// some error when loading the calibration file
return SCPI : : getResultName ( SCPI : : Result : : False ) ;
}
return SCPI : : getResultName ( SCPI : : Result : : True ) ;
} ) ) ;
}
QString Calibration : : TypeToString ( Calibration : : Type type )
{
switch ( 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 " ;
}
}
Calibration : : Type Calibration : : TypeFromString ( QString s )
{
for ( int i = 0 ; i < ( int ) Type : : Last ; i + + ) {
if ( TypeToString ( ( Type ) i ) = = s ) {
return ( Type ) i ;
}
}
return Type : : None ;
}
void Calibration : : correctMeasurement ( VirtualDevice : : VNAMeasurement & d )
{
if ( caltype . type = = Type : : None ) {
// no calibration active, nothing to do
return ;
}
// 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 ( ) ;
} else {
// 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 ) ;
}
// 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 ] ;
}
}
}
}
// 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 ] ;
}
}
}
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 ) ;
}
}
}
void Calibration : : correctTraces ( std : : map < QString , Trace * > traceSet )
{
auto points = Trace : : assembleDatapoints ( traceSet ) ;
if ( points . size ( ) ) {
// succeeded in assembling datapoints
for ( auto & p : points ) {
correctMeasurement ( p ) ;
}
Trace : : fillFromDatapoints ( traceSet , points ) ;
}
}
void Calibration : : edit ( )
{
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 ( ) ) ;
}
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 ) ;
}
} ;
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 ] ) ) ;
}
}
} ;
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 ) ;
}
updateCalButtons ( ) ;
} ;
updateCalibrationList ( ) ;
updateCalStatistics ( ) ;
updateCalButtons ( ) ;
connect ( ui - > calibrationList , & QListWidget : : doubleClicked , [ = ] ( const QModelIndex & index ) {
ui - > activate - > clicked ( ) ;
} ) ;
connect ( ui - > calibrationList , & QListWidget : : currentRowChanged , [ = ] ( ) {
updateCalButtons ( ) ;
} ) ;
connect ( this , & Calibration : : activated , d , [ = ] ( ) {
updateCalibrationList ( ) ;
updateCalStatistics ( ) ;
updateCalButtons ( ) ;
} ) ;
connect ( this , & Calibration : : deactivated , d , [ = ] ( ) {
updateCalibrationList ( ) ;
updateCalStatistics ( ) ;
updateCalButtons ( ) ;
} ) ;
connect ( ui - > activate , & QPushButton : : clicked , [ = ] ( ) {
auto cal = availableCals [ ui - > calibrationList - > currentRow ( ) ] ;
compute ( cal ) ;
} ) ;
connect ( ui - > deactivate , & QPushButton : : clicked , this , & Calibration : : deactivate ) ;
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 ( ) ;
} ;
ui - > createDefault - > addItem ( " " ) ;
for ( unsigned int i = 0 ; i < ( int ) DefaultMeasurements : : Last ; i + + ) {
ui - > createDefault - > addItem ( DefaultMeasurementsToString ( ( DefaultMeasurements ) i ) ) ;
}
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
ui - > createDefault - > blockSignals ( true ) ;
ui - > createDefault - > setCurrentIndex ( 0 ) ;
ui - > createDefault - > blockSignals ( false ) ;
return ;
}
deleteMeasurements ( ) ;
}
createDefaultMeasurements ( ( DefaultMeasurements ) ( ui - > createDefault - > currentIndex ( ) - 1 ) ) ;
updateMeasurementTable ( ) ;
updateCalibrationList ( ) ;
ui - > createDefault - > blockSignals ( true ) ;
ui - > createDefault - > setCurrentIndex ( 0 ) ;
ui - > createDefault - > blockSignals ( false ) ;
} ) ;
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 ) ;
}
}
}
// update calibration (may have changed due to deleted measurement)
if ( canCompute ( caltype ) ) {
compute ( caltype ) ;
} else {
deactivate ( ) ;
}
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 ( ) ] ) ;
}
if ( ! CalibrationMeasurement : : Base : : canMeasureSimultaneously ( m ) ) {
InformationBox : : ShowError ( " Unable to measure " , " Different selected measurements require the same port, unable to perform measurement " ) ;
return ;
}
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 ( ) ;
}
// update calibration (may have changed due to deleted measurement)
if ( canCompute ( caltype ) ) {
compute ( caltype ) ;
} else {
deactivate ( ) ;
}
updateMeasurementTable ( ) ;
updateCalibrationList ( ) ;
} ) ;
connect ( ui - > eCal , & QPushButton : : clicked , [ = ] ( ) {
auto d = new LibreCALDialog ( this ) ;
d - > show ( ) ;
} ) ;
connect ( ui - > editCalkit , & QPushButton : : clicked , [ = ] ( ) {
2022-10-02 05:11:13 +08:00
kit . edit ( [ = ] ( ) {
updateMeasurementTable ( ) ;
// update calibration (may have changed due to edited calibration standard)
if ( canCompute ( caltype ) ) {
compute ( caltype ) ;
} else {
deactivate ( ) ;
}
} ) ;
2022-10-01 23:10:44 +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 ) {
2022-10-14 05:28:02 +08:00
// measurements.push_back(newMeas);
2022-10-01 23:10:44 +08:00
updateMeasurementTable ( ) ;
}
} ) ;
addMenu - > addAction ( action ) ;
}
ui - > bAdd - > setMenu ( addMenu ) ;
updateMeasurementTable ( ) ;
d - > show ( ) ;
}
CalibrationMeasurement : : Base * Calibration : : newMeasurement ( CalibrationMeasurement : : Base : : Type type )
{
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 : : 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 ;
}
Calibration : : Point Calibration : : createInitializedPoint ( double f ) {
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 ( ) ) ) ;
return point ;
}
Calibration : : Point Calibration : : computeSOLT ( double f )
{
Point point = createInitializedPoint ( f ) ;
// 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 s_m = _short - > getMeasured ( f ) ;
auto o_m = open - > getMeasured ( f ) ;
auto s_c = _short - > getActual ( f ) ;
auto o_c = open - > getActual ( f ) ;
complex < double > l_c , l_m ;
auto slidingMeasurements = findMeasurements ( CalibrationMeasurement : : Base : : Type : : SlidingLoad , p ) ;
if ( slidingMeasurements . size ( ) > = 3 ) {
// use sliding load
vector < complex < double > > slidingMeasured ;
for ( auto m : slidingMeasurements ) {
auto slidingLoad = static_cast < CalibrationMeasurement : : SlidingLoad * > ( 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 < CalibrationMeasurement : : Load * > ( 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 ;
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 ;
}
}
return point ;
}
Calibration : : Point Calibration : : computeThroughNormalization ( double f )
{
Point point = createInitializedPoint ( f ) ;
// Calculate SOL coefficients
for ( unsigned int i = 0 ; i < caltype . usedPorts . size ( ) ; i + + ) {
// use ideal coefficients
point . D [ i ] = 0.0 ;
point . S [ i ] = 0.0 ;
point . R [ i ] = 1.0 ;
}
// 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 ) {
S21 = throughForward - > getMeasured ( f ) . m21 ;
Sideal = throughForward - > getActual ( f ) ;
} else if ( throughReverse ) {
S21 = throughReverse - > getMeasured ( f ) . m12 ;
Sideal = throughReverse - > getActual ( f ) ;
swap ( Sideal . m12 , Sideal . m21 ) ;
}
point . L [ i ] [ j ] = 0.0 ;
point . T [ i ] [ j ] = S21 / Sideal . m21 ;
point . I [ i ] [ j ] = 0.0 ;
}
}
return point ;
}
2022-10-02 05:11:13 +08:00
Calibration : : Point Calibration : : computeTRL ( double freq )
{
Point point = createInitializedPoint ( freq ) ;
// 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 ) {
// calculation only possible with through measurements
continue ;
}
auto p1 = caltype . usedPorts [ i ] ;
auto p2 = caltype . usedPorts [ j ] ;
// grab reflection measurements
auto S11_reflection = static_cast < CalibrationMeasurement : : Reflect * > ( findMeasurement ( CalibrationMeasurement : : Base : : Type : : Reflect , p1 ) ) ;
auto S22_reflection = static_cast < CalibrationMeasurement : : Reflect * > ( findMeasurement ( CalibrationMeasurement : : Base : : Type : : Reflect , p2 ) ) ;
bool S11_short , S22_short ;
{
auto S11_short_standard = dynamic_cast < CalStandard : : Short * > ( S11_reflection - > getStandard ( ) ) ;
auto S11_open_standard = dynamic_cast < CalStandard : : Open * > ( S11_reflection - > getStandard ( ) ) ;
auto S11_reflect_standard = dynamic_cast < CalStandard : : Reflect * > ( S11_reflection - > getStandard ( ) ) ;
if ( S11_short_standard ) {
S11_short = true ;
} else if ( S11_open_standard ) {
S11_short = false ;
} else if ( S11_reflect_standard ) {
S11_short = S11_reflect_standard - > getIsShort ( ) ;
} else {
// invalid standard
throw runtime_error ( " Invalid standard defined for reflection measurement " ) ;
}
auto S22_short_standard = dynamic_cast < CalStandard : : Short * > ( S22_reflection - > getStandard ( ) ) ;
auto S22_open_standard = dynamic_cast < CalStandard : : Open * > ( S22_reflection - > getStandard ( ) ) ;
auto S22_reflect_standard = dynamic_cast < CalStandard : : Reflect * > ( S22_reflection - > getStandard ( ) ) ;
if ( S22_short_standard ) {
S22_short = true ;
} else if ( S22_open_standard ) {
S22_short = false ;
} else if ( S22_reflect_standard ) {
S22_short = S22_reflect_standard - > getIsShort ( ) ;
} else {
// invalid standard
throw runtime_error ( " Invalid standard defined for reflection measurement " ) ;
}
}
bool reflectionIsNegative ;
if ( S11_short & & S22_short ) {
reflectionIsNegative = true ;
} else if ( ! S11_short & & ! S22_short ) {
reflectionIsNegative = false ;
} else {
throw runtime_error ( " Reflection measurements must all use the same standard (either open or short) " ) ;
}
// grab through measurement
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 ) ) ;
Sparam Sthrough ;
if ( throughForward ) {
Sthrough = throughForward - > getMeasured ( freq ) ;
} else if ( throughReverse ) {
Sthrough = throughReverse - > getMeasured ( freq ) ;
swap ( Sthrough . m11 , Sthrough . m22 ) ;
swap ( Sthrough . m12 , Sthrough . m21 ) ;
}
// grab line measurement
auto forwardLines = findMeasurements ( CalibrationMeasurement : : Base : : Type : : Line , p1 , p2 ) ;
auto reverseLines = findMeasurements ( CalibrationMeasurement : : Base : : Type : : Line , p2 , p1 ) ;
// find the closest (geometric) match for the current frequency
double closestIdealFreqRatio = numeric_limits < double > : : max ( ) ;
bool closestLineIsReversed = false ;
CalibrationMeasurement : : Line * closestLine = nullptr ;
CalStandard : : Line * closestStandard = nullptr ;
for ( int i = 0 ; i < 2 ; i + + ) {
auto list = i ? reverseLines : forwardLines ;
for ( auto l : list ) {
auto line = static_cast < CalibrationMeasurement : : Line * > ( l ) ;
auto standard = static_cast < CalStandard : : Line * > ( line - > getStandard ( ) ) ;
double idealFreq = ( standard - > minFrequency ( ) + standard - > maxFrequency ( ) ) / 2 ;
double mismatch = idealFreq / freq ;
if ( mismatch < 0 ) {
mismatch = 1.0 / mismatch ;
}
if ( mismatch < closestIdealFreqRatio ) {
closestIdealFreqRatio = mismatch ;
closestLineIsReversed = i > 0 ;
closestLine = line ;
closestStandard = standard ;
}
}
}
if ( ! closestLine ) {
throw runtime_error ( " Unable to find required line measurement " ) ;
}
if ( freq < closestStandard - > minFrequency ( ) | | freq > closestStandard - > maxFrequency ( ) ) {
throw runtime_error ( " No line standard supports the required frequency ( " + QString : : number ( freq ) . toStdString ( ) + " ) " ) ;
}
Sparam Sline = closestLine - > getMeasured ( freq ) ;
if ( closestLineIsReversed ) {
swap ( Sline . m11 , Sline . m22 ) ;
swap ( Sline . m12 , Sline . m21 ) ;
}
// got all required measurements
// calculate TRL calibration
// variable names and formulas according to http://emlab.uiuc.edu/ece451/notes/new_TRL.pdf
// page 19
auto R_T = Tparam ( Sthrough ) ;
auto R_D = Tparam ( Sline ) ;
auto T = R_D * R_T . inverse ( ) ;
complex < double > a_over_c , b ;
// page 21-22
Util : : solveQuadratic ( T . m21 , T . m22 - T . m11 , - T . m12 , b , a_over_c ) ;
// ensure correct root selection
// page 23
if ( abs ( b ) > = abs ( a_over_c ) ) {
swap ( b , a_over_c ) ;
}
// page 24
auto g = R_T . m22 ;
auto d = R_T . m11 / g ;
auto e = R_T . m12 / g ;
auto f = R_T . m21 / g ;
// page 25
auto r22_rho22 = g * ( 1.0 - e / a_over_c ) / ( 1.0 - b / a_over_c ) ;
auto gamma = ( f - d / a_over_c ) / ( 1.0 - e / a_over_c ) ;
auto beta_over_alpha = ( e - b ) / ( d - b * f ) ;
// page 26
auto alpha_a = ( d - b * f ) / ( 1.0 - e / a_over_c ) ;
auto w1 = S11_reflection - > getMeasured ( freq ) ;
auto w2 = S22_reflection - > getMeasured ( freq ) ;
// page 28
auto a = sqrt ( ( w1 - b ) / ( w2 + gamma ) * ( 1.0 + w2 * beta_over_alpha ) / ( 1.0 - w1 / a_over_c ) * alpha_a ) ;
// page 29, check sign of a
auto reflection = ( w1 - b ) / ( a * ( 1.0 - w1 / a_over_c ) ) ;
if ( ( reflection . real ( ) > 0 & & reflectionIsNegative ) | | ( reflection . real ( ) < 0 & & ! reflectionIsNegative ) ) {
// wrong sign for a
a = - a ;
}
// Revert back from error boxes with T parameters to S paramaters,
// page 17 + formulas for calculating S parameters from T parameters.
// Forward coefficients, normalize for S21 = 1.0 -> r22 = 1.0
auto r22 = complex < double > ( 1.0 ) ;
auto rho22 = r22_rho22 / r22 ;
auto alpha = alpha_a / a ;
auto beta = beta_over_alpha * alpha ;
auto c = a / a_over_c ;
auto Box_A = Tparam ( r22 * a , r22 * b , r22 * c , r22 ) ;
auto Box_B = Tparam ( rho22 * alpha , rho22 * beta , rho22 * gamma , rho22 ) ;
auto S_A = Sparam ( Box_A ) ;
point . D [ i ] = S_A . m11 ;
point . R [ i ] = S_A . m12 ;
point . S [ i ] = S_A . m22 ;
auto S_B = Sparam ( Box_B ) ;
point . L [ i ] [ j ] = S_B . m11 ;
point . T [ i ] [ j ] = S_B . m21 ;
// no isolation measurement available
point . I [ i ] [ j ] = 0.0 ;
// Reverse coefficients, will be handled in loop iteration where i=j and j=i
}
}
return point ;
}
2022-10-01 23:10:44 +08:00
Calibration : : CalType Calibration : : getCaltype ( ) const
{
return caltype ;
}
Calibration : : InterpolationType Calibration : : getInterpolation ( double f_start , double f_stop , int npoints )
{
if ( ! points . size ( ) ) {
return InterpolationType : : NoCalibration ;
}
if ( f_start < points . front ( ) . frequency | | f_stop > points . back ( ) . frequency ) {
return InterpolationType : : Extrapolate ;
}
// Either exact or interpolation, check individual frequencies
uint32_t f_step ;
if ( npoints > 1 ) {
f_step = ( f_stop - f_start ) / ( npoints - 1 ) ;
} else {
f_step = f_stop - f_start ;
}
uint64_t f = f_start ;
do {
if ( find_if ( points . begin ( ) , points . end ( ) , [ & f ] ( const Point & p ) {
return abs ( f - p . frequency ) < 100 ;
} ) = = points . end ( ) ) {
return InterpolationType : : Interpolate ;
}
f + = f_step ;
} while ( f < = f_stop & & f_step > std : : numeric_limits < double > : : epsilon ( ) ) ;
// if we get here all frequency points were matched
if ( points . front ( ) . frequency = = f_start & & points . back ( ) . frequency = = f_stop ) {
return InterpolationType : : Unchanged ;
} else {
return InterpolationType : : Exact ;
}
}
std : : vector < Trace * > Calibration : : getErrorTermTraces ( )
{
vector < Trace * > ret ;
if ( points . size ( ) = = 0 ) {
return ret ;
}
for ( unsigned int i = 0 ; i < caltype . usedPorts . size ( ) ; i + + ) {
auto p = caltype . usedPorts [ i ] ;
auto tDir = new Trace ( " Directivity_Port " + QString : : number ( p ) ) ;
tDir - > setReflection ( true ) ;
tDir - > setCalibration ( ) ;
auto tSM = new Trace ( " SourceMatch_Port " + QString : : number ( p ) ) ;
tSM - > setReflection ( true ) ;
tSM - > setCalibration ( ) ;
auto tRT = new Trace ( " ReflectionTracking_Port " + QString : : number ( p ) ) ;
tRT - > setReflection ( false ) ;
tRT - > setCalibration ( ) ;
for ( auto p : points ) {
Trace : : Data td ;
td . x = p . frequency ;
td . y = p . D [ i ] ;
tDir - > addData ( td , Trace : : DataType : : Frequency ) ;
td . y = p . S [ i ] ;
tSM - > addData ( td , Trace : : DataType : : Frequency ) ;
td . y = p . R [ i ] ;
tRT - > addData ( td , Trace : : DataType : : Frequency ) ;
}
ret . push_back ( tDir ) ;
ret . push_back ( tSM ) ;
ret . push_back ( tRT ) ;
for ( unsigned int j = 0 ; j < caltype . usedPorts . size ( ) ; j + + ) {
if ( i = = j ) {
continue ;
}
auto p2 = caltype . usedPorts [ j ] ;
auto tRM = new Trace ( " ReceiverMatch_ " + QString : : number ( p ) + QString : : number ( p2 ) ) ;
tRM - > setReflection ( true ) ;
tRM - > setCalibration ( ) ;
auto tTT = new Trace ( " TransmissionTracking_ " + QString : : number ( p ) + QString : : number ( p2 ) ) ;
tTT - > setReflection ( false ) ;
tTT - > setCalibration ( ) ;
auto tTI = new Trace ( " TransmissionIsolation_ " + QString : : number ( p ) + QString : : number ( p2 ) ) ;
tTI - > setReflection ( false ) ;
tTI - > setCalibration ( ) ;
for ( auto p : points ) {
Trace : : Data td ;
td . x = p . frequency ;
td . y = p . L [ i ] [ j ] ;
tRM - > addData ( td , Trace : : DataType : : Frequency ) ;
td . y = p . T [ i ] [ j ] ;
tTT - > addData ( td , Trace : : DataType : : Frequency ) ;
td . y = p . I [ i ] [ j ] ;
tTI - > addData ( td , Trace : : DataType : : Frequency ) ;
}
ret . push_back ( tRM ) ;
ret . push_back ( tTT ) ;
ret . push_back ( tTI ) ;
}
}
return ret ;
}
std : : vector < Trace * > Calibration : : getMeasurementTraces ( )
{
vector < Trace * > ret ;
for ( auto m : measurements ) {
switch ( m - > getType ( ) ) {
case CalibrationMeasurement : : Base : : Type : : Open :
case CalibrationMeasurement : : Base : : Type : : Short :
case CalibrationMeasurement : : Base : : Type : : Load : {
auto onePort = static_cast < CalibrationMeasurement : : OnePort * > ( m ) ;
auto t = new Trace ( CalibrationMeasurement : : Base : : TypeToString ( onePort - > getType ( ) ) + " _Port " + QString : : number ( onePort - > getPort ( ) ) ) ;
t - > setCalibration ( ) ;
t - > setReflection ( true ) ;
for ( auto d : onePort - > getPoints ( ) ) {
Trace : : Data td ;
td . x = d . frequency ;
td . y = d . S ;
t - > addData ( td , Trace : : DataType : : Frequency ) ;
}
ret . push_back ( t ) ;
}
break ;
case CalibrationMeasurement : : Base : : Type : : Through : {
auto twoPort = static_cast < CalibrationMeasurement : : TwoPort * > ( m ) ;
auto ts11 = new Trace ( CalibrationMeasurement : : Base : : TypeToString ( twoPort - > getType ( ) ) + " _Port " + QString : : number ( twoPort - > getPort1 ( ) ) + QString : : number ( twoPort - > getPort2 ( ) ) + " _S11 " ) ;
auto ts12 = new Trace ( CalibrationMeasurement : : Base : : TypeToString ( twoPort - > getType ( ) ) + " _Port " + QString : : number ( twoPort - > getPort1 ( ) ) + QString : : number ( twoPort - > getPort2 ( ) ) + " _S12 " ) ;
auto ts21 = new Trace ( CalibrationMeasurement : : Base : : TypeToString ( twoPort - > getType ( ) ) + " _Port " + QString : : number ( twoPort - > getPort1 ( ) ) + QString : : number ( twoPort - > getPort2 ( ) ) + " _S21 " ) ;
auto ts22 = new Trace ( CalibrationMeasurement : : Base : : TypeToString ( twoPort - > getType ( ) ) + " _Port " + QString : : number ( twoPort - > getPort1 ( ) ) + QString : : number ( twoPort - > getPort2 ( ) ) + " _S22 " ) ;
ts11 - > setCalibration ( ) ;
ts11 - > setReflection ( true ) ;
ts12 - > setCalibration ( ) ;
ts12 - > setReflection ( false ) ;
ts21 - > setCalibration ( ) ;
ts21 - > setReflection ( false ) ;
ts22 - > setCalibration ( ) ;
ts22 - > setReflection ( true ) ;
for ( auto d : twoPort - > getPoints ( ) ) {
Trace : : Data td ;
td . x = d . frequency ;
td . y = d . S . m11 ;
ts11 - > addData ( td , Trace : : DataType : : Frequency ) ;
td . y = d . S . m12 ;
ts12 - > addData ( td , Trace : : DataType : : Frequency ) ;
td . y = d . S . m21 ;
ts21 - > addData ( td , Trace : : DataType : : Frequency ) ;
td . y = d . S . m22 ;
ts22 - > addData ( td , Trace : : DataType : : Frequency ) ;
}
ret . push_back ( ts11 ) ;
ret . push_back ( ts12 ) ;
ret . push_back ( ts21 ) ;
ret . push_back ( ts22 ) ;
}
break ;
case CalibrationMeasurement : : Base : : Type : : Isolation : {
auto iso = static_cast < CalibrationMeasurement : : Isolation * > ( m ) ;
int ports = iso - > getPoints ( ) [ 0 ] . S . size ( ) ;
// Create the traces
vector < vector < Trace * > > traces ;
traces . resize ( ports ) ;
for ( int i = 0 ; i < ports ; i + + ) {
for ( int j = 0 ; j < ports ; j + + ) {
auto t = new Trace ( CalibrationMeasurement : : Base : : TypeToString ( iso - > getType ( ) ) + " _S " + QString : : number ( i + 1 ) + QString : : number ( j + 1 ) ) ;
t - > setCalibration ( ) ;
t - > setReflection ( i = = j ) ;
traces [ i ] . push_back ( t ) ;
// also add to main return vector
ret . push_back ( t ) ;
}
}
// Fill the traces
for ( auto p : iso - > getPoints ( ) ) {
Trace : : Data td ;
td . x = p . frequency ;
for ( int i = 0 ; i < p . S . size ( ) ; i + + ) {
for ( int j = 0 ; j < p . S [ i ] . size ( ) ; j + + ) {
td . y = p . S [ i ] [ j ] ;
traces [ i ] [ j ] - > addData ( td , Trace : : DataType : : Frequency ) ;
}
}
}
}
break ;
}
}
return ret ;
}
QString Calibration : : getCurrentCalibrationFile ( )
{
return currentCalFile ;
}
double Calibration : : getMinFreq ( )
{
if ( points . size ( ) > 0 ) {
return points . front ( ) . frequency ;
} else {
return numeric_limits < double > : : quiet_NaN ( ) ;
}
}
double Calibration : : getMaxFreq ( )
{
if ( points . size ( ) > 0 ) {
return points . back ( ) . frequency ;
} else {
return numeric_limits < double > : : quiet_NaN ( ) ;
}
}
int Calibration : : getNumPoints ( )
{
return points . size ( ) ;
}
QString Calibration : : descriptiveCalName ( )
{
if ( points . size ( ) = = 0 ) {
return QString ( ) ;
}
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 ;
}
bool Calibration : : hasUnsavedChanges ( ) const
{
return unsavedChanges ;
}
Calkit & Calibration : : getKit ( )
{
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 ) ;
}
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 ) ;
}
j [ " ports " ] = jports ;
j [ " version " ] = qlibrevnaApp - > applicationVersion ( ) . toStdString ( ) ;
if ( VirtualDevice : : getConnected ( ) ) {
j [ " device " ] = VirtualDevice : : getConnected ( ) - > serial ( ) . toStdString ( ) ;
}
return j ;
}
void Calibration : : fromJSON ( nlohmann : : json j )
{
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 ) ;
}
}
if ( ct . type ! = Type : : None ) {
compute ( ct ) ;
}
}
bool Calibration : : toFile ( QString filename )
{
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 ;
}
}
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
unsavedChanges = false ;
return true ;
}
bool Calibration : : fromFile ( QString filename )
{
if ( filename . isEmpty ( ) ) {
filename = QFileDialog : : getOpenFileName ( nullptr , " Load calibration data " , " " , " Calibration files (*.cal) " , nullptr , QFileDialog : : DontUseNativeDialog ) ;
if ( filename . isEmpty ( ) ) {
// aborted selection
return false ;
}
}
// force correct file ending
if ( filename . toLower ( ) . endsWith ( " .cal " ) ) {
filename . chop ( 4 ) ;
filename + = " .cal " ;
}
qDebug ( ) < < " Attempting to open calibration from file " < < filename ;
ifstream file ;
file . open ( filename . toStdString ( ) ) ;
if ( ! file . good ( ) ) {
QString msg = " Unable to open file: " + filename ;
InformationBox : : ShowError ( " Error " , msg ) ;
qWarning ( ) < < msg ;
return false ;
}
try {
nlohmann : : json j ;
file > > j ;
currentCalFile = filename ; // if all ok, remember this
fromJSON ( j ) ;
} catch ( exception & e ) {
currentCalFile . clear ( ) ;
InformationBox : : ShowError ( " File parsing error " , e . what ( ) ) ;
qWarning ( ) < < " Calibration file parsing failed: " < < e . what ( ) ;
return false ;
}
unsavedChanges = false ;
return true ;
}
std : : vector < Calibration : : CalType > Calibration : : getAvailableCalibrations ( )
{
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 ( ) ) ) ;
}
}
return ret ;
}
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 ) ;
}
return types ;
}
bool Calibration : : canCompute ( Calibration : : CalType type , double * startFreq , double * stopFreq , int * points )
{
using RequiredMeasurements = struct {
CalibrationMeasurement : : Base : : Type type ;
int port1 , port2 ;
} ;
vector < RequiredMeasurements > required ;
switch ( type . type ) {
case Type : : None :
return true ; // Always possible to reset the calibration
case Type : : SOLT :
// 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 } ) ;
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 + + ) {
for ( int j = i + 1 ; j < = type . usedPorts . size ( ) ; j + + ) {
required . push_back ( { . type = CalibrationMeasurement : : Base : : Type : : Through , . port1 = i , . port2 = j } ) ;
}
}
break ;
case Type : : ThroughNormalization :
// 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 } ) ;
}
}
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 < 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 ) ;
}
return false ;
}
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 ;
2022-10-02 05:11:13 +08:00
case Type : : ThroughNormalization : p = computeThroughNormalization ( f ) ; break ;
case Type : : TRL : p = computeTRL ( f ) ; break ;
2022-10-01 23:10:44 +08:00
}
points . push_back ( p ) ;
}
} catch ( exception & e ) {
points . clear ( ) ;
caltype . usedPorts . clear ( ) ;
}
emit activated ( caltype ) ;
2022-10-02 05:11:13 +08:00
unsavedChanges = true ;
2022-10-01 23:10:44 +08:00
return true ;
}
void Calibration : : reset ( )
{
deleteMeasurements ( ) ;
deactivate ( ) ;
}
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 ;
}
void Calibration : : addMeasurements ( std : : set < CalibrationMeasurement : : Base * > m , const VirtualDevice : : VNAMeasurement & data )
{
for ( auto meas : m ) {
meas - > addPoint ( data ) ;
}
unsavedChanges = true ;
}
void Calibration : : clearMeasurements ( std : : set < CalibrationMeasurement : : Base * > m )
{
for ( auto meas : m ) {
meas - > clearPoints ( ) ;
}
2022-10-02 05:11:13 +08:00
unsavedChanges = true ;
2022-10-01 23:10:44 +08:00
}
void Calibration : : measurementsComplete ( )
{
emit measurementsUpdated ( ) ;
}
void Calibration : : deactivate ( )
{
points . clear ( ) ;
caltype . type = Type : : None ;
caltype . usedPorts . clear ( ) ;
2022-10-02 05:11:13 +08:00
unsavedChanges = true ;
2022-10-01 23:10:44 +08:00
emit deactivated ( ) ;
}
QString Calibration : : DefaultMeasurementsToString ( Calibration : : DefaultMeasurements dm )
{
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 " ;
}
}
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 ;
}
}
void Calibration : : deleteMeasurements ( )
{
for ( auto m : measurements ) {
delete m ;
}
measurements . clear ( ) ;
}
bool Calibration : : hasFrequencyOverlap ( std : : vector < CalibrationMeasurement : : Base * > m , double * startFreq , double * stopFreq , int * points )
{
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 ;
}
auto resolution = ( meas - > maxFreq ( ) - meas - > minFreq ( ) ) / ( meas - > numPoints ( ) - 1 ) ;
if ( meas - > maxFreq ( ) < maxFreq ) {
maxFreq = meas - > maxFreq ( ) ;
}
if ( meas - > minFreq ( ) > minFreq ) {
minFreq = meas - > minFreq ( ) ;
}
if ( resolution < minResolution ) {
minResolution = resolution ;
}
}
if ( startFreq ) {
* startFreq = minFreq ;
}
if ( stopFreq ) {
* stopFreq = maxFreq ;
}
if ( points ) {
* points = ( maxFreq - minFreq ) / minResolution + 1 ;
}
if ( maxFreq > minFreq ) {
return true ;
} else {
return false ;
}
}
std : : vector < CalibrationMeasurement : : Base * > Calibration : : findMeasurements ( CalibrationMeasurement : : Base : : Type type , int port1 , int port2 )
{
vector < CalibrationMeasurement : : Base * > ret ;
for ( auto m : measurements ) {
if ( m - > getType ( ) ! = type ) {
continue ;
}
auto onePort = dynamic_cast < CalibrationMeasurement : : OnePort * > ( m ) ;
if ( onePort ) {
if ( onePort - > getPort ( ) ! = port1 ) {
continue ;
}
}
auto twoPort = dynamic_cast < CalibrationMeasurement : : TwoPort * > ( m ) ;
if ( twoPort ) {
if ( twoPort - > getPort1 ( ) ! = port1 | | twoPort - > getPort2 ( ) ! = port2 ) {
continue ;
}
}
// if we get here, we have a match
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 ;
}
}
QString Calibration : : CalType : : getReadableDescription ( )
{
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 + = " ] " ;
}
return ret ;
}
QString Calibration : : CalType : : getShortString ( )
{
QString ret = TypeToString ( this - > type ) ;
if ( usedPorts . size ( ) > 0 ) {
ret + = " _ " ;
}
for ( auto p : usedPorts ) {
ret + = QString : : number ( p ) ;
}
return ret ;
}
Calibration : : CalType Calibration : : CalType : : fromShortString ( QString s )
{
CalType ret ;
auto list = s . split ( " _ " ) ;
if ( list . size ( ) ! = 2 ) {
ret . type = Type : : None ;
} else {
ret . type = TypeFromString ( list [ 0 ] ) ;
for ( auto c : list [ 1 ] ) {
ret . usedPorts . push_back ( QString ( c ) . toInt ( ) ) ;
}
}
return ret ;
}
Calibration : : Point Calibration : : Point : : interpolate ( const Calibration : : Point & to , double alpha )
{
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 ;
}