44 from math
import log10, ceil, pi, sin, sqrt
45 from functools
import partial
48 import PyQt4.Qwt5
as Qwt
49 from dbplot
import DbPlot
52 from scipy
import interpolate
54 import Ui_parameditdlg
55 import Ui_couplingmatrixdlg
56 import Ui_matrixeditdlg
57 import Ui_tempvariationdlg
61 MAC =
"qt_mac_set_native_menubar" in dir()
63 from libcommonfunc
import complexStr, listStr, myPrint, setGlobalVariablesLibCommonFunc, Parameters, readParamFile, printHeader, Sparameters, CouplingMatrices, FrequencyTransformBP, parseError, synthError, licenseError, criticalErrorMsg, warningMsg, saveSignificantDigits, saveSignificantDigitsEnergy
64 from libfreefilters
import CharPolys, setGlobalVariablesLibFreeFilters
68 if os.path.exists(
'libextrafilters.pyc'): existingExtraFilters =
True
69 else: existingExtraFilters =
False
70 from libextrafilters
import TZoptimMask
74 importedExtraFilters =
False
76 importedExtraFilters =
True
80 if os.path.exists(
'liblossyfilters.pyc'): existingLossyFilters =
True
81 else: existingLossyFilters =
False
82 from liblossyfilters
import predistortion, nonUniformQ, importedCheckLicense, existingCheckLicense
86 importedLossyFilters =
False
88 importedLossyFilters =
True
102 super(EnergyDbPlot, self).
__init__(*posPars, **keyPars)
104 horLayout = QHBoxLayout()
105 horLayout.addStretch()
106 horLayout.addWidget(QLabel(
"Excitation:"))
107 self.excitation_comboBox = QComboBox()
108 self.excitation_comboBox.addItems([
'Direct (S->L)',
'Reverse (L->S)'])
109 horLayout.addWidget(self.excitation_comboBox)
110 horLayout.addSpacing(20)
111 horLayout.addWidget(QLabel(
"Input power:"))
112 self.inputPower_doubleSpinBox = QDoubleSpinBox()
113 self.inputPower_doubleSpinBox.setRange(0, 1e9)
114 self.inputPower_doubleSpinBox.setValue(1)
115 horLayout.addWidget(self.inputPower_doubleSpinBox)
116 horLayout.addWidget(QLabel(
"W"))
126 self.verticalLayout.insertLayout(0, horLayout)
129 self.connect(self.inputPower_doubleSpinBox, SIGNAL(
"valueChanged(double)"), self.updateInputPower)
130 self.connect(self.excitation_comboBox, SIGNAL(
"currentIndexChanged(int)"), self.updateExcitation)
134 self.leftYDataRev = []
138 self.rightYDataRev = []
148 for nTab
in range(self.Ntabs):
149 newLeftYData = [ value*data
for data
in np.array(self.leftYData[nTab]) ]
150 newRightYData = [ value*data
for data
in self.rightYData[nTab] ]
if self.rightYData[nTab]
is not None else None
152 self.update(nTab, XData = self.XData[nTab], rightXData = self.rightXData[nTab], leftYData = newLeftYData, rightYData = newRightYData )
153 self.autoScaleSomeAxis(nTab, autoScaleBottomX =
False, autoScaleLeftY =
True, autoScaleRightY =
True)
163 for nTab
in range(self.Ntabs):
165 newLeftYData = self.leftYData[nTab]
166 newRightYData = self.rightYData[nTab]
168 newLeftYData = self.leftYDataRev[nTab]
169 newRightYData = self.rightYDataRev[nTab]
171 self.update(nTab, XData = self.XData[nTab], rightXData = self.rightXData[nTab], leftYData = newLeftYData, rightYData = newRightYData )
172 self.autoScaleSomeAxis(nTab, autoScaleBottomX =
False, autoScaleLeftY =
True, autoScaleRightY =
True)
183 self.leftYDataRev.append(leftYDataRev)
184 self.rightYDataRev.append(rightYDataRev)
195 self.leftYDataRev[nTab] = leftYDataRev
196 self.rightYDataRev[nTab] = rightYDataRev
199 self.updateExcitation(self.excitation_comboBox.currentIndex())
206 class TempVarDlg(QDialog, Ui_tempvariationdlg.Ui_TempVarDlg):
208 def __init__(self, parent=None):
209 super(TempVarDlg, self).__init__(parent)
242 if temVarDlg.exec_():
243 if temVarDlg.temVar_groupBox.isChecked() ==
True:
244 alpha = temVarDlg.coef_doubleSpinBox.value()*1e-6
245 Tamb = temVarDlg.Tamb_doubleSpinBox.value()
246 Tmax = temVarDlg.Tmax_doubleSpinBox.value()
247 Tmin = temVarDlg.Tmin_doubleSpinBox.value()
248 return alpha*(Tmax-Tamb), alpha*(Tamb-Tmin)
261 def nextNonComment():
262 line = file.readline()
263 while len(line)>0
and (line.startswith(
'!')
or len(line.strip()) == 0): line = file.readline()
272 def getUnitsFactor(units):
273 try: factor = unitsFactorDict[units]
274 except KeyError, err:
raise parseError,
"Incorrect frequency units '%s', should be one of: %s" % (units, str(unitsFactorDict.keys()))
287 unitsFactors = np.array([ getUnitsFactor(units)
for units
in unitsList ] )
290 while len(line)>0
and not line.startswith(
'#'):
293 xArray = np.array( [ float(x)
for x
in line.split() ] )
294 if len(xArray) != len(unitsFactors):
raise parseError,
"Number of data columns different than number of units in Mask format line (%s)" % str([parType] + unitsList)
295 data.append(xArray * unitsFactors)
298 line = nextNonComment()
299 data = np.array(data).squeeze()
301 if data.ndim == 0: data = float(data)
307 fbasename = os.path.basename(fileName)
386 file = open(fileName,
'r')
388 criticalErrorMsg(
'Cannot open Mask specification file:<p>' + unicode(err) )
389 myPrint(
'Failed to open Mask specification file: %s' % fbasename)
392 freqShiftRight, freqShiftLeft = getTempVar()
393 if freqShiftLeft
is None and freqShiftRight
is None:
394 freqShiftLeft, freqShiftRight = 0, 0
395 myPrint(
'Mask temperature freq shift (relative) = %.2e to the right and %.2e to the left' % (freqShiftRight, freqShiftLeft))
405 myPrint(
'Reading [S] Mask specification file: %s' % fbasename)
407 unitsFactorDict = {
'Hz': 1,
'kHz': 1e3,
'MHz': 1e6,
'GHz': 1e9,
'dB': 1,
's': 1,
'ms': 1e-3,
'us': 1e-6,
'ns': 1e-9 }
410 line = nextNonComment()
412 if not line.lstrip().startswith(
'#'):
raise parseError,
'Incorrect file format'
413 optionList = line[1:].split()
414 parType, unitsList = optionList[0], optionList[1:]
415 line = nextNonComment()
417 if parType.upper() ==
'f0'.upper(): self.
f0, line = getData(line)
418 elif parType.upper() ==
'BW'.upper(): self.
BW, line = getData(line)
419 elif parType.upper() ==
'S11_BW'.upper(): self.
S11spec, line = getData(line)
420 elif parType.upper() ==
'S21_f0'.upper(): self.
S21_F0, line = getData(line)
421 elif parType.upper() ==
'S21_BW'.upper(): self.
S21_BW, line = getData(line)
422 elif parType.upper() ==
'S21_f_inband'.upper(): self.
S21inbandSpecDelta, line = getData(line)
423 elif parType.upper() ==
'GD_f'.upper(): self.
GDspec, line = getData(line)
424 elif parType.upper() ==
'S21_f_outband'.upper(): self.
S21outbandSpec, line = getData(line)
427 except (parseError, ValueError), err:
428 criticalErrorMsg(
'ERROR parsing specifications mask file:<p>' + unicode(err) )
429 myPrint(
'Failed to read file: %s' % fbasename)
431 myPrint(
'Loaded file: %s' % fbasename)
453 def applyFreqShift(mask, type):
457 assert type
in [
'outer',
'inner']
460 elif type ==
'inner':
465 mask[:int(M/2), 0] *= leftPartfactor
466 mask[int((M+1)/2):, 0] *= rightPartFactor
482 maxS21 = max( 20*np.log10(np.abs(SP.S21)) )
486 else: S21inband = np.array([[],[]]).T
490 S11variation[:, 1] = maxS21 - S11variation[:, 1]
491 else: S11variation = np.array([[],[]]).T
493 self.
S21inBandMask = np.concatenate(( S21inband, S11variation ) )
513 if self.
GDspec is not None:
515 indBW = (SP.freq < self.
f0 + self.
BW/4 ) & (SP.freq > self.
f0 - self.
BW/4)
516 GDf0 = np.mean(SP.groupDelay[indBW])
527 applyFreqShift(*maskAndType)
546 raise synthError,
"For optimization with a reference mask, it is necessary to<br>define 'S11_BW' optional parameter in the mask file."
549 raise synthError,
"For optimization with a reference mask, it is necessary to<br>define 'S21_f_outband' optional parameter in the mask file."
552 raise synthError,
"For optimization with a reference mask, it is necessary to<br>define 'S21_F0' and 'S21_BW' optional parameters in the mask file."
560 NpassBand = int(Nsamples/2)
563 self.
freqInbandOptim = np.linspace(minFreqInBand, maxFreqInBand, NpassBand)
568 assert NS21out % 2 == 0,
'Number of samples in S21outBandMask must be even'
569 nonNaN = range(0, NS21out/2-1) + range(NS21out/2+1, NS21out)
571 minFreqOutBandLower = np.min(self.
S21outBandMask[:NS21out/2, 0]) + eps
572 maxFreqOutBandLower = np.max(self.
S21outBandMask[:NS21out/2, 0]) - eps
573 minFreqOutBandUpper = np.min(self.
S21outBandMask[1+NS21out/2:, 0]) +eps
574 maxFreqOutBandUpper = np.max(self.
S21outBandMask[1+NS21out/2:, 0]) - eps
576 NoutBand = int((Nsamples+1)/2)
577 freqOutBandLower = np.linspace(minFreqOutBandLower, maxFreqOutBandLower, int(NoutBand/2) )
578 freqOutBandUpper = np.linspace(minFreqOutBandUpper, maxFreqOutBandUpper, int((NoutBand+1)/2) )
579 self.
freqOutBandOptim = np.concatenate([ freqOutBandLower, freqOutBandUpper ])
587 interpS11 = interpolate.interp1d(self.
S11mask[:, 0], self.
S11mask[:, 1], bounds_error =
False)
608 array1 = inArray.copy()
609 array2 = array1.copy()
610 array1[:, freqCol] = self.
f0 - array1[:, freqCol]
611 array2[:, freqCol] = self.
f0 + array2[:, freqCol]
614 closestFreq = min(inArray[:, 0])
615 hideCenter = np.array([ [self.
f0 - closestFreq, np.nan], [self.
f0 + closestFreq, np.nan] ])
616 outArray = np.concatenate((array1, hideCenter, array2))
618 outArray = np.concatenate((array1, array2))
632 sortedIndices = inArray[:,freqCol].argsort()
633 inArray[:, :] = inArray[sortedIndices, :]
638 st +=
'*** Specifications ***\n\n'
639 st +=
'Central frequency:\n' + str(self.
f0) +
'\n\n'
640 st +=
'Bandwidth:\n' + str(self.
BW) +
'\n\n'
641 st +=
'Specification for S11 (return losses):\n' + str(self.
S11spec) +
'\n\n'
642 st +=
'Value of S21 at f0 (insertion losses):\n' + str(self.
S21_F0) +
'\n\n'
643 st +=
'Value of S21 over bandwidth (insertion losses):\n' + str(self.
S21_BW) +
'\n\n'
644 st +=
'S21 variation over bandwidth (insertion losses):\n' + str(self.
S21inbandSpecDelta) +
'\n\n'
645 st +=
'S21 out of band rejection: \n' + str(self.
S21outbandSpec) +
'\n\n'
646 st +=
'Group delay mask:\n' + str(self.
GDspec) +
'\n\n'
648 st +=
'*** Masks ***\n\n'
649 st +=
'Mask for S11 (return losses): \n' + str(self.
S11mask) +
'\n\n'
650 st +=
'Mask for S21 in-band (insertion losses)\n' + str(self.
S21inBandMask) +
'\n\n'
651 st +=
'Mask for S21 for out-of-band rejection: \n' + str(self.
S21outBandMask) +
'\n\n'
652 st +=
'Mask for GD (upper): \n' + str(self.
GDmaskUpper) +
'\n\n'
653 st +=
'Mask for GD (lower): \n' + str(self.
GDmaskLower) +
'\n\n'
674 fbasename = os.path.basename(fileName)
677 file = open(fileName,
'r')
680 myPrint(
'Failed to open [S] Touchstone file: %s' % fbasename)
683 myPrint(
'Reading [S] from Touchstone file: %s' % fbasename)
687 freqfactorDict = {
'HZ': 1,
'KHZ': 1e3,
'MHZ': 1e6,
'GHZ': 1e9}
688 optionsLoaded =
False
689 freq, S11, S21, S12, S22 = [], [], [], [], []
693 stList = file.readlines()
695 if len(st.lstrip()) == 0:
continue
696 if st.lstrip().startswith(
'!'):
700 if st.lstrip().startswith(
'#'):
701 if optionsLoaded:
raise parseError,
"There are more than one options line."
703 optionList = st.split()
706 if len(optionList) != 6:
raise parseError,
"Incorrect number of items in option line."
709 units = optionList[1].upper()
710 try: freqFactor = freqfactorDict[units]
711 except KeyError, err:
raise parseError,
"Incorrect frequency units '%s'" % units
715 if type !=
'S':
raise parseError,
"Type of parameter is not 'S'."
718 dataFormat = optionList[3].upper()
719 if dataFormat
not in [
'MA',
'DB',
'RI']:
raise parseError,
"Data format '%s' is not 'MA', 'DB', or 'RI'." % dataFormat
722 if optionList[4] !=
'R': raise parseError, "Options line does not include 'R' parameter."
723 impedance = optionList[5]
728 try: f, S11a, S11b, S21a, S21b, S12a, S12b, S22a, S22b = [ float(n)
for n
in st.split()]
729 except ValueError:
raise parseError,
"Data line '%s' contains incorrect number of items" % st
731 freq.append(f * freqFactor)
733 if dataFormat ==
'RI':
734 S11.append( complex(S11a, S11b) )
735 S21.append( complex(S21a, S21b) )
736 S12.append( complex(S12a, S12b) )
737 S22.append( complex(S22a, S22b) )
738 if dataFormat ==
'MA':
739 S11.append( S11a * np.exp(1j * S11b * pi/180) )
740 S21.append( S21a * np.exp(1j * S21b * pi/180) )
741 S12.append( S12a * np.exp(1j * S12b * pi/180) )
742 S22.append( S22a * np.exp(1j * S22b * pi/180) )
743 if dataFormat ==
'DB':
744 S11.append( 10**(S11a/20) * np.exp(1j * S11b * pi/180) )
745 S21.append( 10**(S21a/20) * np.exp(1j * S21b * pi/180) )
746 S12.append( 10**(S12a/20) * np.exp(1j * S12b * pi/180) )
747 S22.append( 10**(S22a/20) * np.exp(1j * S22b * pi/180) )
752 except parseError, err:
754 myPrint(
'Failed to read file: %s' % fbasename)
756 myPrint(
'Loaded file: %s' % fbasename)
760 self.
freq = np.array(freq)
764 self.
S11 = np.array(S11)
768 self.
S21 = np.array(S21)
772 self.
S12 = np.array(S12)
776 self.
S22 = np.array(S22)
815 def __init__(self, name = None, mainDlg = None, parent=None):
816 super(myTableWidget, self).
__init__(parent)
856 self.
f0 = float(self.mainDlg.f0_lineEdit.text()) * 10**(3*self.mainDlg.f0UnitsIndex)
861 freqFactor = pow(10, 3*self.mainDlg.transmissionZerosUnitsIndex)
864 item = self.item(m, 2)
865 stIm = str(item.text()).strip()
if item
is not None else ''
868 newItem = QTableWidgetItem(
'')
869 self.setItem(m, 1, newItem)
871 im = float(stIm) * freqFactor
872 newItem = QTableWidgetItem(
'%.*g' % (saveSignificantDigits, (im + self.
f0) / freqFactor) )
873 newItem.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
874 self.setItem(m, 1, newItem)
882 self.resizeRowsToContents()
883 self.resizeColumnsToContents()
899 freqFactor = pow(10, 3*self.mainDlg.transmissionZerosUnitsIndex)
901 self.setCurrentCell(row, col)
902 item = self.currentItem()
903 item.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
905 stIm = str(item.text()).strip()
if item
is not None else ''
908 newItem = QTableWidgetItem(
'')
909 if col == 1: self.setItem(row, 2, newItem)
910 elif col == 2: self.setItem(row, 1, newItem)
912 im = float(stIm) * freqFactor
914 newItem = QTableWidgetItem(
'%.*g' % (saveSignificantDigits, (im - self.
f0) / freqFactor) )
915 newItem.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
916 self.setItem(row, 2, newItem)
918 newItem = QTableWidgetItem(
'%.*g' % (saveSignificantDigits, (im + self.
f0) / freqFactor) )
919 newItem.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
920 self.setItem(row, 1, newItem)
923 self.mainDlg.updateTotaltransmissionZeros()
935 self.setRowCount(N+1)
937 self.setCurrentCell(N, 1)
938 self.resizeRowsToContents()
939 self.resizeColumnsToContents()
941 self.mainDlg.updateDlgHeight()
945 return maximumSizeHint()
948 def maximumSizeHint(self):
950 size = QTableWidget.sizeHint(self)
956 width = self.verticalHeader().width() + self.horizontalScrollBar().height()
957 for c
in range(self.columnCount()): width += self.columnWidth( c )
958 size.setWidth( width + 8 )
960 height = self.horizontalHeader().height() + self.horizontalScrollBar().height()
961 for r
in range(self.rowCount()): height += self.rowHeight( r )
962 size.setHeight( height + 4 )
991 return self.maximumSizeHint()
1007 super(MainWindow, self).
__init__(parent)
1031 self.restoreGeometry(self.settings.value(
"Geometry").toByteArray())
1032 self.restoreState(self.settings.value(
"State").toByteArray())
1036 self.
lastDir = unicode(self.settings.value(
'LastDirectoryOpened', QVariant(
'.')).toString())
1039 self.setWindowTitle(applicationName)
1040 self.setWindowModified(
False)
1043 self.log_listWidget.setSelectionMode(QAbstractItemView.NoSelection)
1047 self.results_comboBox.setObjectName(
"results_comboBox")
1048 self.results_comboBox.setToolTip(
"Load result from list")
1049 self.results_comboBox.setStatusTip(
"Load result from list")
1050 self.results_comboBox.setWhatsThis(
"Load result from list")
1055 self.toolBar_3.insertAction(self.action_FileExit, QWhatsThis.createAction(self.toolBar_3))
1135 from libcommonfunc
import preGuiOutput
1142 self.action_Execute.trigger()
1144 self.action_CouplingMatrix.trigger()
1146 self.CMdialog.action_Edit.setChecked(
True)
1158 message =
"File %s has unsaved changes\nSave?" % os.path.basename(self.
fileName)
1160 message =
"New file with unsaved changes\nSave?"
1161 reply = QMessageBox.question(self,
"%s - Unsaved Changes" % applicationName, message, QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel)
1162 if reply == QMessageBox.Cancel:
1164 elif reply == QMessageBox.Yes:
1177 self.statusBar().showMessage(message, 5000)
1178 self.log_listWidget.addItem(message)
1179 self.log_listWidget.setCurrentRow(self.log_listWidget.count()-1)
1181 self.setWindowTitle(
"%s - %s[*]" % (applicationName , os.path.basename(self.
fileName)) )
1182 elif self.
P is not None and self.P.empty
is not True:
1183 self.setWindowTitle(
"%s - Unnamed[*]" % applicationName)
1185 self.setWindowTitle(
"%s[*]" % applicationName)
1186 self.setWindowModified(self.
dirty)
1198 fbasename = os.path.basename(fname)
1200 self.
lastDir = os.path.dirname(fname)
1203 QMessageBox.warning(self,
"WARNING",
1204 """<p align="center">It is not possible to open file %s<br>
1205 because it contains an invalid entry:</p>
1206 <p align="center">Please open the file with a text editor and fix it.
1209 message =
"Failed to read file: %s" % fbasename
1212 message =
"Loaded file: %s" % fbasename
1216 if self.
P is not None:
1220 if self.
P is not None:
1222 self.paramEdit.show()
1223 self.paramEdit.raise_()
1233 if self.
SPlotMagPhase is not None and not self.SPlotMagPhase.closed:
1234 self.SPlotMagPhase.close()
1243 if self.
SPlotCompare is not None and not self.SPlotCompare.closed:
1244 self.SPlotCompare.close()
1255 self.CMdialog.close()
1259 if self.
SPlotError is not None and not self.SPlotError.closed:
1260 self.SPlotError.close()
1264 if self.
EnergyPlot is not None and not self.EnergyPlot.closed:
1265 self.EnergyPlot.close()
1280 (self.
P, self.
CP, self.
CM, self.
SP, self.
FT) = (
None,
None,
None,
None,
None)
1289 if self.
SP is not None:
1290 if self.
SPlotMagPhase is None or self.SPlotMagPhase.closed
is True:
1293 linRange = min([ abs(self.SP.S21[0]), abs(self.SP.S21[-1] )])
1294 if linRange > 1e-10: dynamicRange = -20*log10(linRange)
1295 else: dynamicRange = 200
1296 dynamicRange = 10*ceil(dynamicRange/10)
1299 windowTitle =
'[S] parameters',
1300 tabTitle =
'[S] + Group delay',
1301 title =
'[S] parameters (from Characteristic Polynomials)',
1302 XData = self.SP.freq / 1e9,
1303 leftYData = [20*np.log10(np.abs(self.SP.S11)), 20*np.log10(np.abs(self.SP.S21)), 20*np.log10(np.abs(self.SP.S22))],
1304 rightYData = [ 1e9 * self.SP.groupDelay ],
1305 leftYmin = -dynamicRange,
1307 leftYNames = [
'S<sub>11</sub>',
'S<sub>21</sub>',
'S<sub>22</sub>'],
1308 leftYVisible = [
True,
True,
False],
1309 XLabel =
'Frequency (GHz)',
1311 Xunits =
'GHz', leftYunits =
'dB', rightYunits =
'ns',
1312 rightYLabel =
'Time (ns.)' ,
1313 rightYNames = [
'Group delay'],
1314 rightYVisible = [
True]
1316 self.SPlotMagPhase.addTab( tabTitle =
'[S] + Phase',
1317 title =
'[S] parameters (from Characteristic Polynomials)',
1318 XData = self.SP.freq / 1e9,
1319 leftYData = [20*np.log10(np.abs(self.SP.S11)), 20*np.log10(np.abs(self.SP.S21)), 20*np.log10(np.abs(self.SP.S22)) ],
1320 rightYData = [ self.SP.phaseS21 * 180/np.pi, self.SP.phaseS11 * 180/np.pi, self.SP.phaseS22 * 180/np.pi, self.SP.deviationLP * 180/np.pi ],
1321 leftYmin = -dynamicRange,
1323 leftYNames = [
'S<sub>11</sub>',
'S<sub>21</sub>',
'S<sub>22</sub>'],
1324 leftYVisible = [
True,
True,
False],
1325 XLabel =
'Frequency (GHz)',
1327 Xunits =
'GHz', leftYunits =
'dB', rightYunits =
'deg',
1328 rightYLabel =
'degrees' ,
1329 rightYNames = [
'Phase(S<sub>21</sub>)',
'Phase(S<sub>11</sub>)',
'Phase(S<sub>22</sub>)',
'Deviation S<sub>21</sub> from <br>linear phase'],
1330 rightYVisible = [
True,
False,
False,
False]
1332 self.SPlotMagPhase.addTab( tabTitle =
'Group delay + Phase',
1333 title =
'[S] parameters (from Characteristic Polynomials)',
1334 XData = self.SP.freq / 1e9,
1335 leftYData = [1e9 * self.SP.groupDelay],
1336 rightYData = [ self.SP.phaseS21 * 180/np.pi, self.SP.deviationLP * 180/np.pi ],
1337 leftYNames = [
'Group delay'],
1338 XLabel =
'Frequency (GHz)',
1339 leftYLabel =
'Time (ns.)',
1340 Xunits =
'GHz', leftYunits =
'ns', rightYunits =
'deg',
1341 rightYLabel =
'degrees' ,
1342 rightYNames = [
'Phase(S<sub>21</sub>)',
'Deviation from <br>linear phase'],
1343 rightYVisible = [
True,
False]
1347 self.SPlotMagPhase.update(0, self.SP.freq / 1e9, [20*np.log10(np.abs(self.SP.S11)), 20*np.log10(np.abs(self.SP.S21)), 20*np.log10(np.abs(self.SP.S22))],
1348 rightYData=[ 1e9 * self.SP.groupDelay] , autoScaleBottomX = self.
autoScaleFreq)
1350 self.SPlotMagPhase.update(1, self.SP.freq / 1e9, [20*np.log10(np.abs(self.SP.S11)), 20*np.log10(np.abs(self.SP.S21)), 20*np.log10(np.abs(self.SP.S22))],
1351 rightYData=[ self.SP.phaseS21 * 180/np.pi, self.SP.phaseS11 * 180/np.pi, self.SP.phaseS22 * 180/np.pi, self.SP.deviationLP * 180/np.pi ],
1354 self.SPlotMagPhase.update(2, self.SP.freq / 1e9, [1e9 * self.SP.groupDelay], rightYData=[ self.SP.phaseS21 * 180/np.pi, self.SP.deviationLP * 180/np.pi ],
1360 if self.
SM is not None:
1361 self.SPlotMagPhase.deleteMasks()
1370 if self.
SP is None:
return
1372 self.SM.specToMask(self.
SP)
1374 maskNameRL =
'Return losses\nmask'
1375 maskNameRJ =
'Rejection\nmask'
1376 maskNameIL =
'Insertion losses\nmask'
1377 maskNameGDL =
'Group delay\nlower mask'
1378 maskNameGDU =
'Group delay\nupper mask'
1380 if self.
SPlotMagPhase is not None and self.SPlotMagPhase.closed
is False and self.SPlotMagPhase.masks[0] == []:
1381 if self.SM.S11mask
is not None:
1382 self.SPlotMagPhase.addMask(nTab = 0, XData = self.SM.S11mask[:, 0]/1e9, YData = self.SM.S11mask[:, 1], name = maskNameRL, color = Qt.blue, type =
'Upper', axis =
'left', transpar = 32 )
1383 self.SPlotMagPhase.addMask(nTab = 1, XData = self.SM.S11mask[:, 0]/1e9, YData = self.SM.S11mask[:, 1], name = maskNameRL, color = Qt.blue, type =
'Upper', axis =
'left', transpar = 32 )
1385 if self.SM.S21outBandMask
is not None:
1386 self.SPlotMagPhase.addMask(nTab = 0, XData = self.SM.S21outBandMask[:, 0]/1e9, YData =self.SM.S21outBandMask[:, 1], name = maskNameRJ, color = Qt.red, type =
'Upper', axis =
'left', transpar = 32 )
1387 self.SPlotMagPhase.addMask(nTab = 1, XData = self.SM.S21outBandMask[:, 0]/1e9, YData =self.SM.S21outBandMask[:, 1], name = maskNameRJ, color = Qt.red, type =
'Upper', axis =
'left', transpar = 32 )
1389 if self.SM.S21inBandMask
is not None:
1390 self.SPlotMagPhase.addMask(nTab = 0, XData = self.SM.S21inBandMask[:, 0]/1e9, YData =self.SM.S21inBandMask[:, 1], name = maskNameIL, color = Qt.red, type =
'Lower', axis =
'left', transpar = 32 )
1391 self.SPlotMagPhase.addMask(nTab = 1, XData = self.SM.S21inBandMask[:, 0]/1e9, YData =self.SM.S21inBandMask[:, 1], name = maskNameIL, color = Qt.red, type =
'Lower', axis =
'left', transpar = 32 )
1393 if self.SM.GDmaskLower
is not None:
1394 self.SPlotMagPhase.addMask(nTab = 2, XData = self.SM.GDmaskLower[:, 0]/1e9, YData =self.SM.GDmaskLower[:, 1]*1e9, name = maskNameGDL, color = Qt.blue, type =
'Lower', axis =
'left', transpar = 64 )
1395 self.SPlotMagPhase.addMask(nTab = 2, XData = self.SM.GDmaskUpper[:, 0]/1e9, YData =self.SM.GDmaskUpper[:, 1]*1e9, name = maskNameGDU, color = Qt.blue, type =
'Upper', axis =
'left', transpar = 64 )
1397 self.SPlotMagPhase.changeCurveVisibility(0, [
True,
False,
False], [
False], { maskNameRL:
True, maskNameRJ:
False, maskNameIL:
False } )
1398 self.SPlotMagPhase.changeCurveVisibility(1, [
False,
True,
False], [
False,
False,
False,
False], { maskNameRL:
False, maskNameRJ:
True, maskNameIL:
True} )
1399 self.SPlotMagPhase.changeCurveVisibility(2, [
True], [
False,
False], { maskNameGDL:
True, maskNameGDU:
True } )
1401 if self.
SPlotError is not None and self.SPlotError.closed
is False and self.SPlotError.masks[0] == []:
1402 if self.SM.S11mask
is not None:
1403 self.SPlotError.addMask(nTab = 0, XData = self.SM.S11mask[:, 0]/1e9, YData = self.SM.S11mask[:, 1], name = maskNameRL, color = Qt.blue, type =
'Upper', axis =
'left', transpar = 64 )
1405 if self.SM.S21outBandMask
is not None:
1406 self.SPlotError.addMask(nTab = 1, XData = self.SM.S21outBandMask[:, 0]/1e9, YData =self.SM.S21outBandMask[:, 1], name = maskNameRJ, color = Qt.blue, type =
'Upper', axis =
'left', transpar = 64 )
1408 if self.SM.S21inBandMask
is not None:
1409 self.SPlotError.addMask(nTab = 1, XData = self.SM.S21inBandMask[:, 0]/1e9, YData =self.SM.S21inBandMask[:, 1], name = maskNameIL, color = Qt.blue, type =
'Lower', axis =
'left', transpar = 64 )
1411 if self.SM.GDmaskLower
is not None:
1412 self.SPlotError.addMask(nTab = 2, XData = self.SM.GDmaskLower[:, 0]/1e9, YData =self.SM.GDmaskLower[:, 1]*1e9, name = maskNameGDL, color = QColor(0, 175, 0), type =
'Lower', axis =
'left', transpar = 64 )
1413 self.SPlotError.addMask(nTab = 2, XData = self.SM.GDmaskUpper[:, 0]/1e9, YData =self.SM.GDmaskUpper[:, 1]*1e9, name = maskNameGDU, color = QColor(0, 175, 0), type =
'Upper', axis =
'left', transpar = 64 )
1415 if self.
SPlotSensitivity is not None and self.SPlotSensitivity.closed
is False and self.SPlotSensitivity.masks[0] == []:
1416 if self.SM.S11mask
is not None:
1417 self.SPlotSensitivity.addMask(nTab = 0, XData = self.SM.S11mask[:, 0]/1e9, YData = self.SM.S11mask[:, 1], name = maskNameRL, color = Qt.blue, type =
'Upper', axis =
'left', transpar = 32 )
1418 self.SPlotSensitivity.addMask(nTab = 1, XData = self.SM.S11mask[:, 0]/1e9, YData = self.SM.S11mask[:, 1], name = maskNameRL, color = Qt.blue, type =
'Upper', axis =
'left', transpar = 32 )
1420 if self.SM.S21outBandMask
is not None:
1421 self.SPlotSensitivity.addMask(nTab = 0, XData = self.SM.S21outBandMask[:, 0]/1e9, YData =self.SM.S21outBandMask[:, 1], name = maskNameRJ, color = Qt.red, type =
'Upper', axis =
'left', transpar = 32 )
1422 self.SPlotSensitivity.addMask(nTab = 1, XData = self.SM.S21outBandMask[:, 0]/1e9, YData =self.SM.S21outBandMask[:, 1], name = maskNameRJ, color = Qt.red, type =
'Upper', axis =
'left', transpar = 32 )
1424 if self.SM.S21inBandMask
is not None:
1425 self.SPlotSensitivity.addMask(nTab = 0, XData = self.SM.S21inBandMask[:, 0]/1e9, YData =self.SM.S21inBandMask[:, 1], name = maskNameIL, color = Qt.red, type =
'Lower', axis =
'left', transpar = 32 )
1426 self.SPlotSensitivity.addMask(nTab = 1, XData = self.SM.S21inBandMask[:, 0]/1e9, YData =self.SM.S21inBandMask[:, 1], name = maskNameIL, color = Qt.red, type =
'Lower', axis =
'left', transpar = 32 )
1428 if self.SM.GDmaskLower
is not None:
1429 self.SPlotSensitivity.addMask(nTab = 2, XData = self.SM.GDmaskLower[:, 0]/1e9, YData =self.SM.GDmaskLower[:, 1]*1e9, name = maskNameGDL, color = Qt.blue, type =
'Lower', axis =
'left', transpar = 64 )
1430 self.SPlotSensitivity.addMask(nTab = 2, XData = self.SM.GDmaskUpper[:, 0]/1e9, YData =self.SM.GDmaskUpper[:, 1]*1e9, name = maskNameGDU, color = Qt.blue, type =
'Upper', axis =
'left', transpar = 64 )
1432 self.SPlotSensitivity.changeCurveVisibility(0, [
True,
False,
False], [
False], { maskNameRL:
True, maskNameRJ:
False, maskNameIL:
False } )
1433 self.SPlotSensitivity.changeCurveVisibility(1, [
False,
True,
False], [
False,
False,
False], { maskNameRL:
False, maskNameRJ:
True, maskNameIL:
True} )
1434 self.SPlotSensitivity.changeCurveVisibility(2, [
True], [
False], { maskNameGDL:
True, maskNameGDU:
True } )
1448 if self.
SPlotMagPhase is not None and not self.SPlotMagPhase.closed:
1451 if self.
SPlotError is not None and not self.SPlotError.closed:
1452 self.CMdialog.on_action_PlotS_triggered(
True)
1455 self.CMdialog.close()
1457 self.CMdialog.show()
1459 if self.
EnergyPlot is not None and not self.EnergyPlot.closed:
1460 self.CMdialog.on_action_PlotEnergy_triggered(
True)
1463 self.CMdialog.on_runSensitivity_pushButton_clicked(
True)
1466 self.paramEdit.P = self.
P
1467 self.paramEdit.updateDialogParams()
1470 def addResultToList(self, resultArg):
1472 while len(name ) == 0:
1473 input = QInputDialog.getText (self ,
'Result name',
'Give a name to current result:')
1474 if input[1]
is False:
1478 QMessageBox.warning(self,
"WARNING",
'Result name cannot be an empty string.')
1482 result = copy.deepcopy( resultArg )
1484 index = self.results_comboBox.findText(name, Qt.MatchExactly)
1487 message =
"Result with same name already exists in list\nReplace?"
1488 reply = QMessageBox.question(self,
"%s - Result exists" % applicationName, message, QMessageBox.Yes | QMessageBox.No)
1489 if reply == QMessageBox.No:
1491 elif reply == QMessageBox.Yes:
1493 myPrint(
"Result '%s' replaced in list" % name)
1495 self.listResults.append(result)
1497 self.results_comboBox.addItem(name)
1498 index = self.results_comboBox.count() - 1
1499 self.results_comboBox.setCurrentIndex(index)
1502 myPrint(
"Result '%s' appended to list" % name)
1517 self.settings.setValue(
"Geometry", QVariant(self.saveGeometry()))
1518 self.settings.setValue(
"State", QVariant(self.saveState()))
1520 self.settings.setValue(
'LastDirectoryOpened', QVariant(self.
lastDir))
1529 @pyqtSignature(
"bool")
1538 st = st.replace(
'@package',
'Package')
1539 st = st.replace(
'@author',
'Authors:')
1540 st = st.replace(
'@date',
'Date:')
1541 st = st.replace(
'@version',
'Version:')
1543 st =
u"""<b>Lossy Filters Synthesis</b>
1545 <p>Python %s - Qt %s - PyQt %s - Numpy %s - Scipy %s - QWT %s on %s %s""" % (st, platform.python_version(),QT_VERSION_STR, PYQT_VERSION_STR,
1546 np.version.version, sc.version.version, Qwt.QWT_VERSION_STR, platform.system(), platform.release())
1548 QMessageBox.about(self,
"About %s" % applicationName, st)
1551 @pyqtSignature(
"bool")
1559 form =
HelpForm(
"GUI_help.html", self)
1564 @pyqtSignature(
"bool")
1574 @pyqtSignature(
"bool")
1583 if self.
paramEdit is not None and self.paramEdit.readDialogParams() ==
False:
1586 if self.
P is not None and self.P.empty
is False:
1588 app.setOverrideCursor(Qt.WaitCursor)
1590 app.restoreOverrideCursor()
1600 self.CMdialog.close()
1602 self.CMdialog.show()
1605 if self.
SPlotError is not None and not self.SPlotError.closed:
1607 self.CMdialog.on_action_PlotS_triggered(
True)
1609 self.SPlotError.close()
1612 if self.
EnergyPlot is not None and not self.EnergyPlot.closed:
1614 self.CMdialog.on_action_PlotEnergy_triggered(
True)
1616 self.EnergyPlot.close()
1621 self.
updateStatus(
"There are no filter parameters loaded")
1622 QMessageBox.warning(self,
"WARNING",
'There are no filter parameters loaded. Open a parameter file or create a new one.')
1626 self.paramEdit.updateDialogParams(autoFreqUnits =
False)
1627 self.paramEdit.recomputed =
True
1630 @pyqtSignature(
"bool")
1638 if self.
CM is not None:
1640 self.CMdialog.show()
1642 QMessageBox.warning(self,
"WARNING",
'No available coupling matrix to display. Open a parameter file and run synthesis.')
1645 @pyqtSignature(
"bool")
1653 QMessageBox.warning(self,
"WARNING",
'There is an open Parameter Edit Window. Close it before openning a new one.')
1656 if self.
P is not None:
1658 self.paramEdit.show()
1659 self.paramEdit.raise_()
1662 QMessageBox.warning(self,
"WARNING",
'No open parameter file to edit. Open a parameter file or create a new one.')
1665 @pyqtSignature(
"bool")
1672 if self.
P is not None:
1675 fout = codecs.open(self.
fileName,
'w',
'utf-8')
1676 fout.write( unicode(self.
P) )
1679 self.setWindowModified(self.
dirty)
1684 QMessageBox.warning(self,
"WARNING",
"There are no parameters to save.")
1686 @pyqtSignature(
"bool")
1693 if self.
P is not None:
1699 formats = [
"*.par" ]
1700 fname = unicode(QFileDialog.getSaveFileName(self,
"%s - Save Parameter File" % applicationName, dir,
"Parameter files (%s)" %
" ".join(formats)))
1704 fbasename = os.path.basename(fname)
1705 if "." not in fbasename:
1710 QMessageBox.warning(self,
"WARNING",
"There are no parameters to save.")
1712 @pyqtSignature(
"bool")
1720 QMessageBox.warning(self,
"WARNING",
'There is an open Parameter Edit Window. Close it before openning a new one.')
1733 formats = [
"*.par *.dat" ]
1734 fname = unicode(QFileDialog.getOpenFileName(self,
"%s - Open Parameter File" % applicationName, dir,
"Parameter files (%s)" %
" ".join(formats)))
1740 @pyqtSignature(
"bool")
1753 formats = [
"*.msk" ]
1754 fname = unicode(QFileDialog.getOpenFileName(self,
"%s - Open Mask Specification File" % applicationName, dir,
"Mask spec files (%s)" %
" ".join(formats)))
1757 self.action_Mask.setChecked(
True)
1764 self.action_Mask.setChecked(
False)
1768 self.action_Mask.setChecked(
False)
1772 if self.
SPlotMagPhase is not None and self.SPlotMagPhase.closed
is False:
1773 self.SPlotMagPhase.deleteMasks()
1775 if self.
SPlotError is not None and self.SPlotError.closed
is False:
1776 self.SPlotError.deleteMasks()
1778 if self.
SPlotSensitivity is not None and self.SPlotSensitivity.closed
is False:
1779 self.SPlotSensitivity.deleteMasks()
1782 if self.
SPlotMagPhase is not None and self.SPlotMagPhase.closed
is False:
1783 self.SPlotMagPhase.changeCurveVisibility(0, [
True,
True,
False], [
True])
1784 self.SPlotMagPhase.changeCurveVisibility(1, [
True,
True,
False], [
True,
False,
False,
False])
1785 self.SPlotMagPhase.changeCurveVisibility(2, [
True], [
True,
False])
1787 if self.
SPlotSensitivity is not None and self.SPlotSensitivity.closed
is False:
1788 self.SPlotSensitivity.changeCurveVisibility(0, [
True,
True,
False], [
True])
1789 self.SPlotSensitivity.changeCurveVisibility(1, [
True,
True,
False], [
True,
False,
False])
1790 self.SPlotSensitivity.changeCurveVisibility(2, [
True], [
True])
1793 @pyqtSignature(
"bool")
1805 formats = [
"*.s2p" ]
1806 fname = unicode(QFileDialog.getOpenFileName(self,
"%s - Open [S] Touchstone File" % applicationName, dir,
"Touchstone files (%s)" %
" ".join(formats)))
1815 @pyqtSignature(
"bool")
1823 QMessageBox.warning(self,
"WARNING",
'There is an open Parameter Edit Window. Close it before openning a new one.')
1838 @pyqtSignature(
"bool")
1846 QMessageBox.warning(self,
"WARNING",
'No result to store. Open a parameter file and run synthesis first.')
1849 if self.
CP is None or self.
CM is None or self.
SP is None or self.
FT is None:
1850 QMessageBox.warning(self,
"WARNING",
'No result to store. Run synthesis first.')
1854 if self.
paramEdit is not None and self.paramEdit.dialogModified
is True and self.paramEdit.recomputed
is False:
1855 message =
"Parameters have been modified and it is necessary to recompute\nRecompute synthesis?"
1856 reply = QMessageBox.question(self,
"%s - Recompute" % applicationName, message, QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel)
1857 if reply
in [QMessageBox.Cancel, QMessageBox.No]:
1859 elif reply == QMessageBox.Yes:
1860 self.paramEdit.on_compute_pushButton_clicked(
True)
1865 @pyqtSignature(
"bool")
1871 if self.results_comboBox.count() == 0:
1872 QMessageBox.warning(self,
"WARNING",
'Results list is empty' )
1875 index = self.results_comboBox.currentIndex()
1876 name = str(self.results_comboBox.currentText())
1880 message =
"Are you sure you what to remove result '%s' from list?\nRemove?" % name
1881 reply = QMessageBox.question(self,
"%s - Remove result" % applicationName, message, QMessageBox.Yes | QMessageBox.No)
1883 if reply == QMessageBox.Yes:
1884 self.results_comboBox.removeItem(index)
1886 myPrint(
"Result '%s' removed from list" % name)
1888 if self.results_comboBox.count() > 0:
1892 self.
indexResults = self.results_comboBox.currentIndex()
1895 @pyqtSignature(
"int")
1908 index = self.results_comboBox.currentIndex()
1909 name = str(self.results_comboBox.currentText())
1913 if not all([result[0], result[1], result[2], result[4] ]):
1914 QMessageBox.warning(self,
"WARNING",
"""Result '%s' was read from [S] parameters Touchstone file and has no Characteristic Polynomials nor Coupling Matrices.<p>
1915 It cannot be loaded.""" % name)
1918 self.results_comboBox.setCurrentIndex(self.
indexResults)
1924 QMessageBox.warning(self,
"WARNING",
'User cancelled action.<p>Result has not been loaded from list.' )
1927 self.results_comboBox.setCurrentIndex(self.
indexResults)
1936 (self.
P, self.
CP, self.
CM, self.
SP, self.
FT) = copy.deepcopy( result )
1941 myPrint(
"Result '%s' loaded from list" % name)
1943 @pyqtSignature(
"bool")
1954 QMessageBox.warning(self,
"WARNING",
'Results list is empty. Nothing to plot.')
1955 self.action_Compare.setChecked(
False)
1959 myPrint(
'Displayed results comparison:')
1962 freq = [ result[3].freq / 1e9
for result
in self.
listResults ]
1963 dataS11 = [ 20*np.log10(np.abs(result[3].S11))
for result
in self.
listResults ]
1964 dataS21 = [ 20*np.log10(np.abs(result[3].S21))
for result
in self.
listResults ]
1966 freqGD = [ result[3].freq2 / 1e9
for result
in self.
listResults ]
1967 dataGD = [ 1e9 * result[3].groupDelay2
for result
in self.
listResults ]
1969 phaseS11 = [ result[3].phaseS11 * 180/np.pi
for result
in self.
listResults ]
1970 phaseS21 = [ result[3].phaseS21 * 180/np.pi
for result
in self.
listResults ]
1972 resultNamesMag = [ unicode(self.results_comboBox.itemText(n) +
' (dB)')
for n
in range(self.results_comboBox.count()) ]
1973 resultNamesPhase = [ unicode(self.results_comboBox.itemText(n) +
' (phase)')
for n
in range(self.results_comboBox.count()) ]
1974 resultNamesGD = [ unicode(self.results_comboBox.itemText(n) +
' (GD)')
for n
in range(self.results_comboBox.count()) ]
1975 rightYVisible = [
False for n
in range(self.results_comboBox.count())]
1979 for S21
in dataS21: dynamicRange = max(dynamicRange , -20*log10( min([ abs(S21[0]), abs(S21[-1] )])) )
1980 dynamicRange = 10*ceil(dynamicRange/10)
1983 windowTitle =
'[S] comparison',
1985 title =
'S<sub>11</sub> compared for different results',
1986 XData = freq, leftYData = dataS11,
1987 rightYData = phaseS11,
1988 rightYLabel =
'Phase(S<sub>11</sub>) (deg)' , rightYNames = resultNamesPhase, rightYVisible = rightYVisible,
1989 leftYmax = 0, leftYmin = -dynamicRange, leftYNames = resultNamesMag, XLabel =
'Frequency (GHz)', leftYLabel =
'dB',
1990 Xunits =
'GHz', leftYunits =
'dB', rightYunits =
'deg' )
1992 self.SPlotCompare.addTab(tabTitle =
'S21',
1993 title =
'S<sub>21</sub> compared for different results',
1994 XData = freq, leftYData = dataS21,
1995 rightYData = phaseS21,
1996 rightYLabel =
'Phase(S<sub>21</sub>) (deg)' , rightYNames = resultNamesPhase, rightYVisible = rightYVisible,
1997 leftYmax = 0, leftYmin = -dynamicRange, leftYNames = resultNamesMag,
1998 XLabel =
'Frequency (GHz)', leftYLabel =
'dB',
1999 Xunits =
'GHz', leftYunits =
'dB', rightYunits =
'deg' )
2001 self.SPlotCompare.addTab(tabTitle =
'Group delay',
2002 title =
'Group delay compared for different results',
2003 XData = freqGD, leftYData = dataGD,
2004 leftYNames = resultNamesGD, XLabel =
'Frequency (GHz)', leftYLabel =
'Group delay (ns.)',
2005 Xunits =
'GHz', leftYunits =
'ns' )
2030 super(HelpForm, self).
__init__(parent)
2031 self.setAttribute(Qt.WA_DeleteOnClose)
2032 self.setAttribute(Qt.WA_GroupLeader)
2042 backAction = self.mainWindow.action_Back
2043 homeAction = self.mainWindow.action_Home
2045 backAction.setShortcut(QKeySequence.Back)
2046 homeAction.setShortcut(self.tr(
"Home"))
2049 toolBar = QToolBar()
2050 toolBar.addAction(backAction)
2051 toolBar.addAction(homeAction)
2055 layout = QVBoxLayout()
2056 layout.addWidget(toolBar)
2058 self.setLayout(layout)
2060 self.connect(backAction, SIGNAL(
"triggered()"), self.
textBrowser, SLOT(
"backward()"))
2061 self.connect(homeAction, SIGNAL(
"triggered()"), self.
textBrowser, SLOT(
"home()"))
2064 self.textBrowser.setSearchPaths([
":/help/Help"])
2065 self.textBrowser.setSource(QUrl(page))
2066 self.resize(1024, 700)
2067 self.setWindowTitle(self.tr(
"%1 Help").arg(QApplication.applicationName()))
2070 def updatePageTitle(self):
2071 self.pageLabel.setText(self.textBrowser.documentTitle())
2090 def __init__(self, item, topolText, topolColors, parent=None):
2091 super(SetCouplingDlg, self).
__init__(parent)
2092 self.setAttribute(Qt.WA_DeleteOnClose)
2104 self.
typeLabels = [
'Uncoupled',
'Real',
'Real+',
'Real-',
'Imag+',
'Complex',
'Complex+',
'Complex-']
2114 self.
label = QLabel(
'Type of coupling:')
2120 self.comboBox.setCurrentIndex( self.comboBox.findText( entriesDict[ str(item.text()) ] ) )
2122 layout = QVBoxLayout(self)
2123 layout.addWidget(self.
label)
2126 self.setWindowTitle(
"Cross couplings")
2127 self.setToolTip(
"""Choose the type of cross coupling:
2128 The real part is a conventional (inductive or capacitive)
2129 coupling and the imaginary part a resistive coupling.
2130 The imag part will always be positive (passive circuit),
2131 while the real part can forced to positive, negative or
2142 row = self.mainWindow.topology_tableWidget.currentRow()
2143 col = self.mainWindow.topology_tableWidget.currentColumn()
2146 itemReciprocal = self.mainWindow.topology_tableWidget.item(col, row)
2147 for it
in [self.
item, itemReciprocal]:
2149 it.setBackground(QBrush(QColor(self.
topolColors[index])))
2169 super(MatrixEditDlg, self).
__init__(parent)
2185 self.
bkpMatQ = self.mainWindow.CM.bkpMatQ
2189 self.
bkpActions = self.mainWindow.CM.bkpActions
2192 assert self.edit_listWidget.count() == 0
2193 self.edit_listWidget.insertItems(0, self.
bkpActions)
2204 self.rot_angle_lineEdit.setText(
'0')
2205 self.rot_angle_lineEdit.setValidator( QRegExpValidator( QRegExp(stComplex), self) )
2208 self.Q_doubleSpinBox.setValue( np.mean(np.abs(self.mainWindow.CM.MatQ.Q)) )
2211 self.flatnessQeff_lineEdit.setValidator( QRegExpValidator( reRealPositiveInf, self) )
2215 self.optim_comboBox.setCurrentIndex(optimMethod)
2216 self.optim_stackedWidget.setCurrentIndex(optimMethod)
2220 self.topology_tableWidget.setColumnCount(0)
2221 self.topology_tableWidget.setRowCount(0)
2223 self.topology_tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
2224 self.topology_tableWidget.setSelectionMode(QAbstractItemView.NoSelection)
2226 self.topology_tableWidget.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum))
2228 self.topology_tableWidget.setToolTip(
"""<b>Coupling matrix topology: </b>
2230 Define here the position of purely real, purely imaginary
2231 or complex non-diagonal coupling matrix entries.
2233 Diagonal entries corresponding to resonant nodes are always complex, with imaginary
2234 part determined by finite Q of resonators and real part a degree of freedom.
2236 Diagonal entries corresponding to non-resonant nodes are always purely imaginary negative.
2238 Real part of non-diagonal entries can be forced to be positive (R+ or C+)
2239 or negative (R- or C-), to have a electric or a magnetic coupling.
2241 Imaginary part of complex or purely imaginary non-diagonal entries is always positive
2242 to have a passive circuit.
2246 self.verticalLayout_13.addStretch()
2252 self.verticalLayout_12.setStretchFactor(self.edit_toolBox, 10)
2259 self.
topolText = [
'0',
'R', 'R+', 'R-', 'I+', 'C', 'C+', 'C-', '']
2263 self.
topolColors = [ Qt.white, Qt.blue, Qt.green, Qt.cyan, Qt.yellow, Qt.darkRed, Qt.red, Qt.magenta, Qt.black ]
2284 labels = self.mainWindow.rowIndices
2286 M = self.mainWindow.CM.MatQ.M
2289 table.setColumnCount(size)
2290 table.setRowCount(size)
2291 table.setHorizontalHeaderLabels( labels )
2292 table.setVerticalHeaderLabels( labels )
2296 eps = 10** -self.mainWindow.CM_prec.value()
2298 for m
in range(size):
2299 for n
in range(size):
2301 if np.abs(M[m, n].real) < eps:
2302 if np.abs(M[m, n].imag) < eps: type = 0
2305 if np.abs(M[m, n].imag) < eps:
2306 if M[m, n].real > 0: type = 2
2309 if M[m, n].real > 0: type = 6
2315 item = QTableWidgetItem(st)
2316 item.setTextAlignment(Qt.AlignHCenter|Qt.AlignVCenter)
2317 item.setBackground(brush)
2325 table.setItem(m, n, item)
2327 table.resizeRowsToContents()
2328 table.resizeColumnsToContents()
2329 table.setMaximumSize( table.maximumSizeHint() )
2343 Nrows = table.rowCount()
2344 Ncols = table.columnCount()
2345 assert Nrows == Ncols
2347 topologyReal = np.zeros( (Nrows,Ncols), dtype = bool)
2348 topologyImag = np.zeros( (Nrows,Ncols), dtype = bool)
2349 topologySignReal = np.zeros((Nrows,Ncols), dtype=
'int')
2350 topologySignImag = np.zeros((Nrows,Ncols), dtype=
'int')
2352 for m
in range(Nrows):
2353 for n
in range(Ncols):
2355 st = str(table.item(m, n).text())
2356 type = self.topolText.index(st)
2357 topologyReal[m, n] = type
in [1, 2, 3, 5, 6, 7]
2358 topologyImag[m, n] = type
in [4, 5, 6, 7]
2359 if topologyImag[m, n]: topologySignImag[m, n] = 1
2360 if type
in [2, 6]: topologySignReal[m, n] = 1
2361 elif type
in [3, 7]: topologySignReal[m, n] = -1
2362 elif type
in [1, 5]: topologySignReal[m, n] = 0
2363 else: topologySignReal[m, n] = 0
2365 return topologyReal, topologyImag, topologySignReal, topologySignImag
2372 row = self.topology_tableWidget.currentRow()
2373 col = self.topology_tableWidget.currentColumn()
2374 self.topology_tableWidget.setFocus(Qt.MouseFocusReason)
2378 couplingsDlg.exec_()
2387 (M, N) = self.mainWindow.CM.MatQ.M.shape
2389 ind = self.rot_pivotM_comboBox.currentIndex()
2390 self.rot_pivotM_comboBox.clear()
2391 self.rot_pivotM_comboBox.addItems(self.mainWindow.rowIndices)
2392 self.rot_pivotM_comboBox.setCurrentIndex(ind)
2394 ind = self.rot_pivotN_comboBox.currentIndex()
2395 self.rot_pivotN_comboBox.clear()
2396 self.rot_pivotN_comboBox.addItems(self.mainWindow.rowIndices)
2397 self.rot_pivotN_comboBox.setCurrentIndex(ind)
2399 ind = self.ann_pivotM_comboBox.currentIndex()
2400 self.ann_pivotM_comboBox.clear()
2401 self.ann_pivotM_comboBox.addItems(self.mainWindow.rowIndices)
2402 self.ann_pivotM_comboBox.setCurrentIndex(ind)
2404 ind = self.ann_pivotN_comboBox.currentIndex()
2405 self.ann_pivotN_comboBox.clear()
2406 self.ann_pivotN_comboBox.addItems(self.mainWindow.rowIndices)
2407 self.ann_pivotN_comboBox.setCurrentIndex(ind)
2409 ind = self.ann_elemM_comboBox.currentIndex()
2410 self.ann_elemM_comboBox.clear()
2411 self.ann_elemM_comboBox.addItems(self.mainWindow.rowIndices)
2412 self.ann_elemM_comboBox.setCurrentIndex(ind)
2414 ind = self.ann_elemN_comboBox.currentIndex()
2415 self.ann_elemN_comboBox.clear()
2416 self.ann_elemN_comboBox.addItems(self.mainWindow.rowIndices)
2417 self.ann_elemN_comboBox.setCurrentIndex(ind)
2419 ind = self.scale_node_comboBox.currentIndex()
2420 self.scale_node_comboBox.clear()
2421 self.scale_node_comboBox.addItems(self.mainWindow.rowIndices)
2422 self.scale_node_comboBox.setCurrentIndex(ind)
2435 if hasattr(self.sender(),
'validator'):
2436 validator = self.sender().validator()
2437 if validator
is not None:
2438 result = validator.validate(self.sender().text(), 0)[0]
2439 palette = self.sender().palette()
2441 palette.setColor(QPalette.Text, Qt.red)
2442 self.sender().setPalette(palette)
2443 self.badInput.append(self.sender())
2444 self.sender().setFocus(Qt.OtherFocusReason)
2446 palette.setColor(QPalette.Text, self.mainWindow.palette().text().color())
2447 self.sender().setPalette(palette)
2448 while self.sender()
in self.
badInput: self.badInput.remove(self.sender())
2454 self.apply_pushButton.setEnabled(
False)
2455 self.undo_pushButton.setEnabled(
False)
2457 self.apply_pushButton.setEnabled(
True)
2458 self.undo_pushButton.setEnabled(
True)
2460 @pyqtSignature(
"QListWidgetItem*")
2467 index = self.edit_listWidget.row(item)
2468 self.mainWindow.CM.MatQ = self.
bkpMatQ[index+1].
copy()
2469 self.mainWindow.loadMatrixQ(self.mainWindow.CM.MatQ)
2470 self.
lastEditAction =
"Matrix reverted to backup state: '%s'" % st
2471 self.mainWindow.pushEditAction()
2474 @pyqtSignature(
"bool")
2481 count = self.edit_listWidget.count()
2482 assert count == len( self.
bkpMatQ)-1
2485 QMessageBox.warning(self,
"WARNING",
"There are no edit actions to undo.")
2487 badMatQ = self.bkpMatQ.pop()
2490 self.mainWindow.CM.MatQ = MatQ
2491 self.mainWindow.loadMatrixQ(MatQ)
2492 item = self.edit_listWidget.takeItem(count-1)
2493 self.bkpActions.pop()
2494 myPrint(
"Undo: Matrix Edit action '%s'" % item.text())
2498 @pyqtSignature(
"bool")
2505 message =
"Do you really want to clear the action list for undo?"
2506 reply = QMessageBox.question(self,
"%s - Clear actions list" % applicationName, message, QMessageBox.Yes | QMessageBox.Cancel)
2507 if reply == QMessageBox.Cancel:
2510 self.mainWindow.CM.bkpMatQ = [ self.mainWindow.CM.MatQ.copy() ]
2511 self.mainWindow.CM.bkpActions = [ ]
2513 self.
bkpMatQ = self.mainWindow.CM.bkpMatQ
2514 self.
bkpActions = self.mainWindow.CM.bkpActions
2517 while self.edit_listWidget.count() > 0:
2518 item = self.edit_listWidget.takeItem(0)
2522 @pyqtSignature(
"bool")
2529 MatQ = self.mainWindow.CM.MatQ
2532 action = unicode(self.edit_toolBox.itemText(self.edit_toolBox.currentIndex()))
2533 if action ==
u'Rotate matrix':
2534 if self.rot_trigo_radioButton.isChecked(): rotationType =
'trigonometric'
2535 elif self.rot_hyper_radioButton.isChecked(): rotationType =
'hyperbolic'
2536 else:
raise synthError,
"No rotation type selected"
2537 i = self.rot_pivotM_comboBox.currentIndex()
2538 j = self.rot_pivotN_comboBox.currentIndex()
2539 rotAng = complex( str(self.rot_angle_lineEdit.text()).replace(
' ',
'').replace(
'i',
'j') ) *pi/180.0
2542 MatQ.rotateMatrix(rotationType, i, j, rotAng, flagQ=
True)
2544 self.
lastEditAction =
'%s matrix rotation with pivot (%s,%s) and angle %g %+gj deg' % (rotationType.title(), self.mainWindow.rowIndices[i], self.mainWindow.rowIndices[j], rotAng.real *180/pi, rotAng.imag*180/pi )
2546 elif action ==
'Annihilate element':
2547 if self.ann_trigo_radioButton.isChecked(): rotationType =
'trigonometric'
2548 elif self.ann_hyper_radioButton.isChecked(): rotationType =
'hyperbolic'
2549 else:
raise synthError,
"No rotation type selected"
2550 i = self.ann_pivotM_comboBox.currentIndex()
2551 j = self.ann_pivotN_comboBox.currentIndex()
2552 m = self.ann_elemM_comboBox.currentIndex()
2553 n = self.ann_elemN_comboBox.currentIndex()
2557 rotAng = MatQ.rotAngleEliminate(rotationType, i, j, m, n)
2558 MatQ.rotateMatrix(rotationType, i, j, rotAng, flagQ=
True)
2560 self.
lastEditAction =
'%s matrix rotation with pivot (%s,%s) and angle %g %+gj deg to annihilate element (%s,%s)' % (rotationType.title(), self.mainWindow.rowIndices[i], self.mainWindow.rowIndices[j], rotAng.real *180/pi, rotAng.imag*180/pi, self.mainWindow.rowIndices[m], self.mainWindow.rowIndices[n])
2562 elif action ==
'Add nodes':
2563 if self.add_source_radioButton.isChecked():
2566 elif self.add_load_radioButton.isChecked():
2569 elif self.add_both_radioButton.isChecked():
2572 else:
raise synthError,
"Add nodes: No new node position selected"
2573 MatQ.inflateMatrix(position)
2575 elif action ==
'Node scaling':
2576 factor = self.scale_factor_doubleSpinBox.value()
2577 node = self.scale_node_comboBox.currentIndex()
2578 MatQ.scaleNode(node, factor)
2579 self.
lastEditAction =
'Node [%s] scaled with factor %g' % (self.mainWindow.rowIndices[node], factor)
2581 elif action ==
'Prescribed flatness':
2582 Qeff = float(self.flatnessQeff_lineEdit.text())
2583 MatQ.addLossesQeff(Qeff)
2584 self.
lastEditAction =
'Prescribed flatness with Qeff = %g' % (Qeff)
2586 elif action ==
'Optimization':
2588 Q = self.Q_doubleSpinBox.value()
2589 topologyReal, topologyImag, topologySignReal, topologySignImag = self.
getTopologyFlags()
2591 algor = self.algor_comboBox.currentText()
2592 maxIter = self.maxIter_spinBox.value()
2593 Nsamples = self.Nsamples_spinBox.value()
2594 weights = [ self.wS11_doubleSpinBox.value(), self.wS22_doubleSpinBox.value(), self.wS21_doubleSpinBox.value(), self.wGD_doubleSpinBox.value() ]
2596 optimMethod = unicode(self.optim_comboBox.currentText())
2597 if optimMethod ==
u'Characteristic Polynomials':
2598 S11DR = self.S11DR_doubleSpinBox.value()
2599 S21DR = self.S21DR_doubleSpinBox.value()
2600 app.setOverrideCursor(Qt.WaitCursor)
2601 MatQ.uniformQ(self.mainWindow.mainWindow.P, self.mainWindow.mainWindow.CP, weights, Q, algor, maxIter, Nsamples, S11DR, S21DR, topologyReal, topologyImag, topologySignReal, topologySignImag)
2602 app.restoreOverrideCursor()
2603 self.
lastEditAction =
'Matrix optimization (CP) with parameters: alg=%s, maxIter=%d, Nsamples=%d, Q=%g, w=%s, N=%d, S11DR=%g, S21DR=%g' % (algor, maxIter, Nsamples, Q,
listStr(weights, 2), Nsamples, S11DR, S21DR)
2605 elif optimMethod ==
u'Specification mask':
2606 SM = self.mainWindow.mainWindow.SM
2609 reply = QMessageBox.question(self,
"WARNING",
'No specification mask loaded.<p>Do you want to open an specification mask file now?', QMessageBox.Yes| QMessageBox.Cancel)
2610 if reply == QMessageBox.Yes:
2611 self.mainWindow.mainWindow.on_action_Mask_triggered(
True)
2612 SM = self.mainWindow.mainWindow.SM
2615 app.setOverrideCursor(Qt.WaitCursor)
2616 MatQ.uniformQMask(self.mainWindow.mainWindow.P, self.mainWindow.mainWindow.CP, weights, Q, algor, maxIter, Nsamples, SM, topologyReal, topologyImag, topologySignReal, topologySignImag)
2617 app.restoreOverrideCursor()
2618 self.
lastEditAction =
'Matrix optimization (mask) with parameters: alg=%s, maxIter=%d, Nsamples=%d, Q=%g, w=%s, mask=%s' % (algor, maxIter, Nsamples, Q,
listStr(weights, 2), SM.fileName)
2620 myPrint(
'Matrix optimization (mask) cancelled by user')
2624 QMessageBox.warning(self,
"WARNING",
'Unknown optimization method: %s' % optimMethod)
2629 raise synthError,
"Unknown matrix edit action '%s'" % action
2632 self.mainWindow.loadMatrixQ(MatQ)
2633 self.mainWindow.pushEditAction()
2634 self.mainWindow.dirty =
True
2635 self.mainWindow.setWindowModified(self.mainWindow.dirty)
2637 except synthError, err:
2638 app.restoreOverrideCursor()
2639 QMessageBox.critical(self,
"ERROR",
'<p align="center">Matrix editor error:<br>%s</p>' % err )
2649 self.mainWindow.action_Edit.setChecked(
False)
2675 def __init__(self, roots_NRP, zerosArrang, parent=None):
2676 super(PredisZeorsDlg, self).
__init__(parent)
2684 layV = QVBoxLayout(self)
2685 title = QLabel(
"<b>Predistortion synthesis:</b>")
2686 title.setAlignment(Qt.AlignHCenter)
2687 layV.addWidget(title)
2688 layV.addWidget(QLabel(
"Select zeros of F(s)F(-s) in the"))
2689 layV.addWidget(QLabel(
"left s-plane that will go to F(s)"))
2691 layH1 = QHBoxLayout()
2692 grid = QGridLayout()
2694 for n
in range(self.mainWindow.P.N):
2695 grid.addWidget(QLabel(
complexStr(roots_NRP[n], 3)), n, 0, Qt.AlignRight)
2696 checkBox = QCheckBox()
2699 self.connect(checkBox, SIGNAL(
"stateChanged(int)"), partial(self.
setZeroToFs, n) )
2700 grid.addWidget(checkBox, n, 1, Qt.AlignHCenter)
2702 layH1.addLayout(grid)
2705 layV.addLayout(layH1)
2709 buttonBox = QDialogButtonBox(QDialogButtonBox.Ok)
2710 buttonBox.button(QDialogButtonBox.Ok).setDefault(
True)
2711 self.connect(buttonBox, SIGNAL(
"accepted()"), self, SLOT(
"accept()"))
2712 self.connect(buttonBox, SIGNAL(
"rejected()"), self, SLOT(
"reject()"))
2714 layV.addWidget(buttonBox)
2716 self.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
2717 self.setWindowTitle(
"Zeros F(s)")
2718 self.setToolTip(
"""Select predistiortion zeros of F(s)F(-s) in the left-hand s-plane that will go to F(s).
2719 If they are not selected, they will go to F(-s).
2720 The zeros of F(s)F(-s) in the right-hand s-plane will go to the opposite polynomial.""")
2722 def setZeroToFs(self, n, zeroToFs):
2783 self.
SP = self.mainWindow.CM.SP
2798 def runAnalysis(self, N, inout, freq, Q, inductive, capacitive, resistive):
2799 app.setOverrideCursor(Qt.WaitCursor)
2800 MatQ = self.mainWindow.CM.MatQ
2802 nFreq = len(self.SP.freq)
2804 self.
S11M, self.
S21M, self.
S22M = np.zeros((nFreq, N), dtype=np.complex128), np.zeros((nFreq, N), dtype=np.complex128), np.zeros((nFreq, N), dtype=np.complex128)
2805 self.
phaseS11M, self.
phaseS21M, self.
phaseS22M, self.
groupDelayM = np.zeros((nFreq, N)), np.zeros((nFreq, N)), np.zeros((nFreq, N)), np.zeros((nFreq2, N))
2807 maxModReal, maxModImag = np.zeros(MatQ.M.shape), np.zeros(MatQ.M.shape)
2808 maxModQn, maxModF0 = np.zeros(MatQ.Q.shape), np.zeros(MatQ.Q.shape)
2809 first = MatQ.extraNodesS
2810 last = MatQ.M.shape[0] - MatQ.extraNodesL
2812 f0n = MatQ.FT.unormFreq(np.diag(MatQ.M)[first:last].real)
2816 modMatQ = self.
randomVariations(MatQ, inout, inductive, capacitive, resistive, freq, Q )
2817 self.SP.fromCouplingMatrix(modMatQ)
2820 maxModReal = np.maximum(maxModReal, 100* np.abs(modMatQ.M.real / MatQ.M.real - 1) )
2821 maxModImag = np.maximum(maxModImag, 100* np.abs(modMatQ.M.imag / MatQ.M.imag - 1) )
2823 modF0n = MatQ.FT.unormFreq(np.diag(modMatQ.M)[first:last].real)
2824 maxModQn = np.maximum(maxModQn, 100*np.abs(modQn/Qn - 1) )
2825 maxModF0 = np.maximum(maxModF0, 100*np.abs(modF0n/f0n - 1) )
2827 self.
S11M[:, n], self.
S21M[:, n], self.
S22M[:, n], self.
groupDelayM[:, n] = self.SP.S11M, self.SP.S21M, self.SP.S22M, self.SP.groupDelayM
2832 maxModReal[np.isnan(maxModReal)] = 0
2833 maxModReal[np.isinf(maxModReal)] = 0
2834 maxModImag[np.isnan(maxModImag)] = 0
2835 maxModImag[np.isinf(maxModImag)] = 0
2837 rowIndices = self.mainWindow.rowIndices
2838 myPrint(
'\nSENSITIVITY ANALYSIS:')
2839 myPrint(
'Maximum variation achieved (%), Couplings Real part:')
2840 for m
in range(maxModReal.shape[0]):
2841 for n
in range(maxModReal.shape[1]):
2843 if maxModReal[m, n] > 0:
myPrint(
'(%3s,%3s): %6.3g%%' % (rowIndices[m], rowIndices[n], maxModReal[m, n]))
2845 myPrint(
'Maximum variation achieved (%), Couplings Imaginary part:')
2846 for m
in range(maxModImag.shape[0]):
2847 for n
in range(maxModImag.shape[1]):
2849 if maxModImag[m, n] > 0:
myPrint(
'(%3s,%3s): %6.3g%%' % (rowIndices[m], rowIndices[n], maxModImag[m, n]))
2851 myPrint(
'Maximum variation achieved (%), Resonators:')
2852 for m
in range(maxModQn.shape[0]):
2853 myPrint(
'R%d: fres %6.3g%%, Q %6.3g%%' % (m+1, maxModF0[m], maxModQn[m]) )
2855 app.restoreOverrideCursor()
2903 rand =
lambda x: 1 + (2*np.random.rand(1)[0]-1)*x/100
2907 eps = 10** -self.mainWindow.CM_prec.value()
2909 modMatQ = MatQ.copy()
2914 first = MatQ.extraNodesS
2915 last = N - MatQ.extraNodesL
2919 for n
in range(m+1, N):
2921 if m==0
or m==N-1
or n==0
or n==N-1:
2922 if abs(M[m, n]) > eps: varRe, varIm = inout, inout
2923 else: varRe, varIm = 0, 0
2925 if M[m, n].real > eps: varRe = inductive
2926 elif M[m, n].real < -eps: varRe = capacitive
2927 else: varRe, varIm = 0, 0
2929 if abs(M[m, n].imag) > eps: varIm = resistive
2932 M[m, n] = complex(M[m, n].real * rand(varRe), M[m, n].imag * rand(varIm))
2935 for n
in range(first, last):
2937 Qn = MatQ.Q[n-first]
2938 modQn = Qn * rand(Qvar)
2939 losses = M[:,n].imag.sum()
2940 modLosses = -1/(FBW * modQn)
2941 imDiag = MatQ.M[n, n].imag + modLosses - losses
2944 f0n = MatQ.FT.unormFreq(M[n, n].real)
2945 modf0n = f0n * rand(f0var)
2946 reDiag = MatQ.FT.normFreq(modf0n)
2948 M[n, n] = complex(reDiag, imDiag)
2950 modMatQ.Qresonators()
2961 SPlotSensitivity = self.mainWindow.mainWindow.SPlotSensitivity
2963 if SPlotSensitivity
is None or SPlotSensitivity.closed
is True:
2966 dynamicRange = -20*log10( min(np.concatenate( (abs(self.
S21M[0, :]), abs(self.
S21M[-1, :] )) )) )
2967 dynamicRange = 10*ceil(dynamicRange/10)
2970 windowTitle =
'Sensitivity analysis results',
2971 tabTitle =
'[S] + Group delay',
2972 title =
'[S] parameters (from Characteristic Polynomials)',
2973 XData = self.SP.freq / 1e9,
2974 leftYData = [20*np.log10(np.abs(self.
S11M)), 20*np.log10(np.abs(self.
S21M)), 20*np.log10(np.abs(self.
S22M))],
2975 rightXData = self.SP.freq2 / 1e9,
2977 leftYmin = -dynamicRange,
2979 leftYNames = [
'S<sub>11</sub>',
'S<sub>21</sub>',
'S<sub>22</sub>'],
2980 leftYVisible = [
True,
True,
False],
2981 XLabel =
'Frequency (GHz)',
2983 Xunits =
'GHz', leftYunits =
'dB', rightYunits =
'ns',
2984 rightYLabel =
'Time (ns.)' ,
2985 rightYNames = [
'Group delay'],
2986 rightYVisible = [
True]
2988 SPlotSensitivity.addTab( tabTitle =
'[S] + Phase',
2989 title =
'[S] parameters (from Characteristic Polynomials)',
2990 XData = self.SP.freq / 1e9,
2991 leftYData = [20*np.log10(np.abs(self.
S11M)), 20*np.log10(np.abs(self.
S21M)), 20*np.log10(np.abs(self.
S22M)) ],
2993 leftYmin = -dynamicRange,
2995 leftYNames = [
'S<sub>11</sub>',
'S<sub>21</sub>',
'S<sub>22</sub>'],
2996 leftYVisible = [
True,
True,
False],
2997 XLabel =
'Frequency (GHz)',
2999 Xunits =
'GHz', leftYunits =
'dB', rightYunits =
'deg',
3000 rightYLabel =
'degrees' ,
3001 rightYNames = [
'Phase(S<sub>21</sub>)',
'Phase(S<sub>11</sub>)',
'Phase(S<sub>22</sub>)'],
3002 rightYVisible = [
True,
False,
False]
3004 SPlotSensitivity.addTab( tabTitle =
'Group delay + Phase',
3005 title =
'[S] parameters (from Characteristic Polynomials)',
3006 XData = self.SP.freq2 / 1e9,
3008 rightXData = self.SP.freq / 1e9,
3009 rightYData = [ self.
phaseS21M * 180/np.pi ],
3010 leftYNames = [
'Group delay'],
3011 XLabel =
'Frequency (GHz)',
3012 leftYLabel =
'Time (ns.)',
3013 Xunits =
'GHz', leftYunits =
'ns', rightYunits =
'deg',
3014 rightYLabel =
'degrees' ,
3015 rightYNames = [
'Phase(S<sub>21</sub>)'],
3016 rightYVisible = [
True]
3019 self.mainWindow.mainWindow.SPlotSensitivity = SPlotSensitivity
3022 SPlotSensitivity.update(0, self.SP.freq / 1e9, [20*np.log10(np.abs(self.
S11M)), 20*np.log10(np.abs(self.
S21M)), 20*np.log10(np.abs(self.
S22M))],
3023 rightXData = self.SP.freq2 / 1e9, rightYData=[ 1e9 * self.
groupDelayM], autoScaleBottomX = self.mainWindow.mainWindow.autoScaleFreq )
3025 SPlotSensitivity.update(1, self.SP.freq / 1e9, [20*np.log10(np.abs(self.
S11M)), 20*np.log10(np.abs(self.
S21M)), 20*np.log10(np.abs(self.
S22M))],
3026 rightYData=[ self.
phaseS21M * 180/np.pi, self.
phaseS11M * 180/np.pi, self.
phaseS22M * 180/np.pi], autoScaleBottomX = self.mainWindow.mainWindow.autoScaleFreq )
3028 SPlotSensitivity.update(2, self.SP.freq2 / 1e9, [1e9 * self.
groupDelayM], rightXData = self.SP.freq / 1e9, rightYData=[ self.
phaseS21M * 180/np.pi ], autoScaleBottomX = self.mainWindow.mainWindow.autoScaleFreq )
3030 self.mainWindow.mainWindow.autoScaleFreq =
False
3033 if self.mainWindow.mainWindow.SM
is not None:
3034 SPlotSensitivity.deleteMasks()
3035 self.mainWindow.mainWindow.plotMasks()
3057 super(CouplingMatrixDlg, self).
__init__(parent)
3058 self.setAttribute(Qt.WA_DeleteOnClose)
3081 self.setWindowModified(self.
dirty)
3095 self.CM_comboBox.setObjectName(
"CM_comboBox")
3096 self.CM_comboBox.setToolTip(
"Select matrix from list")
3097 self.CM_comboBox.setStatusTip(
"Select matrix from list")
3099 self.toolBar_2.insertWidget(self.action_ListRemove, self.
CM_comboBox)
3103 self.tabWidget.addTab(tabLPQ,
"Low-pass matrix and Q")
3107 self.horizontalLayout_3.addStretch()
3119 self.horizontalLayout_4.addWidget(self.
CM_name)
3120 self.horizontalLayout_4.addStretch()
3124 self.CM_prec.setRange(3, 14)
3126 prec = self.mainWindow.CM.matrixElementsEps(
'Display Coupling Matrix')
3128 self.CM_prec.setValue(4)
3130 self.connect(self.
CM_prec, SIGNAL(
"valueChanged(int)"),
lambda x: self.
loadMatrixQ(CM.MatQ) )
3131 self.horizontalLayout_4.addWidget(self.
CM_prec)
3136 self.
CM_tooltip =
"To manually edit coupling matrix elements,\nfirst open matrix editor by clicking the toolbar button."
3137 self.CM_tableWidget.setToolTip(QApplication.translate(
"CouplingMatrixDlg", self.
CM_tooltip,
None, QApplication.UnicodeUTF8))
3142 self.horizontalLayout_2.addStretch()
3144 self.
Q_tooltip =
"To manually edit Q vector elements,\nfirst open matrix editor by clicking the toolbar button."
3145 self.Q_tableWidget.setToolTip(QApplication.translate(
"CouplingMatrixDlg", self.
Q_tooltip,
None, QApplication.UnicodeUTF8))
3151 self.Q_prec.setRange(3, 14)
3152 self.Q_prec.setValue(5)
3153 self.connect(self.
Q_prec, SIGNAL(
"valueChanged(int)"),
lambda x: self.
loadMatrixQ(CM.MatQ) )
3154 self.Qprec_Layout.addWidget(self.
Q_prec)
3156 self.horizontalLayout_2.addStretch()
3159 self.verticalLayout_CM.addStretch()
3163 self.horizontalLayout_3.addStretch(1)
3169 self.tabWidget.addTab(tabBP,
"Coupling bandwidth matrix (MHz)")
3173 self.horizontalLayout_3bp.addStretch()
3185 self.horizontalLayout_4bp.addWidget(self.
CMbp_name)
3186 self.horizontalLayout_4bp.addStretch()
3190 self.CMbp_prec.setRange(3, 14)
3191 self.CMbp_prec.setValue(5)
3192 self.connect(self.
CMbp_prec, SIGNAL(
"valueChanged(int)"),
lambda x: self.
loadMatrixQ(CM.MatQ) )
3193 self.horizontalLayout_4bp.addWidget(self.
CMbp_prec)
3198 self.
CMbp_tooltip =
"To manually edit coupling matrix elements,\nfirst open matrix editor by clicking the toolbar button."
3199 self.CMbp_tableWidget.setToolTip(QApplication.translate(
"CouplingMatrixDlg", self.
CMbp_tooltip,
None, QApplication.UnicodeUTF8))
3207 self.verticalLayout_CMbp.addStretch()
3211 self.horizontalLayout_3bp.addStretch(1)
3216 self.CM_name.setReadOnly(
True)
3219 self.CM_name.setFrame(
False)
3220 font = self.CM_name.font()
3222 self.CM_name.setFont(font)
3223 palette = self.CM_name.palette()
3224 palette.setColor(QPalette.Base, self.palette().window().color())
3225 self.CM_name.setPalette(palette)
3228 self.CMbp_name.setFont(font)
3230 self.CM_tableWidget.setColumnCount(0)
3231 self.CM_tableWidget.setRowCount(0)
3232 self.Q_tableWidget.setColumnCount(0)
3233 self.Q_tableWidget.setRowCount(0)
3234 self.CMbp_tableWidget.setColumnCount(0)
3235 self.CMbp_tableWidget.setRowCount(0)
3237 self.CM_tableWidget.setSelectionMode(QAbstractItemView.NoSelection)
3238 self.Q_tableWidget.setSelectionMode(QAbstractItemView.NoSelection)
3239 self.CMbp_tableWidget.setSelectionMode(QAbstractItemView.NoSelection)
3242 self.CM_tableWidget.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum))
3243 self.Q_tableWidget.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum))
3244 self.CMbp_tableWidget.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum))
3262 for MatQ
in CM.listM:
3263 self.CM_comboBox.addItem(MatQ.name)
3266 self.CM_comboBox.setCurrentIndex(self.CM.indexCM)
3269 self.CM_tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
3270 self.Q_tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
3271 self.CMbp_tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
3276 self.setWindowModified(
False)
3283 self.connect(self.
CM_prec, SIGNAL(
"valueChanged(int)"), self.matrixEditDlg.udpateTopology)
3300 self.mainWindow.CMdialog =
None
3303 if self.mainWindow.SPlotError
is not None and not self.mainWindow.SPlotError.closed:
3304 self.mainWindow.SPlotError.close()
3305 self.mainWindow.SPlotError =
None
3308 if self.mainWindow.EnergyPlot
is not None and not self.mainWindow.EnergyPlot.closed:
3309 self.mainWindow.EnergyPlot.close()
3310 self.mainWindow.EnergyPlot =
None
3313 if self.mainWindow.SPlotSensitivity
is not None and not self.mainWindow.SPlotSensitivity.closed:
3314 self.mainWindow.SPlotSensitivity.close()
3315 self.mainWindow.SPlotSensitivity =
None
3337 self.CM_name.setText(MatQ.name)
3338 self.CMbp_name.setText(MatQ.name)
3345 first = MatQ.extraNodesS
3346 last = size - MatQ.extraNodesL
3349 table.setColumnCount(size)
3350 table.setRowCount(size)
3354 for n
in range(1, first ): labels.append(
'NR' + str(n))
3355 labels.extend( [
'R'+str(elem) for elem in range(1, last-first+1) ] )
3356 for n
in range(first, first+MatQ.extraNodesL-1 ): labels.append(
'NR' + str(n))
3358 table.setHorizontalHeaderLabels( labels )
3359 table.setVerticalHeaderLabels( labels )
3361 MatQ.rowIndices = labels
3363 for m
in range(size):
3364 for n
in range(size):
3365 item = QTableWidgetItem(
complexStr(M[m, n], self.CM_prec.value()) )
3366 item.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
3367 table.setItem(m, n, item)
3369 table.resizeRowsToContents()
3370 table.resizeColumnsToContents()
3371 table.setMaximumSize( table.maximumSizeHint() )
3379 table.setColumnCount(size)
3380 table.setRowCount(size)
3383 table.setHorizontalHeaderLabels( labels )
3384 table.setVerticalHeaderLabels( labels )
3386 for m
in range(size):
3387 for n
in range(size):
3388 item = QTableWidgetItem(
complexStr(Mcbw[m, n], self.CMbp_prec.value()) )
3389 item.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
3390 table.setItem(m, n, item)
3392 table.resizeRowsToContents()
3393 table.resizeColumnsToContents()
3394 table.setMaximumSize( table.maximumSizeHint() )
3399 self.matrixEditDlg.setMatrixSize()
3400 self.matrixEditDlg.udpateTopology()
3401 self.matrixEditDlg.Q_doubleSpinBox.setValue( np.mean(np.abs(MatQ.Q)) )
3410 table.setColumnCount(N)
3411 table.setRowCount(1)
3412 table.setHorizontalHeaderLabels( [ str(elem)
for elem
in range(1, N+1) ])
3413 table.setVerticalHeaderLabels( [
'Q' ] )
3416 item = QTableWidgetItem(
'%.*g' % (self.Q_prec.value(), Q[n]) )
3417 item.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
3418 table.setItem(0, n, item)
3420 table.resizeRowsToContents()
3421 table.resizeColumnsToContents()
3422 table.setMaximumSize( table.maximumSizeHint() )
3425 if self.mainWindow.SPlotError
is not None and (self.mainWindow.SPlotError.closed
is False):
3429 if self.mainWindow.EnergyPlot
is not None and (self.mainWindow.EnergyPlot.closed
is False):
3441 message =
"Coupling Matrix has been modified, but not saved to list\nSave?"
3442 reply = QMessageBox.question(self,
"%s - Unsaved Changes" % applicationName, message, QMessageBox.Yes | QMessageBox.No| QMessageBox.Cancel)
3443 if reply == QMessageBox.Cancel:
3445 elif reply == QMessageBox.Yes:
3458 if self.action_Edit.isChecked()
is False:
return
3461 item = table.currentItem()
3462 if item
is None:
return
3468 itemOld = table.item(mold, nold)
3469 stOld =
complexStr(self.CM.MatQ.M[mold, nold], self.CM_prec.value())
3470 if itemOld
is not None: itemOld.setText(stOld)
3474 table.resizeRowsToContents()
3475 table.resizeColumnsToContents()
3476 table.setMaximumSize( table.maximumSizeHint() )
3484 if self.action_Edit.isChecked()
is False:
return
3487 item = table.currentItem()
3488 if item
is None:
return
3501 table.resizeRowsToContents()
3502 table.resizeColumnsToContents()
3503 table.setMaximumSize( table.maximumSizeHint() )
3514 if self.sender()
is self.
CM_name:
3515 st = unicode(self.CM_name.text())
3519 self.matrixEditDlg.lastEditAction =
'Matrix name changed to: %s' % st
3524 self.setWindowModified(self.
dirty)
3543 row = self.CM_tableWidget.currentRow()
3544 col = self.CM_tableWidget.currentColumn()
3547 if row>=0
and col>=0:
3548 st = str(item.text().trimmed())
3551 if st.find(
'i') != -1:
3552 st = st.replace(
'i',
'j')
3560 except ValueError, err:
3561 QMessageBox.critical(self,
"ERROR",
'<p align="center">Incorrect value error. String:<br>%s<br>is not a correct complex number representation.</p>' % (st))
3579 self.matrixEditDlg.lastEditAction =
'CM Matrix entry edited: (%d,%d) = %s' % (row, col, st)
3582 itemSym = QTableWidgetItem(st)
3583 itemSym.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
3585 self.CM_tableWidget.setItem(col, row, itemSym)
3587 self.matrixEditDlg.lastEditAction =
'CM Matrix entry edited: (%d,%d) and (%d,%d) = %s' % (row, col, col, row, st)
3591 self.CM.MatQ.lp2bp2cbw()
3592 item = QTableWidgetItem(
complexStr(self.CM.MatQ.Mcbw[row, col], self.CMbp_prec.value()) )
3593 item.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
3594 self.CMbp_tableWidget.setItem(row, col, item)
3596 itemSym = QTableWidgetItem(
complexStr(self.CM.MatQ.Mcbw[col, row], self.CMbp_prec.value()) )
3597 itemSym.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
3598 self.CMbp_tableWidget.setItem(col, row, itemSym)
3623 row = self.Q_tableWidget.currentRow()
3624 col = self.Q_tableWidget.currentColumn()
3629 if row>=0
and col>=0:
3630 st = str(item.text().trimmed())
3634 except ValueError, err:
3635 QMessageBox.critical(self,
"ERROR",
'<p align="center">Incorrect value error. String:<br>%s<br>is not a correct real number representation.</p>' % (st))
3639 item.setText(
'%.5g' % Q[col])
3647 self.matrixEditDlg.lastEditAction =
'Q vector entry edited: (%d) = %s' % (col, st)
3650 colM = col + MatQ.extraNodesS
3651 losses = -1 / (value * MatQ.FT.FBW)
3652 sumImagColNoDiag = M[:, colM].imag.sum() - M[colM, colM].imag
3653 imDiag = losses - sumImagColNoDiag
3655 M[colM, colM] = complex(M[colM, colM] .real, imDiag)
3656 itemM = QTableWidgetItem(
complexStr(M[colM, colM], 4 ))
3657 itemM.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
3659 self.CM_tableWidget.setItem(colM, colM, itemM)
3664 @pyqtSignature(
"bool")
3671 inout = self.inout_doubleSpinBox.value()
3672 inductive = self.inductive_doubleSpinBox.value()
3673 capacitive = self.capacitive_doubleSpinBox.value()
3674 resistive = self.resistive_doubleSpinBox.value()
3675 freq = self.freq_doubleSpinBox.value()
3676 Q = self.Q_doubleSpinBox.value()
3677 N = self.N_spinBox.value()
3678 self.SA.runAnalysis(N, inout, freq, Q, inductive, capacitive, resistive)
3681 @pyqtSignature(
"bool")
3689 self.CM_tableWidget.setEditTriggers(QAbstractItemView.AnyKeyPressed | QAbstractItemView.DoubleClicked | QAbstractItemView.EditKeyPressed)
3690 self.CM_tableWidget.setSelectionMode(QAbstractItemView.SingleSelection)
3691 self.CM_tableWidget.setToolTip(
"")
3692 self.Q_tableWidget.setEditTriggers(QAbstractItemView.AnyKeyPressed | QAbstractItemView.DoubleClicked | QAbstractItemView.EditKeyPressed)
3693 self.Q_tableWidget.setSelectionMode(QAbstractItemView.SingleSelection)
3694 self.Q_tableWidget.setToolTip(
"")
3695 self.CM_name.setReadOnly(
False)
3696 self.CM_name.deselect()
3699 self.CM_name.setFrame(
True)
3700 font = self.CM_name.font()
3702 self.CM_name.setFont(font)
3703 palette = self.CM_name.palette()
3704 palette.setColor(QPalette.Base, self.palette().base().color())
3705 self.CM_name.setPalette(palette)
3709 self.matrixEditDlg.show()
3711 self.CM_tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
3712 self.CM_tableWidget.setSelectionMode(QAbstractItemView.NoSelection)
3713 self.CM_tableWidget.setToolTip(QApplication.translate(
"CouplingMatrixDlg", self.
CM_tooltip,
None, QApplication.UnicodeUTF8))
3714 self.Q_tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
3715 self.Q_tableWidget.setSelectionMode(QAbstractItemView.NoSelection)
3716 self.Q_tableWidget.setToolTip(QApplication.translate(
"CouplingMatrixDlg", self.
Q_tooltip,
None, QApplication.UnicodeUTF8))
3717 self.CM_name.setReadOnly(
True)
3718 self.CM_name.deselect()
3721 self.CM_name.setFrame(
False)
3722 font = self.CM_name.font()
3724 self.CM_name.setFont(font)
3725 palette = self.CM_name.palette()
3726 palette.setColor(QPalette.Base, self.palette().window().color())
3727 self.CM_name.setPalette(palette)
3729 self.matrixEditDlg.close()
3735 @pyqtSignature(
"bool")
3748 @pyqtSignature(
"bool")
3759 dir = self.mainWindow.P.outDir
3762 formats = [
"*.cm",
"*.tcm",
"*.fcm",
"*.fcm_uniQ",
"*.pfi",
"*.ina",
"*.ins",
"*.arrow",
"*.cds",
"*.triplet",
"*.cqs" ]
3763 fileName = unicode(QFileDialog.getOpenFileName(self,
"%s - Open Coupling Matrix File" % applicationName, dir,
"Coupling matrices files (%s)" %
" ".join(formats)))
3768 self.CM.MatQ = self.CM.readCouplingMatrix(fileName)
3769 except parseError, err:
3770 QMessageBox.critical(self,
"ERROR",
'<p align="center">Error reading coupling matrix file:<br>%s</p>' % err)
3773 self.matrixEditDlg.lastEditAction =
"Matrix '%s' read from disk file '%s'" % (self.CM.MatQ.name, os.path.basename(fileName) )
3777 @pyqtSignature(
"bool")
3783 self.CM.saveCouplingMatrices(self.mainWindow.P, self.mainWindow.SP, saveSignificantDigits, saveSignificantDigitsEnergy)
3786 @pyqtSignature(
"bool")
3793 formats = [
"*.cm",
"*.tcm",
"*.fcm",
"*.fcm_uniQ",
"*.pfi",
"*.ina",
"*.ins",
"*.arrow",
"*.cds",
"*.triplet",
"*.cqs" ]
3794 dir = self.mainWindow.P.outDir
3795 fileName = unicode(QFileDialog.getSaveFileName(self,
"%s - Save Coupling Matrix File" % applicationName, dir,
"Coupling matrices files (%s)" %
" ".join(formats)))
3799 fileBaseName = os.path.basename(fileName)
3800 if "." not in fileBaseName:
3804 self.CM.MatQ.saveMat(fileName, self.mainWindow.P, self.mainWindow.SP, saveSignificantDigits, saveSignificantDigitsEnergy)
3805 myPrint(
"Coupling Matrix saved to file: %s" % fileName)
3808 @pyqtSignature(
"bool")
3818 index = self.CM_comboBox.findText(name, Qt.MatchExactly)
3821 message =
"Matrix with same name already exists in list\nReplace?"
3822 reply = QMessageBox.question(self,
"%s - Matrix exists" % applicationName, message, QMessageBox.Yes | QMessageBox.No)
3823 if reply == QMessageBox.No:
3825 elif reply == QMessageBox.Yes:
3826 self.CM.listM[index] = MatQ.copy()
3827 myPrint(
"Coupling matrix '%s' replaced in list" % name)
3829 self.matrixEditDlg.lastEditAction =
"Matrix '%s' replaced in list" % name
3832 self.CM.listM.append(MatQ.copy())
3833 self.CM_comboBox.addItem(name)
3834 index = self.CM_comboBox.count() - 1
3835 self.CM.indexCM = index
3836 myPrint(
"Coupling matrix '%s' appended to list" % name)
3838 self.matrixEditDlg.lastEditAction =
"Matrix '%s' appended to list" % name
3842 self.setWindowModified(self.
dirty)
3844 if programmed
is False:
3847 self.CM_comboBox.setCurrentIndex(index)
3851 @pyqtSignature(
"bool")
3857 if self.CM_comboBox.count() == 0:
3858 QMessageBox.warning(self,
"WARNING",
'Coupling matrices list is empty' )
3861 index = self.CM_comboBox.currentIndex()
3862 name = str(self.CM_comboBox.currentText())
3864 message =
"Are you sure you what to remove matrix '%s' from list?\nRemove?" % name
3865 reply = QMessageBox.question(self,
"%s - Remove matrix" % applicationName, message, QMessageBox.Yes | QMessageBox.No)
3867 if reply == QMessageBox.Yes:
3869 self.CM_comboBox.removeItem(index)
3870 del self.CM.listM[index]
3872 myPrint(
"Coupling matrix '%s' removed from list" % name)
3874 if self.CM_comboBox.count() > 0:
3877 self.CM.indexCM = self.CM_comboBox.currentIndex()
3880 @pyqtSignature(
"bool")
3886 SP = self.mainWindow.SP
3887 SP.energyPowerFromCM(self.CM.MatQ)
3888 Nr = np.size(SP.energyRes,1)
3891 energyCurvesList, energyRevCurvesList, powerCurvesList, powerRevCurvesList, resonatorNames = [], [], [], [], []
3893 energyCurvesList.append(1e9 * SP.energyRes[:, n])
3894 energyRevCurvesList.append(1e9 * SP.energyResRev[:, n])
3895 powerCurvesList.append(SP.powerRes[:, n])
3896 powerRevCurvesList.append(SP.powerResRev[:, n])
3897 resonatorNames.append(
'Resonator %d' % (n+1) )
3899 totalEnergyRes = 1e9 * SP.energyRes.sum(axis=1)
3900 totalEnergyResRev = 1e9 * SP.energyResRev.sum(axis=1)
3901 totalPowerRes = SP.powerRes.sum(axis=1)
3902 totalPowerResRev = SP.powerResRev.sum(axis=1)
3903 energyCurvesList.append(totalEnergyRes)
3904 energyRevCurvesList.append(totalEnergyResRev)
3905 powerCurvesList.append(totalPowerRes)
3906 powerRevCurvesList.append(totalPowerResRev)
3907 resonatorNames.append(
'Total')
3910 eps = 10** -self.CM_prec.value()
3912 powerCoupCurves, powerCoupRevCurves = [], []
3914 powerCoupTotal = np.zeros(SP.freq.shape)
3915 powerCoupRevTotal = 0
3916 for coup
in SP.powerCoup:
3917 if np.abs(coup[1]) < eps:
continue
3919 powerCoupTotal += coup[2]
3920 powerCoupRevTotal += coup[3]
3921 powerCoupCurves.append(coup[2])
3922 powerCoupRevCurves.append(coup[3])
3925 powerCoupCurves.append(powerCoupTotal)
3926 powerCoupRevCurves.append(powerCoupRevTotal)
3927 powerCoupNames.append(
'Total')
3943 if self.mainWindow.EnergyPlot
is None or self.mainWindow.EnergyPlot.closed:
3946 windowTitle =
'Stored Energy and dissipated power',
3947 tabTitle =
'Energy',
3948 title =
'Stored energy in the resonators computed from CM',
3949 XData = SP.freq / 1e9,
3950 leftYData = energyCurvesList,
3951 leftYNames = resonatorNames,
3952 XLabel =
'Frequency (GHz)',
3954 Xunits =
'GHz', leftYunits =
'nJ',
3956 self.mainWindow.EnergyPlot.appendReverseData(leftYDataRev = energyRevCurvesList, rightYDataRev =
None)
3958 self.mainWindow.EnergyPlot.addTab(tabTitle =
'Power',
3959 title =
'Dissipated power in the resonators computed from CM',
3960 XData = SP.freq / 1e9,
3961 leftYData = powerCurvesList,
3962 leftYNames = resonatorNames,
3963 XLabel =
'Frequency (GHz)',
3965 Xunits =
'GHz', leftYunits =
'W',
3967 self.mainWindow.EnergyPlot.appendReverseData(leftYDataRev = powerRevCurvesList, rightYDataRev =
None)
3969 self.mainWindow.EnergyPlot.addTab( tabTitle =
'Couplings power',
3970 title =
'Dissipated power in the couplings computed from CM',
3971 XData = SP.freq / 1e9,
3972 leftYData = powerCoupCurves,
3973 leftYNames = powerCoupNames,
3974 XLabel =
'Frequency (GHz)',
3976 Xunits =
'GHz', leftYunits =
'W',
3978 self.mainWindow.EnergyPlot.appendReverseData(leftYDataRev = powerCoupRevCurves, rightYDataRev =
None)
3981 self.mainWindow.EnergyPlot.addTab( XData = SP.freq / 1e9,
3982 leftYData = energyCurvesList,
3983 leftYNames = resonatorNames,
3985 self.mainWindow.EnergyPlot.replaceReverseData(0, leftYDataRev = energyRevCurvesList, rightYDataRev =
None)
3987 self.mainWindow.EnergyPlot.addTab( XData = SP.freq / 1e9,
3988 leftYData = powerCurvesList,
3989 leftYNames = resonatorNames,
3991 self.mainWindow.EnergyPlot.replaceReverseData(1, leftYDataRev = powerRevCurvesList, rightYDataRev =
None)
3993 self.mainWindow.EnergyPlot.addTab( XData = SP.freq / 1e9,
3994 leftYData = powerCoupCurves,
3995 leftYNames = powerCoupNames,
3997 self.mainWindow.EnergyPlot.replaceReverseData(2, leftYDataRev = powerCoupRevCurves, rightYDataRev =
None)
4012 @pyqtSignature(
"bool")
4019 SP = self.mainWindow.SP
4022 myPrint(
'Displayed coupling matrix:')
4023 stErrorCM, CM_error = SP.fromCouplingMatrix(self.CM.MatQ)
4026 if self.mainWindow.SPlotError
is None or self.mainWindow.SPlotError.closed
is True:
4028 dynamicRange = -20*log10( min([ abs(SP.S21[0]), abs(SP.S21[-1] ), abs(SP.S21M[0]), abs(SP.S21M[-1] )]))
4029 dynamicRange = 10*ceil(dynamicRange/10)
4032 windowTitle =
'[S] parameters CM vs CP',
4034 title =
'S11 parameter computed from CM and CP',
4035 XData = SP.freq / 1e9,
4036 leftYData = [20*np.log10(np.abs(SP.S11)), 20*np.log10(np.abs(SP.S11M)), 20*np.log10(np.abs(SP.S22)), 20*np.log10(np.abs(SP.S22M)) ],
4037 leftWidth = [2, 1, 2, 1],
4038 leftYmax = 0, leftYmin = -dynamicRange,
4039 leftYNames = [
'S<sub>11</sub> from CP',
'S<sub>11</sub> from CM',
'S<sub>22</sub> from CP',
'S<sub>22</sub> from CM'] ,
4040 leftYVisible = [
True,
True,
False,
False],
4041 XLabel =
'Frequency (GHz)',
4043 Xunits =
'GHz', leftYunits =
'dB',
4044 rightYData = [ SP.phaseS11 * 180/np.pi, SP.phaseS11M * 180/np.pi, SP.phaseS22 * 180/np.pi, SP.phaseS22M * 180/np.pi ],
4045 rightWidth = [2, 1, 2, 1],
4046 rightYunits =
'deg', rightYLabel =
'degrees' ,
4047 rightYNames = [
'Phase(S<sub>11</sub>) from CP',
'Phase(S<sub>11</sub>) from CM',
'Phase(S<sub>22</sub>) from CP',
'Phase(S<sub>22</sub>) from CM'],
4048 rightYVisible = [
False,
False,
False,
False],
4049 textLabel =stErrorCM
4052 self.mainWindow.SPlotError.addTab(tabTitle =
'S21',
4053 title =
'S21 parameter computed from CM and CP',
4054 XData = SP.freq / 1e9,
4055 leftYData = [20*np.log10(np.abs(SP.S21)), 20*np.log10(np.abs(SP.S21M)) ],
4056 leftWidth = [2, 1] ,
4057 leftYmax = 0, leftYmin = -dynamicRange,
4058 leftYNames = [
'S<sub>21</sub> from CP',
'S<sub>21</sub> from CM'] ,
4059 XLabel =
'Frequency (GHz)',
4061 Xunits =
'GHz', leftYunits =
'dB',
4062 rightYData = [ SP.phaseS21 * 180/np.pi, SP.phaseS21M * 180/np.pi ],
4063 rightWidth = [2, 1],
4064 rightYunits =
'deg', rightYLabel =
'degrees' ,
4065 rightYNames = [
'Phase(S<sub>21</sub>) from CP',
'Phase(S<sub>21</sub>) from CM'],
4066 rightYVisible = [
False,
False],
4069 self.mainWindow.SPlotError.addTab(tabTitle =
'Group delay',
4070 title =
'Group delay computed from CM and CP',
4071 XData = SP.freq2 / 1e9,
4072 leftYData = [ 1e9 * SP.groupDelay2, 1e9 * SP.groupDelayM ],
4073 leftWidth = [2, 1] ,
4074 leftYNames = [
'Group delay from CP',
'Group delay from CM'],
4075 XLabel =
'Frequency (GHz)',
4076 leftYLabel =
'Group delay (ns.)',
4077 Xunits =
'GHz', leftYunits =
'ns',
4081 self.mainWindow.SPlotError.update(0, XData = SP.freq / 1e9, leftYData = [20*np.log10(np.abs(SP.S11)), 20*np.log10(np.abs(SP.S11M)), 20*np.log10(np.abs(SP.S22)), 20*np.log10(np.abs(SP.S22M))],
4082 rightYData = [ SP.phaseS11 * 180/np.pi, SP.phaseS11M * 180/np.pi, SP.phaseS22 * 180/np.pi, SP.phaseS22M * 180/np.pi ],
4083 textLabel =stErrorCM, autoScaleBottomX = self.mainWindow.autoScaleFreq )
4085 self.mainWindow.SPlotError.update(1, XData = SP.freq / 1e9, leftYData = [20*np.log10(np.abs(SP.S21)), 20*np.log10(np.abs(SP.S21M))],
4086 rightYData = [ SP.phaseS21 * 180/np.pi, SP.phaseS21M * 180/np.pi ], autoScaleBottomX = self.mainWindow.autoScaleFreq)
4088 self.mainWindow.SPlotError.update(2, XData = SP.freq2 / 1e9, leftYData = [1e9 * SP.groupDelay2, 1e9 * SP.groupDelayM], autoScaleBottomX = self.mainWindow.autoScaleFreq )
4090 self.mainWindow.autoScaleFreq =
False
4094 if self.mainWindow.SM
is not None:
4095 self.mainWindow.SPlotError.deleteMasks()
4096 self.mainWindow.plotMasks()
4099 @pyqtSignature(
"int")
4110 QMessageBox.warning(self,
"WARNING",
'User cancelled action.<p>Coupling Matrix has not been loaded from list.' )
4113 self.CM_comboBox.setCurrentIndex(self.CM.indexCM)
4117 MatQ = self.CM.listM[index].
copy()
4121 self.CM.indexCM = index
4124 self.setWindowModified(self.
dirty)
4128 self.matrixEditDlg.lastEditAction =
"Matrix %s loaded from list" % MatQ.name
4132 def pushEditAction(self):
4133 self.matrixEditDlg.edit_listWidget.addItem(self.matrixEditDlg.lastEditAction)
4134 self.matrixEditDlg.bkpActions.append(self.matrixEditDlg.lastEditAction)
4135 self.matrixEditDlg.edit_listWidget.setCurrentRow(self.matrixEditDlg.edit_listWidget.count()-1)
4136 myPrint(
"Done: Matrix edit action '%s'" % self.matrixEditDlg.lastEditAction)
4137 self.setWindowModified(self.
dirty)
4138 self.CM_name.deselect()
4141 self.matrixEditDlg.bkpMatQ.append(self.CM.MatQ.copy())
4165 super(ParamEditDlg, self).
__init__(parent)
4166 self.setAttribute(Qt.WA_DeleteOnClose)
4228 self.
P = self.mainWindow.P
4232 self.
resultBkp = copy.deepcopy( (self.mainWindow.P, self.mainWindow.CP, self.mainWindow.CM, self.mainWindow.SP, self.mainWindow.FT) )
4239 self.tabWidget.setCurrentIndex(0)
4246 self.wFunc_horizontalLayout.addStretch()
4248 self.
wFunc_tooltip =
"Adaptive predistortion weights.\nThe shift is equal to the weight times sigma:\nweights = 1 lead to conventional pole shifting.\nTable entries are editable."
4249 self.wFunc_tableWidget.setToolTip(QApplication.translate(
"ParamEditDlg", self.
wFunc_tooltip,
None, QApplication.UnicodeUTF8))
4250 self.wFunc_tableWidget.horizontalHeader().setVisible(
False)
4252 self.wFunc_horizontalLayout.addStretch()
4254 self.wFunc_verticalLayout.setAlignment(Qt.AlignHCenter)
4255 self.connect(self.N_spinBox, SIGNAL(
"valueChanged(int)"),
lambda x: self.
updatewFuncTableSize(self.P.wFunc, (self.N_spinBox.value(), 1),
True ) )
4256 self.connect(self.adapPredis_groupBox, SIGNAL(
"toggled(bool)"),
lambda x: self.
updatewFuncTableSize(self.P.wFunc, (self.N_spinBox.value(), 1),
True ) )
4261 self.genChebyTZs_horizontalLayout.addStretch()
4263 self.genChebyTZs_tableWidget.setUnits(
'MHz')
4264 self.
genChebyTZs_tooltip =
"Transmission zeros (complex or purely imaginary). \nReal part in normalized frequency units and imaginary part in MHz. Imaginary part cannot be 0 MHz. \nFor complex zeros, a symmetric zero with opposite real part is automatically added."
4265 self.genChebyTZs_tableWidget.setToolTip(QApplication.translate(
"ParamEditDlg", self.
genChebyTZs_tooltip,
None, QApplication.UnicodeUTF8))
4266 self.genChebyTZs_tableWidget.setSelectionMode(QAbstractItemView.SingleSelection)
4268 self.genChebyTZs_horizontalLayout.addStretch()
4270 self.genCheby_verticalLayout.setAlignment(Qt.AlignHCenter)
4272 self.connect(self.
genChebyTZs_tableWidget, SIGNAL(
"cellChanged(int, int)"), self.genChebyTZs_tableWidget.tableCellChanged)
4276 self.LPcomplexZeros_horizontalLayout.addStretch()
4278 self.LPcomplexZeros_tableWidget.setUnits(
'MHz')
4279 self.
LPcomplexZeros_tooltip =
"Initial positions of complex zeros to optimize for linear phase equalization. \nReal part in normalized frequency units and imaginary part in MHz. \nImaginary part of a complex zero cannot be 0 MHz. \nIf imaginary part is empty, the zero is purely real.\nA symmetric zero with opposite real part is automatically added."
4280 self.LPcomplexZeros_tableWidget.setToolTip(QApplication.translate(
"ParamEditDlg", self.
LPcomplexZeros_tooltip,
None, QApplication.UnicodeUTF8))
4281 self.LPcomplexZeros_tableWidget.setSelectionMode(QAbstractItemView.SingleSelection)
4283 self.LPcomplexZeros_horizontalLayout.addStretch()
4285 self.genChebyLPverticalLayout.setAlignment(Qt.AlignHCenter)
4287 self.connect(self.
LPcomplexZeros_tableWidget, SIGNAL(
"cellChanged(int, int)"), self.LPcomplexZeros_tableWidget.tableCellChanged)
4290 self.connect(self.f0_lineEdit, SIGNAL(
"editingFinished()"), self.genChebyTZs_tableWidget.setf0 )
4291 self.connect(self.f0_lineEdit, SIGNAL(
"editingFinished()"), self.LPcomplexZeros_tableWidget.setf0 )
4298 realValidator = QRegExpValidator( reReal , self)
4301 realPositiveValidator = QRegExpValidator( reRealPositive, self)
4302 realPositiveValidatorInf = QRegExpValidator( reRealPositiveInf, self)
4303 complexValidator = QRegExpValidator( reComplex, self)
4304 realListValidator = QRegExpValidator( reRealList, self)
4305 realPositiveListValidator = QRegExpValidator( reRealPositiveList, self)
4306 complexListValidator = QRegExpValidator( reComplexList, self)
4309 self.f0_lineEdit.setValidator(realPositiveValidator)
4310 self.BW_lineEdit.setValidator(realPositiveValidator)
4311 self.maxFreq_lineEdit.setValidator(realPositiveValidator)
4312 self.minFreq_lineEdit.setValidator(realPositiveValidator)
4313 self.chebyLr_lineEdit.setValidator(realPositiveValidator)
4314 self.qeLr_lineEdit.setValidator(realPositiveValidator)
4315 self.qeZero_lineEdit.setValidator(realPositiveValidator)
4316 self.genChebyLr_lineEdit.setValidator(realPositiveValidator)
4321 self.Qo_lineEdit.setValidator(realPositiveValidatorInf)
4322 self.QoPredis_lineEdit.setValidator(realPositiveValidatorInf)
4323 self.Qef_lineEdit.setValidator(realPositiveValidatorInf)
4326 self.nuqK11c1_lineEdit.setValidator(realPositiveValidator)
4327 self.nuqK22c1_lineEdit.setValidator(realPositiveValidator)
4328 self.nuqK21c1_lineEdit.setValidator(realPositiveValidator)
4329 self.nuqK21c2_lineEdit.setValidator(realPositiveValidator)
4330 self.nuqK21c3_lineEdit.setValidator(realPositiveValidator)
4332 self.nuqDelta_lineEdit.setValidator(realPositiveValidator)
4353 if self.P.outName
is not None: self.outName_lineEdit.setText(self.P.outName)
4354 if self.P.outDir
is not None: self.outDir_lineEdit.setText(self.P.outDir)
4357 if self.P.N
is not None: self.N_spinBox.setValue(self.P.N)
4359 if self.P.f0
is not None:
4361 autoUnitsIndex = self.f0_comboBox.findText(units)
4364 self.f0_lineEdit.setText(str(freq))
4365 self.f0_comboBox.setCurrentIndex(autoUnitsIndex)
4368 userUnitsIndex = self.f0_comboBox.currentIndex()
4369 newValue = freq * pow(10, 3*(autoUnitsIndex-userUnitsIndex))
4370 self.f0_lineEdit.setText(str(newValue))
4376 self.genChebyTZs_tableWidget.setf0(
False)
4377 self.LPcomplexZeros_tableWidget.setf0(
False)
4379 if self.P.BW
is not None:
4381 autoUnitsIndex = self.BW_comboBox.findText(units)
4384 self.BW_lineEdit.setText(str(freq))
4385 self.BW_comboBox.setCurrentIndex(autoUnitsIndex)
4388 userUnitsIndex = self.BW_comboBox.currentIndex()
4389 newValue = freq * pow(10, 3*(autoUnitsIndex-userUnitsIndex))
4390 self.BW_lineEdit.setText(str(newValue))
4395 if self.P.filterTransferFunc
is not None:
4396 topol = self.P.filterTransferFunc.title()
4397 iTopol = self.topol_comboBox.findText(topol)
4401 QMessageBox.warning(self,
"WARNING",
"Unknown Filter Topology '%s' replaced by default value." % self.P.filterTransferFunc)
4403 self.topol_comboBox.setCurrentIndex(iTopol)
4404 self.filter_stackedWidget.setCurrentIndex(iTopol)
4407 if self.P.chebyLr
is not None: self.chebyLr_lineEdit.setText(str(self.P.chebyLr))
4408 if self.P.qeLr
is not None: self.qeLr_lineEdit.setText(str(self.P.qeLr))
4411 if self.P.qeZero
is not None:
4413 autoUnitsIndex = self.qeZero_comboBox.findText(units)
4416 self.qeZero_lineEdit.setText(str(freq))
4417 self.qeZero_comboBox.setCurrentIndex(autoUnitsIndex)
4420 userUnitsIndex = self.qeZero_comboBox.currentIndex()
4421 newValue = freq * pow(10, 3*(autoUnitsIndex-userUnitsIndex))
4422 self.qeZero_lineEdit.setText(str(newValue))
4427 if self.P.genChebyLr
is not None: self.genChebyLr_lineEdit.setText(str(P.genChebyLr))
4433 listImaginaryPartsZeros = self.P.transImagZeros + np.imag( self.P.transComplexZeros + self.P.LPcomplexZeros ).tolist()
4434 if len(listImaginaryPartsZeros) > 0:
4436 autoUnitsIndex = self.transmissionZeros_comboBox.findText(units)
4440 self.transmissionZeros_comboBox.setCurrentIndex(autoUnitsIndex)
4443 userUnitsIndex = self.transmissionZeros_comboBox.currentIndex()
4448 if self.P.genChebyLP
is not None: self.genChebyLP_groupBox.setChecked(bool(self.P.genChebyLP))
4451 if self.P.LPalgor
is not None:
4452 algor = self.P.LPalgor.upper()
4453 iAlgor = self.LPalgor_comboBox.findText(algor)
4458 QMessageBox.warning(self,
"WARNING",
"Unknown Linear Phase Optimization Algorithm '%s' replaced by default value." % self.P.LPalgor)
4460 self.LPalgor_comboBox.setCurrentIndex(iAlgor)
4462 if self.P.LPmaxIter
is not None: self.LPmaxIter_spinBox.setValue(self.P.LPmaxIter)
4463 if self.P.LPNsamples
is not None: self.LPNsamples_spinBox.setValue(self.P.LPNsamples)
4464 if self.P.LPfracBW
is not None: self.LPfracBW_doubleSpinBox.setValue(self.P.LPfracBW)
4465 if self.P.LPripple
is not None: self.LPripple_doubleSpinBox.setValue(self.P.LPripple * 1e9)
4468 TZsList = np.concatenate( (1j*np.array(self.P.transImagZeros), np.array(self.P.transComplexZeros)) ).tolist()
4476 if self.P.synthTech
is not None:
4477 tech = self.P.synthTech.title()
4478 iTech = self.synthTech_comboBox.findText(tech)
4483 QMessageBox.warning(self,
"WARNING",
"Unknown Synthesis Technique '%s' replaced by default value." % self.P.synthTech)
4485 self.synthTech_comboBox.setCurrentIndex(iTech)
4486 self.synthTech_stackedWidget.setCurrentIndex(iTech)
4489 if self.P.finiteQo
is not None: self.finiteQo_groupBox.setChecked(bool(self.P.finiteQo))
4490 if self.P.Qo
is not None: self.Qo_lineEdit.setText(self.
float2stInf(self.P.Qo))
4493 if self.P.zerosArrang
is not None:
4494 if type(self.P.zerosArrang).__name__ ==
'list': self.zerosArrang_comboBox.setCurrentIndex(0)
4495 else: self.zerosArrang_comboBox.setCurrentIndex(self.P.zerosArrang)
4496 if self.P.adapPredis
is not None: self.adapPredis_groupBox.setChecked(bool(self.P.adapPredis))
4497 if self.P.QoPredis
is not None: self.QoPredis_lineEdit.setText(self.
float2stInf(self.P.QoPredis))
4498 if self.P.Qef
is not None: self.Qef_lineEdit.setText(self.
float2stInf(self.P.Qef))
4507 if self.P.nuqK11c1
is not None: self.nuqK11c1_lineEdit.setText(str(self.P.nuqK11c1))
4508 if self.P.nuqK22c1
is not None: self.nuqK22c1_lineEdit.setText(str(self.P.nuqK22c1))
4509 if self.P.nuqK21c1
is not None: self.nuqK21c1_lineEdit.setText(str(self.P.nuqK21c1))
4510 if self.P.nuqK21c2
is not None: self.nuqK21c2_lineEdit.setText(str(self.P.nuqK21c2))
4511 if self.P.nuqK21c3
is not None: self.nuqK21c3_lineEdit.setText(str(self.P.nuqK21c3))
4513 if self.P.nuqTech
is not None:
4514 nuqTech= self.P.nuqTech
4515 iNuqTech = self.nuqTech_comboBox.findText(nuqTech)
4520 QMessageBox.warning(self,
"WARNING",
"Unknown Prescribed Insertion Loss technique '%s' replaced by default value." % self.P.nuqTech)
4522 self.nuqTech_comboBox.setCurrentIndex(iNuqTech)
4523 self.nuqTech_stackedWidget.setCurrentIndex(iNuqTech)
4525 if self.P.nuqDelta
is not None: self.nuqDelta_lineEdit.setText(str(self.P.nuqDelta))
4528 if self.P.minFreq
is not None:
4530 autoUnitsIndex = self.minFreq_comboBox.findText(units)
4533 self.minFreq_lineEdit.setText(str(freq))
4534 self.minFreq_comboBox.setCurrentIndex(autoUnitsIndex)
4537 userUnitsIndex = self.minFreq_comboBox.currentIndex()
4538 newValue = freq * pow(10, 3*(autoUnitsIndex-userUnitsIndex))
4539 self.minFreq_lineEdit.setText(str(newValue))
4544 if self.P.maxFreq
is not None:
4546 autoUnitsIndex = self.maxFreq_comboBox.findText(units)
4549 self.maxFreq_lineEdit.setText(str(freq))
4550 self.maxFreq_comboBox.setCurrentIndex(autoUnitsIndex)
4553 userUnitsIndex = self.maxFreq_comboBox.currentIndex()
4554 newValue = freq * pow(10, 3*(autoUnitsIndex-userUnitsIndex))
4555 self.maxFreq_lineEdit.setText(str(newValue))
4560 if self.P.numFreq
is not None: self.numFreq_spinBox.setValue(self.P.numFreq)
4562 self.
oldSweep = (P.minFreq, P.maxFreq)
4571 for n
in range(len(list)):
4573 item = QTableWidgetItem(
complexStr(list[n], saveSignificantDigits, eng =
True) )
4575 item.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
4576 self.wFunc_tableWidget.setItem(0, n, item)
4587 M = table.rowCount()
4590 item = table.item(m, 0)
4592 if item
is None:
raise ValueError,
'Empty cell'
4593 value = float(item.text())
4594 except ValueError, err:
4595 QMessageBox.critical(self,
"ERROR",
'<p align="center">Incorrect table entry:<br>%s</p>' % err)
4596 if item
is not None: item.setText(
'')
4597 else: list.append(value)
4598 if len(list) == 1: list = list[0]
4613 M = table.rowCount()
4619 reItem = table.item(m, 0)
4620 stRe = str(reItem.text()).strip()
if reItem
is not None else ''
4622 re = float(stRe)
if stRe !=
'' else 0
4623 except ValueError, err:
4624 QMessageBox.critical(self,
"ERROR",
'<p align="center">Incorrect table entry:<br>%s</p>' % err)
4625 table.currentItem().setText(
'')
4629 if re == 0
and stRe !=
'': table.currentItem().setText(
'')
4631 imItem = table.item(m, 1)
4632 stIm = str(imItem.text()).strip()
if imItem
is not None else ''
4637 except ValueError, err:
4638 QMessageBox.critical(self,
"ERROR",
'<p align="center">Incorrect table entry:<br>%s</p>' % err)
4639 table.currentItem().setText(
'')
4645 if re==0
and im==0:
continue
4647 stError =
'<p align="center">Incorrect table entry at row %d:<br>%s</p><p align="center"><b>Please fix it.</b></p>'
4649 QMessageBox.critical(self,
"ERROR", stError % (m+1,
'Imaginary part of a transmission zero cannot be negative Hz.'))
4651 QMessageBox.critical(self,
"ERROR", stError % (m+1,
'Imaginary part of a transmission zero cannot be 0 Hz.'))
4661 return listImag, listComplex, listReal
4674 table.setRowCount(len(list))
4675 table.setColumnCount(3)
4677 table.setHorizontalHeaderLabels( [
'Real',
'Imag (%s)' % stUnits,
'Imag-f0 (%s)' % stUnits ] )
4678 table.setToolTip(unicode(table.toolTip()).replace(table.units, stUnits))
4679 table.setUnits(stUnits)
4682 table.updatedByUser =
False
4684 for n
in range(len(list)):
4685 if list[n].real != 0: reItem = QTableWidgetItem(
'%.*g' % (saveSignificantDigits, list[n].real) )
4686 else: reItem = QTableWidgetItem(
'')
4687 reItem.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
4688 table.setItem(n, 0, reItem)
4690 if list[n].imag != 0:
4692 imItemf0 = QTableWidgetItem(
'%.*g' % (saveSignificantDigits, (list[n].imag - table.f0) / pow(10, 3*self.
transmissionZerosUnitsIndex)) )
4694 imItem = QTableWidgetItem(
'')
4695 imItemf0 = QTableWidgetItem(
'')
4696 imItem.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
4697 imItemf0.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
4698 table.setItem(n, 1, imItem)
4699 table.setItem(n, 2, imItemf0)
4701 table.updatedByUser =
True
4703 table.updateTableSize()
4715 if freq == 0:
return (0,
'Hz')
4717 if type(freq)
in [ types.FloatType, types.IntType, types.ComplexType ]: freq = [ freq ]
4719 afreq = np.array(freq)
4720 freqExp = log10(np.prod(afreq)) / len(freq)
4723 newFreq = afreq / 1e9
4726 newFreq = afreq / 1e6
4729 newFreq = afreq / 1e3
4735 newFreq = newFreq.tolist()
4736 if len(newFreq) == 1: newFreq = newFreq[0]
4738 return newFreq, units
4748 return np.inf
if st.lower().lstrip().rstrip()==
'inf' else float(st)
4758 return 'Inf' if value==np.inf
else str(value)
4774 key =
'Filter / Filter order'
4775 self.P.N = self.N_spinBox.value()
4777 key =
'Name of results output files'
4778 if self.outName_lineEdit.text() ==
u'':
raise ValueError,
'Empty string'
4779 self.P.outName = unicode(self.outName_lineEdit.text())
4781 key =
'Output directory'
4782 if self.outDir_lineEdit.text() ==
u'': self.P.outDir =
None
4783 self.P.outDir = unicode(self.outDir_lineEdit.text())
4785 key =
'Filter / Center Frequency'
4786 self.P.f0 = float(self.f0_lineEdit.text()) * 10**(3*self.
f0UnitsIndex)
4788 key =
'Filter / Bandwidth'
4789 self.P.BW = float(self.BW_lineEdit.text()) * 10**(3*self.
BWUnitsIndex)
4791 key =
'Filter / Filter Topology'
4792 self.P.filterTransferFunc = unicode(self.topol_comboBox.currentText())
4794 key =
'Filter / Chebyshev / Return losses'
4795 if unicode(self.chebyLr_lineEdit.text()) !=
u'' or self.P.filterTransferFunc ==
u'Chebyshev':
4796 self.P.chebyLr = float(self.chebyLr_lineEdit.text())
4798 key =
'Filter / Quasieliptic / Return losses'
4799 if unicode(self.qeLr_lineEdit.text()) !=
u'' or self.P.filterTransferFunc ==
u'Quasieliptic':
4800 self.P.qeLr = float(self.qeLr_lineEdit.text())
4802 key =
'Filter / Quasieliptic / Transmission zero'
4803 if unicode(self.qeZero_lineEdit.text()) !=
u'' or self.P.filterTransferFunc ==
u'Quasieliptic':
4804 self.P.qeZero = float(self.qeZero_lineEdit.text()) * 10**(3*self.
qeZeroUnitsIndex)
4806 key =
'Filter / Generalized Chebyshev / Return losses'
4807 if unicode(self.genChebyLr_lineEdit.text()) !=
u'' or self.P.filterTransferFunc ==
u'Generalized Chebyshev':
4808 self.P.genChebyLr = float(self.genChebyLr_lineEdit.text())
4810 key =
'Filter / Generalized Chebyshev / Transmission Zeros'
4813 if self.P.filterTransferFunc ==
u'Generalized Chebyshev':
4819 if len(transRealZeros) > 0:
raise ValueError,
'Transmission zeros cannot be purely real,\nthey must have imaginary part > 0 Hz'
4824 key =
'Filter / Generalized Chebyshev / Linear Phase'
4825 self.P.genChebyLP = int(self.genChebyLP_groupBox.isChecked())
4827 if self.P.genChebyLP:
4835 key =
'Filter / Generalized Chebyshev / Linear Phase equalization / Algorithm'
4836 self.P.LPalgor = unicode(self.LPalgor_comboBox.currentText())
4838 key =
'Filter / Generalized Chebyshev / Linear Phase equalization / Max iter'
4839 self.P.LPmaxIter = self.LPmaxIter_spinBox.value()
4841 key =
'Filter / Generalized Chebyshev / Linear Phase equalization / N samples'
4842 self.P.LPNsamples = self.LPNsamples_spinBox.value()
4844 key =
'Filter / Generalized Chebyshev / Linear Phase equalization / Fractional bandwidth to optimize'
4845 self.P.LPfracBW = self.LPfracBW_doubleSpinBox.value()
4847 key =
'Filter / Generalized Chebyshev / Linear Phase equalization / Group delay ripple'
4848 self.P.LPripple = self.LPripple_doubleSpinBox.value() / 1e9
4850 key =
'Filter / Generalized Chebyshev / Linear Phase equalization / Initial position of complex transmission zeros'
4852 if len(imagZerosList) > 0:
raise ValueError,
'Linear Phase optimization zeros cannot be purely imaginary'
4854 key =
'Synthesis / Synthesis Technique'
4855 self.P.synthTech = unicode(self.synthTech_comboBox.currentText())
4857 key =
'Synthesis / Minimum Insertion Loss / Finite Q'
4858 self.P.finiteQo = int(self.finiteQo_groupBox.isChecked())
4860 key =
'Synthesis / Minimum Insertion Loss / Q of implementation'
4861 if unicode(self.Qo_lineEdit.text()) !=
u'' or ( self.P.synthTech ==
u'Minimum Insertion Loss' and self.P.finiteQo == 1 ):
4862 self.P.Qo = self.
st2floatInf(unicode(self.Qo_lineEdit.text()))
4864 key =
'Synthesis / Predistortion / Arrangement of the reflection zeros'
4865 if self.zerosArrang_comboBox.currentIndex() == 0:
4867 if type(self.P.zerosArrang).__name__ ==
'int':
4868 if self.P.zerosArrang == 1: self.P.zerosArrang = [
True for n
in range(self.P.N) ]
4869 if self.P.zerosArrang == 2: self.P.zerosArrang = [
False for n
in range(self.P.N) ]
4870 if self.P.zerosArrang == 3: self.P.zerosArrang = [ bool(n%2)
for n
in range(self.P.N) ]
4871 if self.P.zerosArrang == 4: self.P.zerosArrang = [
not bool(n%2)
for n
in range(self.P.N) ]
4873 self.P.zerosArrang = self.zerosArrang_comboBox.currentIndex()
4875 key =
'Synthesis / Predistortion / Adaptive predistorsion'
4876 self.P.adapPredis = int(self.adapPredis_groupBox.isChecked())
4878 key =
'Synthesis / Predistortion / Q to implement'
4879 if unicode(self.QoPredis_lineEdit.text()) !=
u'' or self.P.synthTech ==
u'Predistortion':
4880 self.P.QoPredis = self.
st2floatInf(unicode(self.QoPredis_lineEdit.text()))
4882 key =
'Synthesis / Predistortion / Q to emulate'
4883 if unicode(self.Qef_lineEdit.text()) !=
u'' or self.P.synthTech ==
u'Predistortion':
4884 self.P.Qef = self.
st2floatInf(unicode(self.Qef_lineEdit.text()))
4886 key =
'Synthesis / Predistortion / Weight function for the pole shifting'
4888 if self.P.synthTech ==
u'Predistortion' and self.P.adapPredis == 1:
4896 if len(self.P.wFunc) == 1: self.P.wFunc = self.P.wFunc[0]
4898 key =
'Synthesis / Non-uniform Q / Prescribed Insertion Loss technique'
4899 self.P.nuqTech = unicode(self.nuqTech_comboBox.currentText())
4901 key =
'Synthesis / Non-uniform Q / Prescribed Insertion Loss technique / kS21+kS11 / K11'
4902 if unicode(self.nuqK11c1_lineEdit.text()) !=
u'' or self.P.synthTech ==
u'Prescribed Insertion Loss' and self.P.nuqTech ==
'kS21+kS11':
4903 self.P.nuqK11c1 = float(self.nuqK11c1_lineEdit.text())
4905 key =
'Synthesis / Non-uniform Q / Prescribed Insertion Loss technique / kS21+kS11 / K22'
4906 if unicode(self.nuqK22c1_lineEdit.text()) !=
u'' or self.P.synthTech ==
u'Prescribed Insertion Loss' and self.P.nuqTech ==
'kS21+kS11':
4907 self.P.nuqK22c1 = float(self.nuqK22c1_lineEdit.text())
4909 key =
'Synthesis / Non-uniform Q / Prescribed Insertion Loss technique / kS21+kS11 / K21'
4910 if unicode(self.nuqK21c1_lineEdit.text()) !=
u'' or self.P.synthTech ==
u'Prescribed Insertion Loss' and self.P.nuqTech ==
'kS21+kS11':
4911 self.P.nuqK21c1 = float(self.nuqK21c1_lineEdit.text())
4913 key =
'Synthesis / Non-uniform Q / Prescribed Insertion Loss technique / kS21 / Insertion losses K21'
4914 if unicode(self.nuqK21c2_lineEdit.text()) !=
u'' or self.P.synthTech ==
u'Prescribed Insertion Loss' and self.P.nuqTech ==
'kS21':
4915 self.P.nuqK21c2 = float(self.nuqK21c2_lineEdit.text())
4917 key =
'Synthesis / Non-uniform Q / Prescribed Insertion Loss technique / kS21+pole/zero / Insertion losses K21'
4918 if unicode(self.nuqK21c3_lineEdit.text()) !=
u'' or self.P.synthTech ==
u'Prescribed Insertion Loss' and self.P.nuqTech ==
'kS21+pole/zero':
4919 self.P.nuqK21c3 = float(self.nuqK21c3_lineEdit.text())
4921 key =
'Synthesis / Non-uniform Q / Prescribed Insertion Loss technique / kS21+pole/zero / Delta'
4922 if unicode(self.nuqDelta_lineEdit.text()) !=
u'' or (self.P.synthTech ==
u'Prescribed Insertion Loss' and self.P.nuqTech ==
'kS21+pole/zero' ):
4923 self.P.nuqDelta = float(self.nuqDelta_lineEdit.text())
4925 key =
'Sweep / Minimum Frequency'
4926 self.P.minFreq = float(self.minFreq_lineEdit.text()) * 10**(3*self.
minFreqUnitsIndex)
4928 key =
'Sweep / Maximum Frequency'
4929 self.P.maxFreq = float(self.maxFreq_lineEdit.text()) * 10**(3*self.
maxFreqUnitsIndex)
4931 key =
'Sweep / Number of samples'
4932 self.P.numFreq = self.numFreq_spinBox.value()
4934 if self.
oldSweep != (self.P.minFreq, self.P.maxFreq): self.mainWindow.autoScaleFreq =
True
4935 else: self.mainWindow.autoScaleFreq =
False
4937 self.
oldSweep = (self.P.minFreq, self.P.maxFreq)
4939 except ValueError, err:
4940 QMessageBox.critical(self,
"ERROR",
'<p align="center">Incorrect parameter error:<br>%s<br>%s<br></p><p align="center">Fix or click "Discard" button.</p>' % (key, err))
4946 except parseError, err:
4947 QMessageBox.critical(self,
"ERROR",
'<p align="center">Incorrect parameter error:<br>%s</p><p align="center">Fix or click "Discard" button.</p>' % err)
4954 self.P.empty =
False
4970 if type(self.P.zerosArrang).__name__ ==
'list':
4971 Nold = len(self.P.zerosArrang)
4972 if N > Nold: self.P.zerosArrang += [
False for n
in range(N-Nold)]
4973 if N < Nold: self.P.zerosArrang = self.P.zerosArrang[0:N]
4989 if unicode(self.synthTech_comboBox.currentText()) ==
u'Predistortion' and self.adapPredis_groupBox.isChecked():
4996 list = (1 - 0.5 * np.sin(np.arange(1., M+1)*pi/(M+1)) )
4997 self.wFunc_tableWidget.setRowCount(M)
4998 self.wFunc_tableWidget.setColumnCount(N)
5001 self.wFunc_tableWidget.resizeRowsToContents()
5002 self.wFunc_tableWidget.resizeColumnsToContents()
5003 self.wFunc_tableWidget.setMaximumSize( self.wFunc_tableWidget.maximumSizeHint() )
5017 totalZeros = len(self.P.transImagZeros) + 2*len(self.P.transComplexZeros)
5019 if self.genChebyLP_groupBox.isChecked():
5020 totalZeros += len(LPimagZeros) + 2*len(self.P.LPcomplexZeros + self.P.LPrealZeros)
5022 self.transmissionZeros_lcdNumber.display(totalZeros)
5034 incTZsTable = (self.genChebyTZs_tableWidget.rowCount()+1.5) * self.genChebyTZs_tableWidget.rowHeight(0)
5035 incLPzerosTable = (self.LPcomplexZeros_tableWidget.rowCount()+1.5) * self.LPcomplexZeros_tableWidget.rowHeight(0)
5037 dlgSize = self.size()
5038 dlgHeight= dlgSize.height()
5040 dlgOptSize = dlgMinHeight + incTZsTable + incLPzerosTable
5046 dlgSize.setHeight(dlgOptSize)
5047 self.resize(dlgSize)
5059 if hasattr(self.sender(),
'validator'):
5060 validator = self.sender().validator()
5061 if validator
is not None:
5062 result = validator.validate(self.sender().text(), 0)[0]
5063 palette = self.sender().palette()
5065 palette.setColor(QPalette.Text, Qt.red)
5066 self.sender().setPalette(palette)
5067 self.badInput.append(self.sender())
5068 self.sender().setFocus(Qt.OtherFocusReason)
5070 palette.setColor(QPalette.Text, self.mainWindow.palette().text().color())
5071 self.sender().setPalette(palette)
5072 while self.sender()
in self.
badInput: self.badInput.remove(self.sender())
5078 self.compute_pushButton.setEnabled(
False)
5079 self.accept_pushButton.setEnabled(
False)
5081 self.compute_pushButton.setEnabled(
True)
5082 self.accept_pushButton.setEnabled(
True)
5091 outDir = self.P.outDir
if self.P.outDir
is not None else os.path.dirname(sys.argv[0])
5092 self.P.outDir = QFileDialog.getExistingDirectory(self, QString(
u"Output directory"), outDir)
5094 self.outDir_lineEdit.setText(QDir.toNativeSeparators(self.P.outDir))
5097 @pyqtSignature(
"bool")
5106 QMessageBox.critical(self,
"ERROR",
'Incorrect parameter in edit window.<p>Cannot run optimization with incorrect parameters.')
5109 algor = self.algor_comboBox.currentText()
5110 maxIter = self.maxIter_spinBox.value()
5111 Nsamples = self.Nsamples_spinBox.value()
5112 BWmaxvar = self.BWoptim_doubleSpinBox.value()
5113 weights = [ self.wS11_doubleSpinBox.value(), self.wS22_doubleSpinBox.value(), self.wS21_doubleSpinBox.value() ]
5115 SM = self.mainWindow.SM
5118 reply = QMessageBox.question(self,
"WARNING",
'<b>No specification mask loaded.</b><p>Do you want to open an specification mask file now?', QMessageBox.Yes| QMessageBox.Cancel)
5119 if reply == QMessageBox.Yes:
5120 self.mainWindow.on_action_Mask_triggered(
True)
5121 SM = self.mainWindow.SM
5123 runOptimization =
False
5125 if self.genChebyLP_groupBox.isChecked():
5126 reply = QMessageBox.question(self,
"WARNING",
'''<b>Linear phase optimization is enabled.</b><p>
5127 First, equalization zeros will be optimized for linear phase.<p>
5128 Second, imaginary transmission zeros will be optimized to comply mask, with the optimum equalization zeros as prescribed transmission zeros.<p>
5129 Third, if you have an open [S] parameter window, filter synthesis will be recomputed, which involves a new linear phase optimization with fixed prescribed transmission zeros.<p>
5130 Do you wish to proceed?''', QMessageBox.Yes| QMessageBox.Cancel)
5131 if reply == QMessageBox.Yes:
5132 runOptimization =
True
5135 runOptimization =
True
5141 if importedExtraFilters
is False:
5142 if existingExtraFilters
is False:
5144 Chebyshev filter is in the Library of Extra Filters,<br>
5145 which is not installed in this system.
5146 <p>Contact lossyfilters@tsc.upc.edu to get the Library of Extra Filters.
5150 Importing the 'Library of Extra Filters' failed. <br>
5151 You have a libextrafilters.pyc file, but it cannot be imported. <br>
5152 Possibly libextrafilters.pyc was compiled using a different Python version than yours.
5153 <p>Your installed Python version is: %s on %s
5154 <p>Read the README.html documentation or contact lossyfilters@tsc.upc.edu for assistence.
5155 """ % (platform.python_version(), platform.system()) )
5159 app.setOverrideCursor(Qt.WaitCursor)
5161 TZoptimMask(self, self.
P, self.mainWindow.FT, weights, BWmaxvar, algor, maxIter, Nsamples, SM, LPeqZeros)
5162 except synthError, err:
5165 app.restoreOverrideCursor()
5166 myPrint(
'Imaginaty TZs and BW optimization to mask with parameters: alg=%s, maxIter=%d, Nsamples=%d, BWmaxvar=%g, w=%s, mask=%s' % (algor, maxIter, Nsamples, BWmaxvar,
listStr(weights, 2), SM.fileName) )
5168 myPrint(
'Imaginaty TZs and BW optimization to mask cancelled by user')
5171 @pyqtSignature(
"bool")
5178 self.mainWindow.on_action_Execute_triggered(
True)
5181 @pyqtSignature(
"bool")
5187 self.genChebyTZs_tableWidget.addRow()
5190 @pyqtSignature(
"bool")
5196 self.LPcomplexZeros_tableWidget.addRow()
5199 @pyqtSignature(
"bool")
5206 row = table.currentRow()
5209 stError =
'<p align="center">Please select a transmission zero to symmetrize<p align="center"</p>'
5210 QMessageBox.warning(self,
"WARNING", stError)
5213 reItem = table.item(row, 0)
5214 imItem = table.item(row, 1)
5215 stRe = str(reItem.text()).strip()
if reItem
is not None else ''
5216 stIm = str(imItem.text()).strip()
if imItem
is not None else ''
5217 re = float(stRe)
if stRe !=
'' else 0
5222 f0 = float(self.f0_lineEdit.text()) * 10**(3*self.
f0UnitsIndex)
5225 N = table.rowCount()
5226 table.setRowCount(N+1)
5228 imSymItem.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
5229 table.setItem(N, 1, imSymItem)
5230 reSymItem = QTableWidgetItem(
'%.*g' % (saveSignificantDigits, re) )
if re != 0
else QTableWidgetItem(
'')
5231 reSymItem.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
5232 table.setItem(N, 0, reSymItem)
5234 table.updateTableSize()
5238 @pyqtSignature(
"bool")
5245 row = table.currentRow()
5248 stError =
'<p align="center">Please select a transmission zero to symmetrize<p align="center"</p>'
5249 QMessageBox.warning(self,
"WARNING", stError)
5252 reItem = table.item(row, 0)
5253 imItem = table.item(row, 1)
5254 stRe = str(reItem.text()).strip()
if reItem
is not None else ''
5255 stIm = str(imItem.text()).strip()
if imItem
is not None else ''
5256 re = float(stRe)
if stRe !=
'' else 0
5259 imSym = self.mainWindow.FT.unormFreq( - self.mainWindow.FT.normFreq(im) )
5261 N = table.rowCount()
5262 table.setRowCount(N+1)
5264 imSymItem.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
5265 table.setItem(N, 1, imSymItem)
5266 reSymItem = QTableWidgetItem(
'%.*g' % (saveSignificantDigits, re) )
if re != 0
else QTableWidgetItem(
'')
5267 reSymItem.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
5268 table.setItem(N, 0, reSymItem)
5270 table.updateTableSize()
5289 message =
"Parameters have been modified and it is necessary to recompute synthesis.<p>Continue?"
5290 reply = QMessageBox.question(self,
"%s - Recompute" % applicationName, message, QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel)
5291 if reply
in [QMessageBox.Cancel, QMessageBox.No]:
5294 elif reply == QMessageBox.Yes:
5297 self.mainWindow.dirty =
True
5298 self.mainWindow.setWindowModified(self.mainWindow.dirty)
5300 self.mainWindow.updateStatus(
"Parameter values accepted")
5301 self.mainWindow.paramEdit =
None
5304 self.mainWindow.updateStatus(
"Incorrect parameters not accepted")
5308 @pyqtSignature(
"bool")
5317 message =
"""Dialog discarded by user:<p>
5318 All parameters and synthesis results will be reverted to a previous state. To keep your parameters and results, click the "Accept" button in the Parameter Editor.<p>
5319 Revert parameters and results?"""
5320 reply = QMessageBox.question(self,
"%s - Discard parameters" % applicationName, message, QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel)
5321 if reply
in [QMessageBox.Cancel, QMessageBox.No]:
5324 (self.mainWindow.P, self.mainWindow.CP, self.mainWindow.CM, self.mainWindow.SP, self.mainWindow.FT) = copy.deepcopy(self.
resultBkp)
5325 self.mainWindow.updateStatus(
"Parameter values discarded by user")
5326 self.mainWindow.paramEdit =
None
5327 self.mainWindow.updateWindows()
5335 @pyqtSignature(
"int")
5345 newValue = float(self.f0_lineEdit.text()) * pow(10, 3*(self.
f0UnitsIndex-newIndex))
5346 self.f0_lineEdit.setText(str(newValue))
5350 @pyqtSignature(
"int")
5360 newValue = float(self.BW_lineEdit.text()) * pow(10, 3*(self.
BWUnitsIndex-newIndex))
5361 self.BW_lineEdit.setText(str(newValue))
5365 @pyqtSignature(
"int")
5375 newValue = float(self.qeZero_lineEdit.text()) * pow(10, 3*(self.
qeZeroUnitsIndex-newIndex))
5376 self.qeZero_lineEdit.setText(str(newValue))
5380 @pyqtSignature(
"int")
5391 TZsList = np.concatenate( (1j*np.array(self.P.transImagZeros), np.array(self.P.transComplexZeros)) ).tolist()
5396 @pyqtSignature(
"int")
5406 newValue = float(self.minFreq_lineEdit.text()) * pow(10, 3*(self.
minFreqUnitsIndex-newIndex))
5407 self.minFreq_lineEdit.setText(str(newValue))
5411 @pyqtSignature(
"int")
5421 newValue = float(self.maxFreq_lineEdit.text()) * pow(10, 3*(self.
maxFreqUnitsIndex-newIndex))
5422 self.maxFreq_lineEdit.setText(str(newValue))
5446 CP, CM, SP =
None,
None,
None
5452 myPrint(
"Relative error in the computation of lossless characteristic polynomials = %g" % CP.rootsErr)
5454 if P.synthTech.title() ==
u'Predistortion':
5455 if importedLossyFilters
is False:
5456 if existingLossyFilters
is False:
5457 raise synthError,
"""Pre-distorted characteristic polynomials are in the Library of Lossy Filters, which is not installed in this system.
5458 <p>Contact lossyfilters@tsc.upc.edu to get the Library of Lossy Filters.
5461 raise synthError,
"""Importing the 'Library of Lossy Filters' failed. <br>
5462 You have a liblossyfilters.pyc file, but it cannot be imported. <br>
5463 Possibly liblossyfilters.pyc was compiled using a different Python version than yours.
5464 <p>Your installed Python version is: %s on %s
5465 <p>Read the README.html documentation or contact lossyfilters@tsc.upc.edu for assistence.
5466 """ % (platform.python_version(), platform.system())
5467 elif importedCheckLicense
is False:
5468 if existingCheckLicense
is False:
5469 raise synthError,
"""There is no check_license.pyc file in your system.
5470 It should have been installed together with libextrafilters.pyc file,
5471 which actually is in your system.
5472 Please follow the 'Extra Filters Library' installation instructions.
5475 raise synthError,
"""Importing the 'License Check Library' failed. <br>
5476 You have a libchecklicense.pyc file, but it cannot be imported. <br>
5477 Possibly libchecklicense.pyc was compiled using a different Python version than yours.
5478 <p>Your installed Python version is: %s on %s
5479 <p>Read the README.html documentation or contact lossyfilters@tsc.upc.edu for assistence.
5480 """ % (platform.python_version(), platform.system())
5482 predistortion(P, CP, FT )
5483 myPrint(
"Relative error in the computation of pre-distorted characteristic polynomials = %g" % CP.rootsErr)
5485 elif P.synthTech.title() ==
u'Prescribed Insertion Loss':
5486 if importedLossyFilters
is False:
5487 if existingLossyFilters
is False:
5488 raise synthError,
"""Prescribed insertion loss characteristic polynomials are in the Library of Lossy Filters, which is not installed in this system.
5489 <p>Contact lossyfilters@tsc.upc.edu to get the Library of Lossy Filters.
5492 raise synthError,
"""Importing the 'Library of Lossy Filters' failed. <br>
5493 You have a liblossyfilters.pyc file, but it cannot be imported. <br>
5494 Possibly liblossyfilters.pyc was compiled using a different Python version than yours.
5495 <p>Your installed Python version is: %s on %s
5496 <p>Read the README.html documentation or contact lossyfilters@tsc.upc.edu for assistence.
5497 """ % (platform.python_version(), platform.system())
5498 elif importedCheckLicense
is False:
5499 if existingCheckLicense
is False:
5500 raise synthError,
"""There is no check_license.pyc file in your system.
5501 It should have been installed together with libextrafilters.pyc file,
5502 which actually is in your system.
5503 Please follow the 'Extra Filters Library' installation instructions.
5506 raise synthError,
"""Importing the 'License Check Library' failed. <br>
5507 You have a libchecklicense.pyc file, but it cannot be imported. <br>
5508 Possibly libchecklicense.pyc was compiled using a different Python version than yours.
5509 <p>Your installed Python version is: %s on %s
5510 <p>Read the README.html documentation or contact lossyfilters@tsc.upc.edu for assistence.
5511 """ % (platform.python_version(), platform.system())
5521 myPrint(
"Relative error in the computation of transversal coupling matrix = %g" % CM.CM_error)
5525 if (P.synthTech.title() !=
u'Prescribed Insertion Loss')
or (P.nuqTech !=
u'kS21+pole/zero'):
5527 for MatQ
in [ CM.listM[0] ]:
5529 stErrorCM, CM_error = SP.fromCouplingMatrix(MatQ)
5530 myPrint(stErrorCM +
', Relative error: %e\n' % CM_error)
5531 CM.updateCM_error(CM_error, st =
'Error in %s' % MatQ.name)
5533 if P.outDir
is not None:
5535 P.outDir = os.path.normpath(P.outDir)
5536 P.outDir = os.path.expanduser(P.outDir)
5539 if not os.path.isdir(P.outDir):
5541 warningMsg(
u"WARNING: Directory '%s' does not exist. <p>Results not saved" % P.outDir)
5544 P.outDirName = os.path.join(P.outDir, P.outName)
5546 P.outDirName = P.outName
5548 if P.outDirName
is not None:
5550 P.outDirName = os.path.normpath(P.outDirName)
5553 CP.saveCharPolys(P, saveSignificantDigits)
5554 SP.saveSparam(P, saveSignificantDigits)
5555 if saveDefaultMatrices:
5556 CM.saveCouplingMatrices(P, SP, saveSignificantDigits, saveSignificantDigitsEnergy)
5558 except licenseError, err:
5560 return None,
None,
None,
False
5562 except synthError, err:
5564 return None,
None,
None,
False
5566 return CP, CM, SP,
True
5577 pgrm_name = os.path.basename(sys.argv[0])
5579 print 'usage: ' + pgrm_name +
' [-vh] [--help] [parameter_file]'
5581 print '-v: Verbose output. Show more information (for debugging) at the log in the main window (or at the console with --nogui flag).'
5582 print '-s: Automatically symmetrize Generalized Chebyshev zeros in Hz in order to compute a folded matrix with uniform Q in resonators.'
5583 print '-r: Automatically run Synthesis. Needs simultaneous parameter file specification.'
5584 print '-m: Automatically open Coupling Matrices window. Needs simultaneous -r flag.'
5585 print '-e: Automatically open Matrix Edit window. Needs simultaneous -m flag.'
5586 print '-p N: Save all default coupling matrices to file after they are computed, using N significant digits. By default the matrices must be saved manually using the GUI.'
5587 print '-h, --help: help'
5588 print '--nogui: Command line interface'
5589 print '--style windows, motif, cleanlooks, plastique or cde'
5590 print '\nArguments:'
5591 print 'parameter_file (optional): Path to ASCII file containing parameter values\n'
5601 if __name__ ==
'__main__':
5608 applicationName =
"Microwave filters GUI"
5612 opts, args = getopt.getopt(sys.argv[1:],
"hsvrmep:", [
"style=",
"help",
"nogui"])
5613 except getopt.GetoptError:
5615 usage(
'Error: Bad command line parameters', 2)
5618 QtArgs.append(sys.argv[0])
5621 symmetrizeZeros =
None
5622 verbose = autoRun = autoMatrix = autoEditMatrix =
False
5625 saveDefaultMatrices =
False
5632 symmetrizeZeros =
True
5641 autoEditMatrix =
True
5645 saveSignificantDigits = int(a)
5647 print "ERROR in command line flags:"
5648 print "Precision flag -p must take a numeric argument."
5649 print "To get help use -h flag:\n%s -h\n" % sys.argv[0]
5651 saveDefaultMatrices =
True
5653 if o
in (
"-h",
"--help"):
5659 if o
in [
"--style"]:
5669 if len(args) != 1:
usage(
'Error: Incorrect number of arguments', 2)
5684 CP, CM, SP, done =
runSynthesis(P, FT, symmetrizeZeros)
5687 if QtArgsStyle
is None: QtArgsStyle =
'cleanlooks'
5688 QtArgs.extend([
'-style', QtArgsStyle ])
5690 if len(args) > 1:
usage(
'Error: Incorrect number of arguments', 2)
5692 if len(args) == 1: fileName = unicode(args[0])
5693 else: fileName =
None
5697 stFloatPoint =
r'((\d+\.?\d*|\d*\.?\d+)([Ee][-+]?\d+)?)'
5698 stReal =
r'(([-+]?)' + stFloatPoint +
'\s*)'
5699 stRealPositive =
r'((\+?)' + stFloatPoint +
'\s*)'
5700 stComplex =
r'(([-+]?' + stFloatPoint +
r'|[-+]?(' + stFloatPoint +
r')?[ij]|[-+]?' + stFloatPoint +
r'\s*[-+]\s*(' + stFloatPoint +
r')?[ij])\s*)'
5701 stRealList = stReal +
r'(,\s*' + stReal +
r')*'
5702 stRealPositiveList = stRealPositive +
r'(,\s*' + stRealPositive +
r')*'
5703 stComplexList = stComplex +
r'(,\s*' + stComplex +
r')*'
5705 reReal = QRegExp( stReal +
r'|^$')
5706 reRealPositive = QRegExp( stRealPositive +
r'|^$')
5707 reRealPositiveInf = QRegExp( stRealPositive +
r'|^$|inf|Inf')
5708 reComplex = QRegExp( stComplex +
r'|^$')
5709 reRealList = QRegExp( stRealList +
r'|^$' )
5710 reRealPositiveList = QRegExp( stRealPositiveList +
r'|^$' )
5711 reComplexList = QRegExp( stComplexList +
r'|^$' )
5721 app = QApplication(QtArgs)
5722 app.setOrganizationName(
"UPC")
5723 app.setOrganizationDomain(
"http://www.tsc.upc.edu/hfs; http://www.tsc.upc.edu/antennalab")
5724 app.setApplicationName(applicationName)
5725 app.setWindowIcon(QIcon(
":/icon/icons/icon_Spar-5.png"))