#include "impedancematchdialog.h" #include "ui_impedancematchdialog.h" #include "Tools/eseries.h" #include "Util/util.h" #include "preferences.h" using namespace std; ImpedanceMatchDialog::ImpedanceMatchDialog(MarkerModel &model, Marker *marker, QWidget *parent) : QDialog(parent), ui(new Ui::ImpedanceMatchDialog) { ui->setupUi(this); Z0 = 50.0; // set SI units and prefixes ui->zReal->setUnit("Ohm"); ui->zImag->setUnit("Ohm"); ui->zFreq->setUnit("Hz"); ui->zFreq->setPrefixes(" kMG"); ui->mImag->setUnit("Ohm"); ui->mReal->setUnit("Ohm"); ui->mLoss->setUnit("db"); ui->lValue->setUnit("H"); ui->lValue->setPrefixes("pnum "); ui->cValue->setUnit("F"); ui->cValue->setPrefixes("pnum "); connect(ui->zFreq, &SIUnitEdit::valueChanged, this, &ImpedanceMatchDialog::calculateMatch); connect(ui->zImag, &SIUnitEdit::valueChanged, this, &ImpedanceMatchDialog::calculateMatch); connect(ui->zReal, &SIUnitEdit::valueChanged, this, &ImpedanceMatchDialog::calculateMatch); connect(ui->zGroup, qOverload(&QButtonGroup::idClicked), this, &ImpedanceMatchDialog::calculateMatch); connect(ui->cMatchType, qOverload(&QComboBox::currentIndexChanged), this, &ImpedanceMatchDialog::calculateMatch); connect(ui->lGroup, qOverload(&QButtonGroup::idClicked), this, &ImpedanceMatchDialog::calculateMatch); connect(ui->cGroup, qOverload(&QButtonGroup::idClicked), this, &ImpedanceMatchDialog::calculateMatch); connect(ui->zGroup, qOverload(&QButtonGroup::idClicked), this, &ImpedanceMatchDialog::calculateMatch); // populate marker options auto markers = model.getMarkers(); for(auto m : markers) { if(!m->trace()->isReflection()) { // matching only possible for reflections continue; } ui->cSource->addItem("From Marker "+QString::number(m->getNumber()), QVariant::fromValue(m)); if(m == marker) { // select the last index, e.i. the just created marker ui->cSource->setCurrentIndex(ui->cSource->count()-1); } } } ImpedanceMatchDialog::~ImpedanceMatchDialog() { delete ui; } void ImpedanceMatchDialog::on_cSource_currentIndexChanged(int index) { ui->rbSeries->setEnabled(index == 0); ui->rbParallel->setEnabled(index == 0); ui->zReal->setEnabled(index == 0); ui->zImag->setEnabled(index == 0); ui->zFreq->setEnabled(index == 0); if(index > 0) { auto m = qvariant_cast(ui->cSource->itemData(index)); ui->rbSeries->setChecked(true); auto data = m->getData(); Z0 = m->getTrace()->getReferenceImpedance(); auto reflection = Z0 * (1.0 + data) / (1.0 - data); ui->zReal->setValue(reflection.real()); ui->zImag->setValue(reflection.imag()); ui->zFreq->setValue(m->getPosition()); } else { Z0 = 50.0; } } void ImpedanceMatchDialog::calculateMatch() { try { double freq = ui->zFreq->value(); complex Z; if(ui->rbSeries->isChecked()) { Z.real(ui->zReal->value()); Z.imag(ui->zImag->value()); } else { auto real = complex(ui->zReal->value(), 0.0); auto imag = complex(0.0, ui->zImag->value()); // calculate parallel impedance Z = real * imag / (real + imag); } bool seriesC = ui->cMatchType->currentIndex() == 0 ? true : false; // equations taken from http://www.ittc.ku.edu/~jstiles/723/handouts/section_5_1_Matching_with_Lumped_Elements_package.pdf double B, X; if(Z.real() > Z0) { B = sqrt(Z.real()/Z0)*sqrt(norm(Z)-Z0*Z.real()); if (seriesC) { B = -B; } B += Z.imag(); B /= norm(Z); X = 1/B + Z.imag()*Z0/Z.real()-Z0/(B*Z.real()); } else { B = sqrt((Z0-Z.real())/Z.real())/Z0; X = sqrt(Z.real()*(Z0-Z.real())); if (seriesC) { B = -B; X = -X; } X -= Z.imag(); } // convert X and B to inductor and capacitor bool twoCs = false; bool twoLs = false; double L = 0, C = 0, C2 = 0, L2 = 0; if(X >= 0) { L = X/(2*M_PI*freq); if(B > 0) { C = B/(2*M_PI*freq); } else { L2 = X/(2*M_PI*freq); L = -1/(B*2*M_PI*freq); twoLs = true; } } else { C = -1/(X*2*M_PI*freq); if(B < 0) { L = -1/(B*2*M_PI*freq); } else { C2 = B/(2*M_PI*freq); twoCs = true; } } ESeries::Series Lseries; if(ui->lE6->isChecked()) { Lseries = ESeries::Series::E6; } else if(ui->lE12->isChecked()) { Lseries = ESeries::Series::E12; } else if(ui->lE24->isChecked()) { Lseries = ESeries::Series::E24; } else if(ui->lE48->isChecked()) { Lseries = ESeries::Series::E48; } else if(ui->lE96->isChecked()) { Lseries = ESeries::Series::E96; } else { Lseries = ESeries::Series::Ideal; } ESeries::Series Cseries; if(ui->cE6->isChecked()) { Cseries = ESeries::Series::E6; } else if(ui->cE12->isChecked()) { Cseries = ESeries::Series::E12; } else if(ui->cE24->isChecked()) { Cseries = ESeries::Series::E24; } else if(ui->cE48->isChecked()) { Cseries = ESeries::Series::E48; } else if(ui->cE96->isChecked()) { Cseries = ESeries::Series::E96; } else { Cseries = ESeries::Series::Ideal; } L = ESeries::ToESeries(L, Lseries); C = ESeries::ToESeries(C, Cseries); L2 = ESeries::ToESeries(L2, Lseries); C2 = ESeries::ToESeries(C2, Cseries); if(twoCs) { for(auto b : ui->lGroup->buttons()) { b->setEnabled(false); } for(auto b : ui->cGroup->buttons()) { b->setEnabled(true); } ui->lL->setText("C1:"); ui->lC->setText("C2:"); ui->lValue->setUnit("F"); ui->cValue->setUnit("F"); ui->lValue->setValue(C2); ui->cValue->setValue(C); } else if(twoLs) { for(auto b : ui->cGroup->buttons()) { b->setEnabled(false); } for(auto b : ui->lGroup->buttons()) { b->setEnabled(true); } ui->lC->setText("L2:"); ui->lL->setText("L1:"); ui->cValue->setUnit("H"); ui->lValue->setUnit("H"); ui->cValue->setValue(L2); ui->lValue->setValue(L); } else { for(auto b : ui->cGroup->buttons()) { b->setEnabled(true); } for(auto b : ui->lGroup->buttons()) { b->setEnabled(true); } ui->lC->setText("C:"); ui->lL->setText("L:"); ui->lValue->setUnit("H"); ui->cValue->setUnit("F"); ui->lValue->setValue(L); ui->cValue->setValue(C); } // calculate actual matched impedance complex Zmatched; complex Zp, Zs; if(seriesC) { if(twoLs) { Zs = complex(0, 2*M_PI*freq*L2); Zp = complex(0, 2*M_PI*freq*L); } else if(twoCs) { Zs = complex(0, -1/(2*M_PI*freq*C2)); Zp = complex(0, -1/(2*M_PI*freq*C)); } else { Zs = complex(0, -1/(2*M_PI*freq*C)); Zp = complex(0, 2*M_PI*freq*L); } } else { if(twoCs) { Zs = complex(0, -1/(2*M_PI*freq*C)); Zp = complex(0, -1/(2*M_PI*freq*C2)); } else if(twoLs){ Zs = complex(0, 2*M_PI*freq*L); Zp = complex(0, 2*M_PI*freq*L2); } else { Zs = complex(0, 2*M_PI*freq*L); Zp = complex(0, -1/(2*M_PI*freq*C)); } } if(Z.real() > Z0) { Zmatched = Z*Zp/(Z+Zp) + Zs; } else { Zmatched = Zp*(Z+Zs)/(Zp+Z+Zs); } ui->mReal->setValue(Zmatched.real()); ui->mImag->setValue(Zmatched.imag()); double reflection = abs((Zmatched-Z0)/(Zmatched+Z0)); auto loss = Util::SparamTodB(reflection); ui->mLoss->setValue(loss); // set correct image if(Z.real() > Z0) { if(X >= 0 && B >= 0) { ui->Image->setPixmap(QPixmap(":/icons/sLpC_small.png")); } else if(X < 0 && B < 0) { ui->Image->setPixmap(QPixmap(":/icons/sCpL_small.png")); } else if(X >= 0 && B < 0) { ui->Image->setPixmap(QPixmap(":/icons/sCpC_small.png")); } else { ui->Image->setPixmap(QPixmap(":/icons/sLpL_small.png")); } } else { if(X >= 0 && B >= 0) { ui->Image->setPixmap(QPixmap(":/icons/pCsL_small.png")); } else if(X < 0 && B < 0) { ui->Image->setPixmap(QPixmap(":/icons/pLsC_small.png")); } else if(X >= 0 && B < 0) { ui->Image->setPixmap(QPixmap(":/icons/pLsL_small.png")); } else { ui->Image->setPixmap(QPixmap(":/icons/pCsC_small.png")); } } } catch (exception &e){ // something went wrong, probably caused by (intermediate) invalid input, such as f=0Hz ui->lValue->setValue(nan("")); ui->cValue->setValue(nan("")); ui->mReal->setValue(nan("")); ui->mImag->setValue(nan("")); ui->mLoss->setValue(nan("")); } }