class SimulatorDialog(tk.Toplevel): def __init__(self, parent): tk.Toplevel.__init__(self, parent.parent) self.parent=parent self.withdraw() self.title('Simulation') self.img = tk.PhotoImage(file=SignalIntegrity.App.IconsBaseDir+'AppIcon2.gif') self.tk.call('wm', 'iconphoto', self._w, self.img) self.protocol("WM_DELETE_WINDOW", self.onClosing) # the Doers - the holder of the commands, menu elements, toolbar elements, and key bindings self.WaveformSaveDoer = Doer(self.onWriteSimulatorToFile).AddHelpElement('Control-Help:Save-Waveforms').AddToolTip('Save waveforms to files') # TODO: someday allow waveform reading self.WaveformReadDoer = Doer(self.onReadSimulatorFromFile).AddHelpElement('Control-Help:Read-Waveforms').Activate(False).AddToolTip('Read waveforms from files') self.Matplotlib2tikzDoer = Doer(self.onMatplotlib2TikZ).AddHelpElement('Control-Help:Simulator-output-to-LaTeX').AddToolTip('Output plots to LaTeX') # ------ self.SelectionsDisplayAllDoer = Doer(self.onSelectionsDisplayAll).AddHelpElement('Control-Help:Display-All').AddToolTip('Display all waveforms') self.SelectionsDisplayNoneDoer = Doer(self.onSelectionsDisplayNone).AddHelpElement('Control-Help:Display-None').AddToolTip('Turn off display of all waveforms') self.SelectionsToggleAllDoer = Doer(self.onSelectionsToggle).AddHelpElement('Control-Help:Toggle-Selections').AddToolTip('Toggle all waveform display') # ------ self.CalculationPropertiesDoer = Doer(self.onCalculationProperties).AddHelpElement('Control-Help:Calculation-Properties').AddToolTip('Edit calculation properties') self.ExamineTransferMatricesDoer = Doer(self.onExamineTransferMatrices).AddHelpElement('Control-Help:View-Transfer-Parameters').AddToolTip('View transfer parameters') self.SimulateDoer = Doer(self.parent.parent.onCalculate).AddHelpElement('Control-Help:Recalculate').AddToolTip('Recalculate simulation') # ------ self.ShowGridsDoer = Doer(self.onShowGrids).AddHelpElement('Control-Help:Show-Grids').AddToolTip('Show grids in plots') self.ViewTimeDomainDoer = Doer(self.onViewTimeDomain).AddHelpElement('Control-Help:View-Time-domain').AddToolTip('View time-domain waveforms') self.LogScaleDoer = Doer(self.onLogScale).AddHelpElement('Control-Help:Sim-Log-Scale').AddToolTip('Show frequency plots log scale') self.ViewSpectralContentDoer = Doer(self.onViewSpectralContent).AddHelpElement('Control-Help:View-Spectral-Content').AddToolTip('View spectral content of waveforms') self.ViewSpectralDensityDoer = Doer(self.onViewSpectralDensity).AddHelpElement('Control-Help:View-Spectral-Density').AddToolTip('View spectral density of waveforms') # ------ self.HelpDoer = Doer(self.onHelp).AddHelpElement('Control-Help:Simulator-Open-Help-File').AddToolTip('Open the help system in a browser') self.ControlHelpDoer = Doer(self.onControlHelp).AddHelpElement('Control-Help:Simulator-Control-Help').AddToolTip('Get help on a control') self.PreferencesDoer=Doer(self.onPreferences).AddHelpElement('Control-Help:Simulator-Preferences').AddToolTip('Edit the preferences') # ------ self.EscapeDoer = Doer(self.onEscape).AddKeyBindElement(self,'<Escape>').DisableHelp() # The menu system TheMenu=tk.Menu(self) self.TheMenu=TheMenu self.config(menu=TheMenu) FileMenu=tk.Menu(self) TheMenu.add_cascade(label='File',menu=FileMenu,underline=0) self.WaveformSaveDoer.AddMenuElement(FileMenu,label="Save Waveforms",underline=0) self.WaveformReadDoer.AddMenuElement(FileMenu,label="Read Waveforms",underline=0) FileMenu.add_separator() self.Matplotlib2tikzDoer.AddMenuElement(FileMenu,label='Output to LaTeX (TikZ)',underline=10) # ------ self.SelectionMenu=tk.Menu(self) TheMenu.add_cascade(label='Selection',menu=self.SelectionMenu,underline=0) self.SelectionsDisplayAllDoer.AddMenuElement(self.SelectionMenu,label='Display All',underline=8) self.SelectionsDisplayNoneDoer.AddMenuElement(self.SelectionMenu,label='Dispay None',underline=7) self.SelectionsToggleAllDoer.AddMenuElement(self.SelectionMenu,label='Toggle All',underline=0) self.SelectionMenu.add_separator() # ------ CalcMenu=tk.Menu(self) TheMenu.add_cascade(label='Calculate',menu=CalcMenu,underline=0) self.CalculationPropertiesDoer.AddMenuElement(CalcMenu,label='Calculation Properties',underline=12) self.ExamineTransferMatricesDoer.AddMenuElement(CalcMenu,label='View Transfer Parameters',underline=0) CalcMenu.add_separator() self.SimulateDoer.AddMenuElement(CalcMenu,label='Recalculate',underline=0) # ------ ViewMenu=tk.Menu(self) TheMenu.add_cascade(label='View',menu=ViewMenu,underline=0) self.ShowGridsDoer.AddCheckButtonMenuElement(ViewMenu,label='Show Grids',underline=5) self.ShowGridsDoer.Set(SignalIntegrity.App.Preferences['Appearance.GridsOnPlots']) self.ViewTimeDomainDoer.AddCheckButtonMenuElement(ViewMenu,label='View Time-domain',underline=5) self.ViewTimeDomainDoer.Set(True) self.LogScaleDoer.AddCheckButtonMenuElement(ViewMenu,label='Log Frequency Scale',underline=0) self.LogScaleDoer.Set(SignalIntegrity.App.Preferences['SParameterProperties.Plot.LogScale']) self.ViewSpectralContentDoer.AddCheckButtonMenuElement(ViewMenu,label='View Spectral Content',underline=14) self.ViewSpectralDensityDoer.AddCheckButtonMenuElement(ViewMenu,label='View Spectral Density',underline=14) # ------ HelpMenu=tk.Menu(self) TheMenu.add_cascade(label='Help',menu=HelpMenu,underline=0) self.HelpDoer.AddMenuElement(HelpMenu,label='Open Help File',underline=0) self.ControlHelpDoer.AddMenuElement(HelpMenu,label='Control Help',underline=0) self.PreferencesDoer.AddMenuElement(HelpMenu,label='Preferences',underline=0) # The Toolbar ToolBarFrame = tk.Frame(self) ToolBarFrame.pack(side=tk.TOP,fill=tk.X,expand=tk.NO) iconsdir=SignalIntegrity.App.IconsDir+'' self.WaveformReadDoer.AddToolBarElement(ToolBarFrame,iconfile=iconsdir+'document-open-2.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) self.WaveformSaveDoer.AddToolBarElement(ToolBarFrame,iconfile=iconsdir+'document-save-2.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) tk.Frame(self,height=2,bd=2,relief=tk.RAISED).pack(side=tk.LEFT,fill=tk.X,padx=5,pady=5) self.CalculationPropertiesDoer.AddToolBarElement(ToolBarFrame,iconfile=iconsdir+'tooloptions.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) self.SimulateDoer.AddToolBarElement(ToolBarFrame,iconfile=iconsdir+'system-run-3.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) tk.Frame(ToolBarFrame,height=2,bd=2,relief=tk.RAISED).pack(side=tk.LEFT,fill=tk.X,padx=5,pady=5) self.HelpDoer.AddToolBarElement(ToolBarFrame,iconfile=iconsdir+'help-contents-5.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) self.ControlHelpDoer.AddToolBarElement(ToolBarFrame,iconfile=iconsdir+'help-3.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) self.statusbar=StatusBar(self) self.statusbar.pack(side=tk.TOP,fill=tk.X,expand=tk.NO) labelFrame = tk.Frame(self) labelFrame.pack(side=tk.TOP,fill=tk.X,expand=tk.NO) self.plotLabel = tk.Label(labelFrame,fg='black') self.plotLabel.pack(fill=tk.X) plotWidth=SignalIntegrity.App.Preferences['Appearance.PlotWidth'] plotHeight=SignalIntegrity.App.Preferences['Appearance.PlotHeight'] plotDPI=SignalIntegrity.App.Preferences['Appearance.PlotDPI'] self.f = Figure(figsize=(plotWidth,plotHeight), dpi=plotDPI) self.plt = self.f.add_subplot(111) self.plt.set_xlabel('time (ns)') self.plt.set_ylabel('amplitude') self.waveformList=None self.waveformNamesList=None self.canvas = FigureCanvasTkAgg(self.f, master=self) #canvas.show() self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=tk.YES) toolbar = NavigationToolbar2Tk( self.canvas, self ) toolbar.update() toolbar.pan() self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) controlsFrame = tk.Frame(self) tk.Button(controlsFrame,text='autoscale',command=self.onAutoscale).pack(side=tk.LEFT,expand=tk.NO,fill=tk.X) controlsFrame.pack(side=tk.TOP,fill=tk.X,expand=tk.NO) try: try: from tikzplotlib import save as tikz_save except: try: from matplotlib2tikz import save as tikz_save except: self.Matplotlib2tikzDoer.Activate(False) except: self.Matplotlib2tikzDoer.Activate(False) self.ExamineTransferMatricesDoer.Activate(False) self.SimulateDoer.Activate(False) self.ZoomsInitialized=False self.geometry("%+d%+d" % (self.parent.parent.root.winfo_x()+self.parent.parent.root.winfo_width()/2-self.winfo_width()/2, self.parent.parent.root.winfo_y()+self.parent.parent.root.winfo_height()/2-self.winfo_height()/2)) self.lift() self.attributes('-topmost',True) self.after_idle(self.attributes,'-topmost',False) def onXLimitChange(self,ax): xlim=ax.get_xlim() self.minx=xlim[0] self.maxx=xlim[1] def onYLimitChange(self,ax): ylim=ax.get_ylim() self.miny=ylim[0] self.maxy=ylim[1] def onClosing(self): self.withdraw() self.destroy() def destroy(self): tk.Toplevel.withdraw(self) tk.Toplevel.destroy(self) def onAutoscale(self): self.plt.autoscale(True) self.f.canvas.draw() def PlotWaveformsFrequencyContent(self,density=False): self.lift(self.parent.parent) self.plt.cla() if not SignalIntegrity.App.Preferences['Appearance.PlotCursorValues']: self.plt.format_coord = lambda x, y: '' if not self.waveformList == None: self.plt.autoscale(False) self.frequencyContentList=[wf.FrequencyContent().LimitEndFrequency(SignalIntegrity.App.Project['CalculationProperties.EndFrequency']) for wf in self.waveformList] minf=None maxf=None for wfi in range(len(self.waveformList)): fc=self.frequencyContentList[wfi] fcFrequencies=fc.Frequencies() if len(fcFrequencies)==0: continue fcValues=fc.Values('dBm') fcName=str(self.waveformNamesList[wfi]) minf=fcFrequencies[0] if minf is None else min(minf,fcFrequencies[0]) maxf=fcFrequencies[-1] if maxf is None else max(maxf,fcFrequencies[-1]) freqLabel='Hz' freqLabelDivisor=1. if not self.waveformList is None: if (not minf is None) and (not maxf is None): durLabelFrequency=(maxf-minf) freqLabel=ToSI(durLabelFrequency,'Hz')[-3:] freqLabelDivisor=FromSI('1. '+freqLabel,'Hz') minf=minf/freqLabelDivisor maxf=maxf/freqLabelDivisor if not self.ZoomsInitialized: self.minx=minf self.maxx=maxf if self.LogScaleDoer.Bool(): if self.minx <= 0.: if max(fcFrequencies)>0: for value in fcFrequencies: if value>0.: self.minx=value/freqLabelDivisor break if self.minx != None: self.plt.set_xlim(left=self.minx) if self.maxx != None: self.plt.set_xlim(right=self.maxx) if density: self.plotLabel.config(text='Spectral Density') self.plt.set_ylabel('magnitude (dBm/'+freqLabel+')',fontsize=10) else: self.plotLabel.config(text='Spectral Content') self.plt.set_ylabel('magnitude (dBm)',fontsize=10) minv=None maxv=None minvStd=None for wfi in range(len(self.frequencyContentList)): fc=self.frequencyContentList[wfi] fcFrequencies=fc.Frequencies(freqLabelDivisor) if len(fcFrequencies)==0: continue if density: adder=10.*math.log10(freqLabelDivisor) fcValues=[v+adder for v in fc.Values('dBmPerHz')] else: fcValues=fc.Values('dBm') minv=min(fcValues) if minv is None else min(minv,min(fcValues)) maxv=max(fcValues) if maxv is None else max(maxv,max(fcValues)) minvStd=mean(fcValues)-0.5*std(fcValues) if minvStd is None else min(minvStd,mean(fcValues)-0.5*std(fcValues)) fcName=str(self.waveformNamesList[wfi]) fcColor=self.waveformColorIndexList[wfi] if self.LogScaleDoer.Bool(): self.plt.semilogx(fcFrequencies,fcValues,label=fcName,c=fcColor) else: self.plt.plot(fcFrequencies,fcValues,label=fcName,c=fcColor) if minv != None or minvStd != None: minv = max(minv,minvStd) self.plt.set_xlabel('frequency ('+freqLabel+')',fontsize=10) self.plt.legend(loc='upper right',labelspacing=0.1) if not self.ZoomsInitialized: self.miny=minv self.maxy=maxv if self.miny != None: self.plt.set_ylim(bottom=self.miny) if self.maxy != None: self.plt.set_ylim(top=self.maxy) if self.ShowGridsDoer.Bool(): self.plt.grid(True, 'both') self.ZoomsInitialized=True self.f.canvas.draw() self.plt.callbacks.connect('xlim_changed', self.onXLimitChange) self.plt.callbacks.connect('ylim_changed', self.onYLimitChange) return self def UpdateWaveforms(self,waveformList, waveformNamesList): self.totalwaveformList=waveformList self.totalwaveformNamesList=waveformNamesList # ------ self.SelectionDoerList = [Doer(lambda x=s: self.onSelection(x)) for s in range(len(self.totalwaveformNamesList))] # ------ # ------ self.SelectionMenu.delete(5, tk.END) for s in range(len(self.totalwaveformNamesList)): self.SelectionDoerList[s].AddCheckButtonMenuElement(self.SelectionMenu,label=self.totalwaveformNamesList[s]) self.SelectionDoerList[s].Set(True) self.TheMenu.entryconfigure('Selection', state= tk.DISABLED if len(self.totalwaveformNamesList) <= 1 else tk.ACTIVE) # ------ self.onSelection() return self def onSelectionsDisplayAll(self): for sd in self.SelectionDoerList: sd.Set(True) self.onSelection() def onSelectionsDisplayNone(self): for sd in self.SelectionDoerList: sd.Set(False) self.onSelection() def onSelectionsToggle(self): for sd in self.SelectionDoerList: sd.Set(not sd.Bool()) self.onSelection() def onSelection(self,x=None): self.waveformList=[] self.waveformNamesList=[] self.waveformColorIndexList=[] colors=matplotlib.pyplot.rcParams['axes.prop_cycle'].by_key()['color'] for si in range(len(self.SelectionDoerList)): if self.SelectionDoerList[si].Bool(): self.waveformList.append(self.totalwaveformList[si]) self.waveformNamesList.append(self.totalwaveformNamesList[si]) self.waveformColorIndexList.append(colors[si%len(colors)]) if len(self.waveformList) == 1: self.statusbar.set(ToSI(self.waveformList[0].td.K,'Pts')+' starting at '+ToSI(self.waveformList[0].td.H,'s')+' at '+ ToSI(self.waveformList[0].td.Fs,'S/s')+' (T = '+ToSI(1./self.waveformList[0].td.Fs,'s')+')') elif len(self.waveformList) == 0: self.statusbar.set('No Waveforms') else: self.statusbar.set('Multiple Waveforms') if self.ViewTimeDomainDoer.Bool(): self.PlotWaveformsTimeDomain() elif self.ViewSpectralContentDoer.Bool(): self.PlotWaveformsFrequencyContent(density=False) elif self.ViewSpectralDensityDoer.Bool(): self.PlotWaveformsFrequencyContent(density=True) return self def onShowGrids(self): SignalIntegrity.App.Preferences['Appearance.GridsOnPlots']=self.ShowGridsDoer.Bool() SignalIntegrity.App.Preferences.SaveToFile() self.onSelection() def onLogScale(self): SignalIntegrity.App.Preferences['SParameterProperties.Plot.LogScale']=self.LogScaleDoer.Bool() SignalIntegrity.App.Preferences.SaveToFile() self.onSelection() def onViewTimeDomain(self): self.ZoomsInitialized=False self.ViewSpectralDensityDoer.Set(False) self.ViewSpectralContentDoer.Set(False) self.PlotWaveformsTimeDomain() def onViewSpectralContent(self): self.ZoomsInitialized=False self.ViewTimeDomainDoer.Set(False) self.ViewSpectralDensityDoer.Set(False) self.PlotWaveformsFrequencyContent(density=False) def onViewSpectralDensity(self): self.ZoomsInitialized=False self.ViewTimeDomainDoer.Set(False) self.ViewSpectralContentDoer.Set(False) self.PlotWaveformsFrequencyContent(density=True) def PlotWaveformsTimeDomain(self): self.lift(self.parent.parent) self.plt.cla() self.plt.set_ylabel('amplitude',fontsize=10) self.plotLabel.config(text='Time-domain View') if not SignalIntegrity.App.Preferences['Appearance.PlotCursorValues']: self.plt.format_coord = lambda x, y: '' if not self.waveformList == None: self.plt.autoscale(False) mint=None maxt=None for wfi in range(len(self.waveformList)): wf=self.waveformList[wfi] wfTimes=wf.Times() if len(wfTimes)==0: continue wfValues=wf.Values() wfName=str(self.waveformNamesList[wfi]) mint=wfTimes[0] if mint is None else min(mint,wfTimes[0]) maxt=wfTimes[-1] if maxt is None else max(maxt,wfTimes[-1]) timeLabel='s' timeLabelDivisor=1. if not self.waveformList is None: if (not mint is None) and (not maxt is None): durLabelTime=(maxt-mint) timeLabel=ToSI(durLabelTime,'s')[-2:] timeLabelDivisor=FromSI('1. '+timeLabel,'s') mint=mint/timeLabelDivisor maxt=maxt/timeLabelDivisor if not self.ZoomsInitialized: self.minx=mint self.maxx=maxt if self.minx != None: self.plt.set_xlim(left=self.minx) if self.maxx != None: self.plt.set_xlim(right=self.maxx) minv=None maxv=None for wfi in range(len(self.waveformList)): wf=self.waveformList[wfi] wfTimes=wf.Times(timeLabelDivisor) if len(wfTimes)==0: continue wfValues=wf.Values() wfName=str(self.waveformNamesList[wfi]) wfColor=self.waveformColorIndexList[wfi] plotlog=False plotdB=False if plotlog: self.plt.semilogy(wfTimes,wf.Values('abs'),label=wfName,c=wfColor) elif plotdB: self.plt.plot(wfTimes,[max(20.*math.log10(abs(a)),-200.) for a in wf.Values('abs')],label=wfName,c=wfColor) else: self.plt.plot(wfTimes,wfValues,label=wfName,c=wfColor) minv=min(wfValues) if minv is None else min(minv,min(wfValues)) maxv=max(wfValues) if maxv is None else max(maxv,max(wfValues)) self.plt.set_xlabel('time ('+timeLabel+')',fontsize=10) self.plt.legend(loc='upper right',labelspacing=0.1) if not self.ZoomsInitialized: self.miny=minv self.maxy=maxv if self.miny != None: self.plt.set_ylim(bottom=self.miny) if self.maxy != None: self.plt.set_ylim(top=self.maxy) if self.ShowGridsDoer.Bool(): self.plt.grid(True) self.ZoomsInitialized=True self.f.canvas.draw() self.plt.callbacks.connect('xlim_changed', self.onXLimitChange) self.plt.callbacks.connect('ylim_changed', self.onYLimitChange) return self def onWriteSimulatorToFile(self): for wfi in range(len(self.waveformNamesList)): outputWaveformName=self.waveformNamesList[wfi] outputWaveform=self.waveformList[wfi] if self.parent.parent.fileparts.filename=='': filename=outputWaveformName else: filename=self.parent.parent.fileparts.filename+'_'+outputWaveformName preferLeCroyWaveforms=SignalIntegrity.App.Preferences['ProjectFiles.PreferSaveWaveformsLeCroyFormat'] if preferLeCroyWaveforms: filename=AskSaveAsFilename(parent=self,filetypes=[('LeCroy','.trc'),('waveform', '.txt')], defaultextension='.trc', initialdir=self.parent.parent.fileparts.AbsoluteFilePath(), initialfile=filename+'.trc') else: filename=AskSaveAsFilename(parent=self,filetypes=[('waveform', '.txt'),('LeCroy','.trc')], defaultextension='.txt', initialdir=self.parent.parent.fileparts.AbsoluteFilePath(), initialfile=filename+'.txt') if filename is None: continue outputWaveform.WriteToFile(filename) def onReadSimulatorFromFile(self): pass def onCalculationProperties(self): self.parent.parent.onCalculationProperties() def onExamineTransferMatrices(self): buttonLabelList=[[out+' due to '+inp for inp in self.parent.sourceNames] for out in self.parent.outputWaveformLabels] maxLength=len(max([item for sublist in buttonLabelList for item in sublist],key=len)) buttonLabelList=[[item.ljust(maxLength) for item in sublist] for sublist in buttonLabelList] sp=self.parent.transferMatrices.SParameters() SParametersDialog(self.parent.parent,sp, self.parent.parent.fileparts.FullFilePathExtension('s'+str(sp.m_P)+'p'), 'Transfer Parameters',buttonLabelList) def onMatplotlib2TikZ(self): if self.ViewTimeDomainDoer.Bool(): suffix='Waveforms' elif self.ViewSpectralContentDoer.Bool(): suffix='SpectralContent' elif self.ViewSpectralDensityDoer.Bool(): suffix='SpectralDensity' filename=AskSaveAsFilename(parent=self,filetypes=[('tex', '.tex')], defaultextension='.tex', initialdir=self.parent.parent.fileparts.AbsoluteFilePath(), initialfile=self.parent.parent.fileparts.filename+suffix+'.tex') if filename is None: return try: PlotTikZ(filename,self.f) except: messagebox.showerror('Export LaTeX','LaTeX could not be generated or written ') def onHelp(self): if Doer.helpKeys is None: messagebox.showerror('Help System','Cannot find or open this help element') return Doer.helpKeys.Open('sec:Simulator-Dialog') def onControlHelp(self): Doer.inHelp=True self.config(cursor='question_arrow') def onEscape(self): Doer.inHelp=False self.config(cursor='left_ptr') def onPreferences(self): if not hasattr(self, 'preferencesDialog'): self.preferencesDialog = SParameterViewerPreferencesDialog(self,SignalIntegrity.App.Preferences) if self.preferencesDialog == None: self.preferencesDialog= SParameterViewerPreferencesDialog(self,SignalIntegrity.App.Preferences) else: if not self.preferencesDialog.winfo_exists(): self.preferencesDialog=SParameterViewerPreferencesDialog(self,SignalIntegrity.App.Preferences)
class EyeDiagramDialog(tk.Toplevel): def __init__(self, parent, name): tk.Toplevel.__init__(self, parent.parent) self.parent=parent self.withdraw() self.name=name self.title('Eye Diagram: '+name) self.img = tk.PhotoImage(file=SignalIntegrity.App.IconsBaseDir+'AppIcon2.gif') self.tk.call('wm', 'iconphoto', self._w, self.img) self.protocol("WM_DELETE_WINDOW", self.onClosing) # the Doers - the holder of the commands, menu elements, toolbar elements, and key bindings self.EyeDiagramSaveDoer = Doer(self.onWriteImageToFile).AddHelpElement('Control-Help:Save-Eye-Diagram-Image').AddToolTip('Save images to files') # ------ self.CalculationPropertiesDoer = Doer(self.onCalculationProperties).AddHelpElement('Control-Help:Calculation-Properties').AddToolTip('Edit calculation properties') self.PropertiesDoer=Doer(self.onProperties).AddHelpElement('Control-Help:Eye-Diagram-Properties').AddToolTip('Edit eye diagram properties') self.SimulateDoer = Doer(self.onCalculate).AddHelpElement('Control-Help:Recalculate').AddToolTip('Recalculate simulation') self.OnlyRecalculateEyeDoer =Doer(self.onRecalculateEyeDiagram).AddHelpElement('Control-Help:Only-Recalculate-Eye-Diagram').AddToolTip('Recalculate eye diagram') # ------ self.EyeMeasurementsDoer = Doer(self.onEyeMeasurements).AddHelpElement('Control-Help:Eye-Measurements').AddToolTip('View the eye measurements') self.BathtubCurveDoer = Doer(self.onBathtubCurve).AddHelpElement('Control-Help:Bathtub-Curve').AddToolTip('View the bathtub curves') # ------ self.HelpDoer = Doer(self.onHelp).AddHelpElement('Control-Help:Eye-Diagram-Open-Help-File').AddToolTip('Open the help system in a browser') self.ControlHelpDoer = Doer(self.onControlHelp).AddHelpElement('Control-Help:Eye-Diagram-Control-Help').AddToolTip('Get help on a control') # ------ self.EscapeDoer = Doer(self.onEscape).AddKeyBindElement(self,'<Escape>').DisableHelp() # The menu system TheMenu=tk.Menu(self) self.TheMenu=TheMenu self.config(menu=TheMenu) FileMenu=tk.Menu(self) TheMenu.add_cascade(label='File',menu=FileMenu,underline=0) self.EyeDiagramSaveDoer.AddMenuElement(FileMenu,label="Save Image to File",underline=0) FileMenu.add_separator() # ------ CalcMenu=tk.Menu(self) TheMenu.add_cascade(label='Calculate',menu=CalcMenu,underline=0) self.CalculationPropertiesDoer.AddMenuElement(CalcMenu,label='Calculation Properties',underline=0) self.PropertiesDoer.AddMenuElement(CalcMenu,label='Eye Diagram Properties',underline=0) CalcMenu.add_separator() self.SimulateDoer.AddMenuElement(CalcMenu,label='Recalculate',underline=0) self.OnlyRecalculateEyeDoer.AddMenuElement(CalcMenu,label='Only Recalculate Eye Diagram',underline=0) # ------ ViewMenu=tk.Menu(self) TheMenu.add_cascade(label='View',menu=ViewMenu,underline=0) self.EyeMeasurementsDoer.AddMenuElement(ViewMenu,label='Eye Measurements',underline=0) self.BathtubCurveDoer.AddMenuElement(ViewMenu,label='Bathtub Curve',underline=0) # ------ HelpMenu=tk.Menu(self) TheMenu.add_cascade(label='Help',menu=HelpMenu,underline=0) self.HelpDoer.AddMenuElement(HelpMenu,label='Open Help File',underline=0) self.ControlHelpDoer.AddMenuElement(HelpMenu,label='Control Help',underline=0) # The Toolbar ToolBarFrame = tk.Frame(self) ToolBarFrame.pack(side=tk.TOP,fill=tk.X,expand=tk.NO) iconsdir=SignalIntegrity.App.IconsDir+'' self.EyeDiagramSaveDoer.AddToolBarElement(ToolBarFrame,iconfile=iconsdir+'document-save-2.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) tk.Frame(self,height=2,bd=2,relief=tk.RAISED).pack(side=tk.LEFT,fill=tk.X,padx=5,pady=5) self.CalculationPropertiesDoer.AddToolBarElement(ToolBarFrame,iconfile=iconsdir+'tooloptions.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) self.SimulateDoer.AddToolBarElement(ToolBarFrame,iconfile=iconsdir+'system-run-3.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) self.OnlyRecalculateEyeDoer.AddToolBarElement(ToolBarFrame,iconfile=iconsdir+'eye.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) tk.Frame(ToolBarFrame,height=2,bd=2,relief=tk.RAISED).pack(side=tk.LEFT,fill=tk.X,padx=5,pady=5) self.HelpDoer.AddToolBarElement(ToolBarFrame,iconfile=iconsdir+'help-contents-5.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) self.ControlHelpDoer.AddToolBarElement(ToolBarFrame,iconfile=iconsdir+'help-3.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) self.eyeStatus=StatusBar(self) self.eyeStatus.pack(side=tk.TOP,fill=tk.X,expand=tk.NO) self.eyeFrame=tk.Frame(self, relief=tk.RIDGE, borderwidth=5) self.eyeCanvas=tk.Canvas(self.eyeFrame,width=0,height=0) self.eyeCanvas.pack() self.eyeFrame.pack(side=tk.TOP,fill=tk.BOTH,expand=tk.YES) # status bar self.statusbar=StatusBar(self) self.statusbar.pack(side=tk.BOTTOM,fill=tk.X,expand=tk.NO) self.eyeDiagram=EyeDiagram(self,self.name) self.geometry("%+d%+d" % (self.parent.parent.root.winfo_x()+self.parent.parent.root.winfo_width()/2-self.winfo_width()/2, self.parent.parent.root.winfo_y()+self.parent.parent.root.winfo_height()/2-self.winfo_height()/2)) # Allow resizing of the image self.knowDelta=False self.deltaWidth=0 self.deltaHeight=0 self.bind('<Configure>',self.onResize) self.bind('<FocusIn>',self.onFocus) def onFocus(self,event): if event.widget == self: if hasattr(self,'eyeDiagramMeasurementsDialog'): if self.eyeDiagramMeasurementsDialog != None: if self.eyeDiagramMeasurementsDialog.winfo_exists(): self.eyeDiagramMeasurementsDialog.lift() self.lift() def onResize(self,event): if not self.knowDelta: self.adjusting=False self.adjustCount=0 self.deltaWidth=4 self.deltaHeight=4 self.knowDelta=True else: if self.adjusting: self.adjustCount+=1 else: self.adjusting=True self.adjustCount=0 self.after(100,self.AdjustImage) def AdjustImage(self): if self.adjustCount != 0: self.adjustCount=0 self.after(100,self.AdjustImage) else: if hasattr(self, 'eyeImage'): newImageWidth=self.eyeCanvas.winfo_width()-self.deltaWidth newImageHeight=self.eyeCanvas.winfo_height()-self.deltaHeight if (newImageWidth != self.eyeImage.width()) or (newImageHeight != self.eyeImage.height()): if (newImageHeight > 0) and (newImageWidth > 0): img=self.eyeDiagram.img.resize((newImageWidth,newImageHeight)) self.eyeImage=ImageTk.PhotoImage(img) self.eyeCanvas.create_image(newImageWidth/2,newImageHeight/2,image=self.eyeImage) self.adjusting=False def onClosing(self): self.withdraw() self.destroy() def destroy(self): tk.Toplevel.withdraw(self) tk.Toplevel.destroy(self) def onWriteImageToFile(self): if self.parent.parent.fileparts.filename=='': filename=self.name else: filename=self.parent.parent.fileparts.filename+'_'+self.name filename=AskSaveAsFilename(parent=self,filetypes=[('Images',('.png','.bmp','.jpg','.gif','.tiff'))], defaultextension='.png', initialdir=self.parent.parent.fileparts.AbsoluteFilePath(), initialfile=filename+'.png') if filename is None: return self.eyeDiagram.img.save(filename) def onCalculate(self): self.statusbar.set('Calculation Started') self.parent.parent.onCalculate() def onRecalculateEyeDiagram(self): self.statusbar.set('Calculation Started') import SignalIntegrity.Lib as si progressDialog=ProgressDialog(self.parent.parent,"Eye Diagram Processing",self,self.CalculateEyeDiagram) try: progressDialog.GetResult() except si.SignalIntegrityException as e: messagebox.showerror('Eye Diagram',e.parameter+': '+e.message) return def onCalculationProperties(self): self.parent.parent.onCalculationProperties() def onHelp(self): if Doer.helpKeys is None: messagebox.showerror('Help System','Cannot find or open this help element') return Doer.helpKeys.Open('sec:Eye-Diagram-Dialog') def onControlHelp(self): Doer.inHelp=True self.config(cursor='question_arrow') def onEscape(self): Doer.inHelp=False self.config(cursor='left_ptr') def onProperties(self): self.eyeArgs['Config'].onConfiguration(self) def SetEyeArgs(self,eyeArgs): self.eyeArgs=eyeArgs return self def InstallCallback(self,Callback=None): self.callback=Callback def RemoveCallback(self): self.callback=None def CalculateEyeDiagram(self): self.eyeDiagram.CalculateEyeDiagram(self.parent.parent.fileparts.FileNameTitle(),self.callback) if hasattr(self,'eyeDiagramMeasurementsDialog'): if self.eyeDiagramMeasurementsDialog != None: if self.eyeDiagramMeasurementsDialog.winfo_exists(): self.EyeDiagramMeasurementsDialog().UpdateMeasurements(self.eyeDiagram.measDict) if hasattr(self, 'bathtubCurveDialog'): if self.bathtubCurveDialog != None: if self.bathtubCurveDialog.winfo_exists(): self.BathtubCurveDialog().UpdateMeasurements(self.eyeDiagram.measDict) self.EyeMeasurementsDoer.Activate(not self.eyeDiagram.measDict is None) self.BathtubCurveDoer.Activate((not self.eyeDiagram.measDict is None) and ('Bathtub' in self.eyeDiagram.measDict.keys())) self.eyeCanvas.pack_forget() config=self.eyeArgs['Config'] R=config['Rows']; C=config['Columns'] C=int(C*config['ScaleX']/100.*config['UI']); R=int(R*config['ScaleY']/100.) self.eyeCanvas=tk.Canvas(self.eyeFrame,width=C,height=R) if not self.eyeDiagram.img is None: self.eyeStatus.set(ToSI(int(self.eyeDiagram.prbswf.td.K/self.eyeDiagram.prbswf.td.Fs*self.eyeDiagram.baudrate),'UI')+' at '+ToSI(self.eyeDiagram.baudrate,'Baud')) self.eyeImage=ImageTk.PhotoImage(self.eyeDiagram.img) self.eyeCanvas.create_image(C/2,R/2,image=self.eyeImage) self.eyeCanvas.pack(expand=tk.YES,fill=tk.BOTH) self.statusbar.set('Calculation complete') else: self.statusbar.set('Calculation failed or aborted') self.eyeStatus.set('No Eye') def EyeDiagramMeasurementsDialog(self): if not hasattr(self,'eyeDiagramMeasurementsDialog'): self.eyeDiagramMeasurementsDialog=EyeDiagramMeasurementsDialog(self,self.name) if self.eyeDiagramMeasurementsDialog == None: self.eyeDiagramMeasurementsDialog=EyeDiagramMeasurementsDialog(self,self.name) else: if not self.eyeDiagramMeasurementsDialog.winfo_exists(): self.eyeDiagramMeasurementsDialog=EyeDiagramMeasurementsDialog(self,self.name) return self.eyeDiagramMeasurementsDialog def UpdateWaveforms(self): self.eyeDiagram.prbswf=self.eyeArgs['Waveform'] self.eyeDiagram.baudrate=self.eyeArgs['BaudRate'] self.eyeDiagram.config=self.eyeArgs['Config'] self.CalculateEyeDiagram() self.deiconify() self.lift() return self def BathtubCurveDialog(self): if not hasattr(self,'bathtubCurveDialog'): self.bathtubCurveDialog=BathtubCurveDialog(self,self.name) if self.bathtubCurveDialog == None: self.bathtubCurveDialog=BathtubCurveDialog(self,self.name) else: if not self.bathtubCurveDialog.winfo_exists(): self.bathtubCurveDialog=BathtubCurveDialog(self,self.name) return self.bathtubCurveDialog def onBathtubCurve(self): windowOpen=hasattr(self,'bathtubCurveDialog')\ and (self.bathtubCurveDialog != None)\ and bool(self.bathtubCurveDialog.winfo_exists()) if not windowOpen: self.BathtubCurveDialog().UpdateMeasurements(self.eyeDiagram.measDict) self.BathtubCurveDialog().lift() def onEyeMeasurements(self): windowOpen=hasattr(self,'eyeDiagramMeasurementsDialog')\ and (self.eyeDiagramMeasurementsDialog != None)\ and bool(self.eyeDiagramMeasurementsDialog.winfo_exists()) if not windowOpen: self.EyeDiagramMeasurementsDialog().UpdateMeasurements(self.eyeDiagram.measDict) self.EyeDiagramMeasurementsDialog().lift()
class SimulatorDialog(tk.Toplevel): def __init__(self, parent): tk.Toplevel.__init__(self, parent.parent) self.parent = parent self.withdraw() self.title('Simulation') self.img = tk.PhotoImage(file=SignalIntegrity.App.IconsBaseDir + 'AppIcon2.gif') self.tk.call('wm', 'iconphoto', self._w, self.img) self.protocol("WM_DELETE_WINDOW", self.onClosing) # the Doers - the holder of the commands, menu elements, toolbar elements, and key bindings self.WaveformSaveDoer = Doer( self.onWriteSimulatorToFile).AddHelpElement( 'Control-Help:Save-Waveforms') # TODO: someday allow waveform reading self.WaveformReadDoer = Doer( self.onReadSimulatorFromFile).AddHelpElement( 'Control-Help:Read-Waveforms').Activate(False) self.Matplotlib2tikzDoer = Doer(self.onMatplotlib2TikZ).AddHelpElement( 'Control-Help:Output-to-LaTeX') # ------ self.CalculationPropertiesDoer = Doer( self.onCalculationProperties).AddHelpElement( 'Control-Help:Calculation-Properties') self.ExamineTransferMatricesDoer = Doer( self.onExamineTransferMatrices).AddHelpElement( 'Control-Help:View-Transfer-Parameters') self.SimulateDoer = Doer( self.parent.parent.onCalculate).AddHelpElement( 'Control-Help:Recalculate') # ------ self.viewTimeDomain = tk.BooleanVar() self.viewTimeDomain.set(True) self.viewTimeDomainDoer = Doer(self.onViewTimeDomain) self.viewSpectralContent = tk.BooleanVar() self.viewSpectralContentDoer = Doer(self.onViewSpectralContent) self.viewSpectralDensity = tk.BooleanVar() self.viewSpectralDensityDoer = Doer(self.onViewSpectralDensity) # ------ self.HelpDoer = Doer(self.onHelp).AddHelpElement( 'Control-Help:Simulator-Open-Help-File') self.ControlHelpDoer = Doer(self.onControlHelp).AddHelpElement( 'Control-Help:Simulator-Control-Help') self.PreferencesDoer = Doer(self.onPreferences).AddHelpElement( 'Control-Help:Simulator-Preferences') # ------ self.EscapeDoer = Doer(self.onEscape).AddKeyBindElement( self, '<Escape>').DisableHelp() # The menu system TheMenu = tk.Menu(self) self.config(menu=TheMenu) FileMenu = tk.Menu(self) TheMenu.add_cascade(label='File', menu=FileMenu, underline=0) self.WaveformSaveDoer.AddMenuElement(FileMenu, label="Save Waveforms", underline=0) self.WaveformReadDoer.AddMenuElement(FileMenu, label="Read Waveforms", underline=0) FileMenu.add_separator() self.Matplotlib2tikzDoer.AddMenuElement(FileMenu, label='Output to LaTeX (TikZ)', underline=10) # ------ CalcMenu = tk.Menu(self) TheMenu.add_cascade(label='Calculate', menu=CalcMenu, underline=0) self.CalculationPropertiesDoer.AddMenuElement( CalcMenu, label='Calculation Properties', underline=12) self.ExamineTransferMatricesDoer.AddMenuElement( CalcMenu, label='View Transfer Parameters', underline=0) CalcMenu.add_separator() self.SimulateDoer.AddMenuElement(CalcMenu, label='Recalculate', underline=0) # ------ ViewMenu = tk.Menu(self) TheMenu.add_cascade(label='View', menu=ViewMenu, underline=0) self.viewTimeDomainDoer.AddCheckButtonMenuElement( ViewMenu, label='View Time-domain', underline=5, onvalue=True, offvalue=False, variable=self.viewTimeDomain) self.viewSpectralContentDoer.AddCheckButtonMenuElement( ViewMenu, label='View Spectral Content', underline=14, onvalue=True, offvalue=False, variable=self.viewSpectralContent) self.viewSpectralDensityDoer.AddCheckButtonMenuElement( ViewMenu, label='View Spectral Density', underline=14, onvalue=True, offvalue=False, variable=self.viewSpectralDensity) # ------ HelpMenu = tk.Menu(self) TheMenu.add_cascade(label='Help', menu=HelpMenu, underline=0) self.HelpDoer.AddMenuElement(HelpMenu, label='Open Help File', underline=0) self.ControlHelpDoer.AddMenuElement(HelpMenu, label='Control Help', underline=0) self.PreferencesDoer.AddMenuElement(HelpMenu, label='Preferences', underline=0) # The Toolbar ToolBarFrame = tk.Frame(self) ToolBarFrame.pack(side=tk.TOP, fill=tk.X, expand=tk.NO) iconsdir = SignalIntegrity.App.IconsDir + '' self.WaveformReadDoer.AddToolBarElement( ToolBarFrame, iconfile=iconsdir + 'document-open-2.gif').Pack(side=tk.LEFT, fill=tk.NONE, expand=tk.NO) self.WaveformSaveDoer.AddToolBarElement( ToolBarFrame, iconfile=iconsdir + 'document-save-2.gif').Pack(side=tk.LEFT, fill=tk.NONE, expand=tk.NO) tk.Frame(self, height=2, bd=2, relief=tk.RAISED).pack(side=tk.LEFT, fill=tk.X, padx=5, pady=5) self.CalculationPropertiesDoer.AddToolBarElement( ToolBarFrame, iconfile=iconsdir + 'tooloptions.gif').Pack(side=tk.LEFT, fill=tk.NONE, expand=tk.NO) self.SimulateDoer.AddToolBarElement( ToolBarFrame, iconfile=iconsdir + 'system-run-3.gif').Pack(side=tk.LEFT, fill=tk.NONE, expand=tk.NO) tk.Frame(ToolBarFrame, height=2, bd=2, relief=tk.RAISED).pack(side=tk.LEFT, fill=tk.X, padx=5, pady=5) self.HelpDoer.AddToolBarElement( ToolBarFrame, iconfile=iconsdir + 'help-contents-5.gif').Pack(side=tk.LEFT, fill=tk.NONE, expand=tk.NO) self.ControlHelpDoer.AddToolBarElement(ToolBarFrame, iconfile=iconsdir + 'help-3.gif').Pack(side=tk.LEFT, fill=tk.NONE, expand=tk.NO) labelFrame = tk.Frame(self) labelFrame.pack(side=tk.TOP, fill=tk.X, expand=tk.NO) self.plotLabel = tk.Label(labelFrame, fg='black') self.plotLabel.pack(fill=tk.X) plotWidth = SignalIntegrity.App.Preferences['Appearance.PlotWidth'] plotHeight = SignalIntegrity.App.Preferences['Appearance.PlotHeight'] plotDPI = SignalIntegrity.App.Preferences['Appearance.PlotDPI'] self.f = Figure(figsize=(plotWidth, plotHeight), dpi=plotDPI) self.plt = self.f.add_subplot(111) self.plt.set_xlabel('time (ns)') self.plt.set_ylabel('amplitude') self.waveformList = None self.waveformNamesList = None self.canvas = FigureCanvasTkAgg(self.f, master=self) #canvas.show() self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=tk.YES) toolbar = NavigationToolbar2Tk(self.canvas, self) toolbar.update() toolbar.pan() self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) controlsFrame = tk.Frame(self) tk.Button(controlsFrame, text='autoscale', command=self.onAutoscale).pack(side=tk.LEFT, expand=tk.NO, fill=tk.X) controlsFrame.pack(side=tk.TOP, fill=tk.X, expand=tk.NO) try: try: from tikzplotlib import save as tikz_save except: try: from matplotlib2tikz import save as tikz_save except: self.Matplotlib2tikzDoer.Activate(False) except: self.Matplotlib2tikzDoer.Activate(False) self.ExamineTransferMatricesDoer.Activate(False) self.SimulateDoer.Activate(False) self.geometry( "%+d%+d" % (self.parent.parent.root.winfo_x() + self.parent.parent.root.winfo_width() / 2 - self.winfo_width() / 2, self.parent.parent.root.winfo_y() + self.parent.parent.root.winfo_height() / 2 - self.winfo_height() / 2)) def onClosing(self): self.withdraw() self.destroy() def destroy(self): tk.Toplevel.withdraw(self) tk.Toplevel.destroy(self) def onAutoscale(self): self.plt.autoscale(True) self.f.canvas.draw() def PlotWaveformsFrequencyContent(self, density=False): self.lift(self.parent.parent) self.plt.cla() import SignalIntegrity.Lib as si fd = si.fd.EvenlySpacedFrequencyList( SignalIntegrity.App.Project['CalculationProperties.EndFrequency'], SignalIntegrity.App. Project['CalculationProperties.FrequencyPoints']) if not SignalIntegrity.App.Preferences['Appearance.PlotCursorValues']: self.plt.format_coord = lambda x, y: '' if not self.waveformList == None: self.plt.autoscale(False) self.frequencyContentList = [ wf.FrequencyContent().LimitEndFrequency( SignalIntegrity.App. Project['CalculationProperties.EndFrequency']) for wf in self.waveformList ] minf = None maxf = None for wfi in range(len(self.waveformList)): fc = self.frequencyContentList[wfi] fcFrequencies = fc.Frequencies() if len(fcFrequencies) == 0: continue fcValues = fc.Values('dBm') fcName = str(self.waveformNamesList[wfi]) minf = fcFrequencies[0] if minf is None else min( minf, fcFrequencies[0]) maxf = fcFrequencies[-1] if maxf is None else max( maxf, fcFrequencies[-1]) freqLabel = 'Hz' freqLabelDivisor = 1. if not self.waveformList is None: if (not minf is None) and (not maxf is None): durLabelFrequency = (maxf - minf) freqLabel = ToSI(durLabelFrequency, 'Hz')[-3:] freqLabelDivisor = FromSI('1. ' + freqLabel, 'Hz') minf = minf / freqLabelDivisor maxf = maxf / freqLabelDivisor if not minf is None: self.plt.set_xlim(left=minf) if not maxf is None: self.plt.set_xlim(right=maxf) if density: self.plotLabel.config(text='Spectral Density') self.plt.set_ylabel('magnitude (dBm/' + freqLabel + ')', fontsize=10) else: self.plotLabel.config(text='Spectral Content') self.plt.set_ylabel('magnitude (dBm)', fontsize=10) minv = None maxv = None minvStd = None for wfi in range(len(self.frequencyContentList)): fc = self.frequencyContentList[wfi] fcFrequencies = fc.Frequencies(freqLabelDivisor) if len(fcFrequencies) == 0: continue if density: adder = 10. * math.log10(freqLabelDivisor) fcValues = [v + adder for v in fc.Values('dBmPerHz')] else: fcValues = fc.Values('dBm') minv = min(fcValues) if minv is None else min(minv, min(fcValues)) maxv = max(fcValues) if maxv is None else max(maxv, max(fcValues)) minvStd = mean( fcValues) - 0.5 * std(fcValues) if minvStd is None else min( minvStd, mean(fcValues) - 0.5 * std(fcValues)) fcName = str(self.waveformNamesList[wfi]) self.plt.plot(fcFrequencies, fcValues, label=fcName) minv = max(minv, minvStd) self.plt.set_xlabel('frequency (' + freqLabel + ')', fontsize=10) self.plt.legend(loc='upper right', labelspacing=0.1) self.plt.set_ylim(bottom=minv) self.plt.set_ylim(top=maxv) self.f.canvas.draw() return self def UpdateWaveforms(self, waveformList, waveformNamesList): self.waveformList = waveformList self.waveformNamesList = waveformNamesList if self.viewTimeDomain.get(): self.PlotWaveformsTimeDomain() elif self.viewSpectralContent.get(): self.PlotWaveformsFrequencyContent(density=False) elif self.viewSpectralDensity.get(): self.PlotWaveformsFrequencyContent(density=True) return self def onViewTimeDomain(self): self.viewSpectralDensity.set(False) self.viewSpectralContent.set(False) self.PlotWaveformsTimeDomain() def onViewSpectralContent(self): self.viewTimeDomain.set(False) self.viewSpectralDensity.set(False) self.PlotWaveformsFrequencyContent(density=False) def onViewSpectralDensity(self): self.viewTimeDomain.set(False) self.viewSpectralContent.set(False) self.PlotWaveformsFrequencyContent(density=True) def PlotWaveformsTimeDomain(self): self.lift(self.parent.parent) self.plt.cla() self.plt.set_ylabel('amplitude', fontsize=10) self.plotLabel.config(text='Time-domain View') if not SignalIntegrity.App.Preferences['Appearance.PlotCursorValues']: self.plt.format_coord = lambda x, y: '' if not self.waveformList == None: self.plt.autoscale(False) mint = None maxt = None for wfi in range(len(self.waveformList)): wf = self.waveformList[wfi] wfTimes = wf.Times() if len(wfTimes) == 0: continue wfValues = wf.Values() wfName = str(self.waveformNamesList[wfi]) mint = wfTimes[0] if mint is None else min(mint, wfTimes[0]) maxt = wfTimes[-1] if maxt is None else max(maxt, wfTimes[-1]) timeLabel = 's' timeLabelDivisor = 1. if not self.waveformList is None: if (not mint is None) and (not maxt is None): durLabelTime = (maxt - mint) timeLabel = ToSI(durLabelTime, 's')[-2:] timeLabelDivisor = FromSI('1. ' + timeLabel, 's') mint = mint / timeLabelDivisor maxt = maxt / timeLabelDivisor if not mint is None: self.plt.set_xlim(left=mint) if not maxt is None: self.plt.set_xlim(right=maxt) minv = None maxv = None for wfi in range(len(self.waveformList)): wf = self.waveformList[wfi] wfTimes = wf.Times(timeLabelDivisor) if len(wfTimes) == 0: continue wfValues = wf.Values() wfName = str(self.waveformNamesList[wfi]) plotlog = False plotdB = False if plotlog: self.plt.semilogy(wfTimes, wf.Values('abs'), label=wfName) elif plotdB: self.plt.plot(wfTimes, [ max(20. * math.log10(abs(a)), -200.) for a in wf.Values('abs') ], label=wfName) else: self.plt.plot(wfTimes, wfValues, label=wfName) minv = min(wfValues) if minv is None else min(minv, min(wfValues)) maxv = max(wfValues) if maxv is None else max(maxv, max(wfValues)) self.plt.set_xlabel('time (' + timeLabel + ')', fontsize=10) self.plt.legend(loc='upper right', labelspacing=0.1) self.plt.set_ylim(bottom=minv) self.plt.set_ylim(top=maxv) self.f.canvas.draw() return self def onWriteSimulatorToFile(self): for wfi in range(len(self.waveformNamesList)): outputWaveformName = self.waveformNamesList[wfi] outputWaveform = self.waveformList[wfi] if self.parent.parent.fileparts.filename == '': filename = outputWaveformName else: filename = self.parent.parent.fileparts.filename + '_' + outputWaveformName filename = AskSaveAsFilename( parent=self, filetypes=[('waveform', '.txt')], defaultextension='.txt', initialdir=self.parent.parent.fileparts.AbsoluteFilePath(), initialfile=filename + '.txt') if filename is None: continue outputWaveform.WriteToFile(filename) def onReadSimulatorFromFile(self): pass def onCalculationProperties(self): self.parent.parent.onCalculationProperties() def onExamineTransferMatrices(self): buttonLabelList = [[ out + ' due to ' + inp for inp in self.parent.sourceNames ] for out in self.parent.outputWaveformLabels] maxLength = len( max([item for sublist in buttonLabelList for item in sublist], key=len)) buttonLabelList = [[item.ljust(maxLength) for item in sublist] for sublist in buttonLabelList] sp = self.parent.transferMatrices.SParameters() SParametersDialog( self.parent.parent, sp, self.parent.parent.fileparts.FullFilePathExtension('s' + str(sp.m_P) + 'p'), 'Transfer Parameters', buttonLabelList) def onMatplotlib2TikZ(self): if self.viewTimeDomain.get(): suffix = 'Waveforms' elif self.viewSpectralContent.get(): suffix = 'SpectralContent' elif self.viewSpectralDensity.get(): suffix = 'SpectralDensity' filename = AskSaveAsFilename( parent=self, filetypes=[('tex', '.tex')], defaultextension='.tex', initialdir=self.parent.parent.fileparts.AbsoluteFilePath(), initialfile=self.parent.parent.fileparts.filename + suffix + '.tex') if filename is None: return try: PlotTikZ(filename, self.f) except: messagebox.showerror('Export LaTeX', 'LaTeX could not be generated or written ') def onHelp(self): if Doer.helpKeys is None: messagebox.showerror('Help System', 'Cannot find or open this help element') return Doer.helpKeys.Open('sec:Simulator-Dialog') def onControlHelp(self): Doer.inHelp = True self.config(cursor='question_arrow') def onEscape(self): Doer.inHelp = False self.config(cursor='left_ptr') def onPreferences(self): if not hasattr(self, 'preferencesDialog'): self.preferencesDialog = SParameterViewerPreferencesDialog( self, SignalIntegrity.App.Preferences) if self.preferencesDialog == None: self.preferencesDialog = SParameterViewerPreferencesDialog( self, SignalIntegrity.App.Preferences) else: if not self.preferencesDialog.winfo_exists(): self.preferencesDialog = SParameterViewerPreferencesDialog( self, SignalIntegrity.App.Preferences)
class SParametersDialog(tk.Toplevel): def __init__(self, parent,sp,filename=None,title=None,buttonLabels=None): tk.Toplevel.__init__(self, parent) self.parent=parent self.withdraw() self.fileparts=FileParts(filename) if title is None: if self.fileparts.filename =='': self.title('S-parameters') else: self.title('S-parameters: '+self.fileparts.FileNameTitle()) else: if filename is None: self.title(title) else: self.title(title+': '+self.fileparts.FileNameTitle()) img = tk.PhotoImage(file=SignalIntegrity.App.IconsBaseDir+'AppIcon2.gif') self.tk.call('wm', 'iconphoto', self._w, img) self.protocol("WM_DELETE_WINDOW", self.onClosing) self.variableLineWidth = tk.BooleanVar() self.showPassivityViolations = tk.BooleanVar() self.showCausalityViolations = tk.BooleanVar() self.showImpedance = tk.BooleanVar() self.logScale = tk.BooleanVar() # the Doers - the holder of the commands, menu elements, toolbar elements, and key bindings self.ReadSParametersFromFileDoer = Doer(self.onReadSParametersFromFile).AddKeyBindElement(self,'<Control-o>').AddHelpElement('Control-Help:Open-S-parameter-File') self.WriteSParametersToFileDoer = Doer(self.onWriteSParametersToFile).AddKeyBindElement(self,'<Control-s>').AddHelpElement('Control-Help:Save-S-parameter-File') self.Matplotlib2tikzDoer = Doer(self.onMatplotlib2TikZ) # ------ self.CalculationPropertiesDoer = Doer(self.onCalculationProperties).AddHelpElement('Control-Help:Calculation-Properties') self.ResampleDoer = Doer(self.onResample).AddHelpElement('Control-Help:Resample') self.EnforcePassivityDoer = Doer(self.onEnforcePassivity).AddHelpElement('Control-Help:Enforce-Passivity') self.EnforceCausalityDoer = Doer(self.onEnforceCausality).AddHelpElement('Control-Help:Enforce-Causality') self.WaveletDenoiseDoer = Doer(self.onWaveletDenoise).AddHelpElement('Control-Help:Wavelet-Denoise') # ------ self.HelpDoer = Doer(self.onHelp).AddHelpElement('Control-Help:Open-Help-File') self.ControlHelpDoer = Doer(self.onControlHelp).AddHelpElement('Control-Help:Control-Help') # ------ self.VariableLineWidthDoer = Doer(self.PlotSParameter).AddHelpElement('Control-Help:Variable-Line-Width') self.ShowPassivityViolationsDoer = Doer(self.PlotSParameter).AddHelpElement('Control-Help:Show-Passivity-Violations') self.ShowCausalityViolationsDoer = Doer(self.PlotSParameter).AddHelpElement('Control-Help:Show-Causality-Violations') self.ShowImpedanceDoer = Doer(self.PlotSParameter).AddHelpElement('Control-Help:Show-Impedance') self.LogScaleDoer = Doer(self.PlotSParameter).AddHelpElement('Control-Help:Log-Scale') # ------ self.EscapeDoer = Doer(self.onEscape).AddKeyBindElement(self,'<Escape>').DisableHelp() # The menu system TheMenu=tk.Menu(self) self.config(menu=TheMenu) # ------ FileMenu=tk.Menu(self) TheMenu.add_cascade(label='File',menu=FileMenu,underline=0) self.WriteSParametersToFileDoer.AddMenuElement(FileMenu,label="Save",accelerator='Ctrl+S',underline=0) self.ReadSParametersFromFileDoer.AddMenuElement(FileMenu,label="Open File",accelerator='Ctrl+O',underline=0) FileMenu.add_separator() self.Matplotlib2tikzDoer.AddMenuElement(FileMenu,label='Output to LaTeX (TikZ)',underline=10) # ------ CalcMenu=tk.Menu(self) TheMenu.add_cascade(label='Calculate',menu=CalcMenu,underline=0) self.CalculationPropertiesDoer.AddMenuElement(CalcMenu,label='Calculation Properties',underline=0) #CalcMenu.add_separator() self.ResampleDoer.AddMenuElement(CalcMenu,label='Resample',underline=0) #CalcMenu.add_separator() self.EnforcePassivityDoer.AddMenuElement(CalcMenu,label='Enforce Passivity',underline=8) self.EnforceCausalityDoer.AddMenuElement(CalcMenu,label='Enforce Causality',underline=9) self.WaveletDenoiseDoer.AddMenuElement(CalcMenu,label='Wavelet Denoise',underline=0) # ------ ViewMenu=tk.Menu(self) TheMenu.add_cascade(label='View',menu=ViewMenu,underline=0) self.VariableLineWidthDoer.AddCheckButtonMenuElement(ViewMenu,label='Variable Line Width',underline=9,onvalue=True,offvalue=False,variable=self.variableLineWidth) self.ShowPassivityViolationsDoer.AddCheckButtonMenuElement(ViewMenu,label='Show Passivity Violations',underline=5,onvalue=True,offvalue=False,variable=self.showPassivityViolations) self.ShowCausalityViolationsDoer.AddCheckButtonMenuElement(ViewMenu,label='Show Causality Violations',underline=6,onvalue=True,offvalue=False,variable=self.showCausalityViolations) self.ShowImpedanceDoer.AddCheckButtonMenuElement(ViewMenu,label='Show Impedance',underline=5,onvalue=True,offvalue=False,variable=self.showImpedance) self.LogScaleDoer.AddCheckButtonMenuElement(ViewMenu,label='Log Scale',underline=4,onvalue=True,offvalue=False,variable=self.logScale) # ------ HelpMenu=tk.Menu(self) TheMenu.add_cascade(label='Help',menu=HelpMenu,underline=0) self.HelpDoer.AddMenuElement(HelpMenu,label='Open Help File',underline=0) self.ControlHelpDoer.AddMenuElement(HelpMenu,label='Control Help',underline=0) # The Toolbar ToolBarFrame = tk.Frame(self) ToolBarFrame.pack(side=tk.TOP,fill=tk.X,expand=tk.NO) self.ReadSParametersFromFileDoer.AddToolBarElement(ToolBarFrame,iconfile=SignalIntegrity.App.IconsDir+'document-open-2.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) self.WriteSParametersToFileDoer.AddToolBarElement(ToolBarFrame,iconfile=SignalIntegrity.App.IconsDir+'document-save-2.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) tk.Frame(self,bd=2,relief=tk.SUNKEN).pack(side=tk.LEFT,fill=tk.X,padx=5,pady=5) self.CalculationPropertiesDoer.AddToolBarElement(ToolBarFrame,iconfile=SignalIntegrity.App.IconsDir+'tooloptions.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) tk.Frame(ToolBarFrame,height=2,bd=2,relief=tk.RAISED).pack(side=tk.LEFT,fill=tk.X,padx=5,pady=5) self.HelpDoer.AddToolBarElement(ToolBarFrame,iconfile=SignalIntegrity.App.IconsDir+'help-contents-5.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) self.ControlHelpDoer.AddToolBarElement(ToolBarFrame,iconfile=SignalIntegrity.App.IconsDir+'help-3.gif').Pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) topFrame=tk.Frame(self) topFrame.pack(side=tk.TOP,fill=tk.BOTH,expand=tk.YES) bottomFrame=tk.Frame(self) bottomFrame.pack(side=tk.TOP,fill=tk.BOTH,expand=tk.YES) topLeftFrame=tk.Frame(topFrame) topLeftFrame.pack(side=tk.LEFT,fill=tk.BOTH,expand=tk.YES) topRightFrame=tk.Frame(topFrame) topRightFrame.pack(side=tk.LEFT,fill=tk.BOTH,expand=tk.YES) bottomLeftFrame=tk.Frame(bottomFrame) bottomLeftFrame.pack(side=tk.LEFT,fill=tk.BOTH,expand=tk.YES) bottomRightFrame=tk.Frame(bottomFrame) bottomRightFrame.pack(side=tk.LEFT,fill=tk.BOTH,expand=tk.YES) self.topLeftFigure=Figure(figsize=(5,2), dpi=100) self.topLeftPlot=self.topLeftFigure.add_subplot(111) self.topLeftCanvas=FigureCanvasTkAgg(self.topLeftFigure, master=topLeftFrame) self.topLeftCanvas.get_tk_widget().pack(side=tk.TOP, fill=tk.X, expand=1) self.topLeftToolbar = NavigationToolbar2Tk( self.topLeftCanvas, topLeftFrame ) self.topLeftToolbar.update() self.topLeftCanvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) self.topRightFigure=Figure(figsize=(5,2), dpi=100) self.topRightPlot=self.topRightFigure.add_subplot(111) self.topRightCanvas=FigureCanvasTkAgg(self.topRightFigure, master=topRightFrame) self.topRightCanvas.get_tk_widget().pack(side=tk.TOP, fill=tk.X, expand=1) self.topRightToolbar = NavigationToolbar2Tk( self.topRightCanvas, topRightFrame ) self.topRightToolbar.update() self.topRightCanvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) self.topRightCanvasControlsFrame=tk.Frame(topRightFrame) self.topRightCanvasControlsFrame.pack(side=tk.TOP, fill=tk.X, expand=tk.NO) tk.Button(self.topRightCanvasControlsFrame,text='unwrap',command=self.onUnwrap).pack(side=tk.LEFT,expand=tk.NO,fill=tk.NONE) self.delay=PartPropertyDelay(0.) self.delayViewerProperty=ViewerProperty(self.topRightCanvasControlsFrame,self.delay,self.onDelayEntered) self.bottomLeftFigure=Figure(figsize=(5,2), dpi=100) self.bottomLeftPlot=self.bottomLeftFigure.add_subplot(111) self.bottomLeftCanvas=FigureCanvasTkAgg(self.bottomLeftFigure, master=bottomLeftFrame) self.bottomLeftCanvas.get_tk_widget().pack(side=tk.TOP, fill=tk.X, expand=1) self.bottomLeftToolbar = NavigationToolbar2Tk( self.bottomLeftCanvas, bottomLeftFrame ) self.bottomLeftToolbar.update() self.bottomLeftCanvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) self.bottomRightFigure=Figure(figsize=(5,2), dpi=100) self.bottomRightPlot=self.bottomRightFigure.add_subplot(111) self.bottomRightCanvas=FigureCanvasTkAgg(self.bottomRightFigure, master=bottomRightFrame) self.bottomRightCanvas.get_tk_widget().pack(side=tk.TOP, fill=tk.X, expand=1) self.bottomRightToolbar = NavigationToolbar2Tk( self.bottomRightCanvas, bottomRightFrame ) self.bottomRightToolbar.update() self.bottomRightCanvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) controlsFrame = tk.Frame(self) controlsFrame.pack(side=tk.TOP,fill=tk.X,expand=tk.NO) self.sButtonsFrame = tk.Frame(controlsFrame, bd=1, relief=tk.SUNKEN) self.sButtonsFrame.pack(side=tk.LEFT,expand=tk.NO,fill=tk.NONE) self.resampleButton=tk.Button(controlsFrame,text='resample',command=self.onResample) self.resampleButton.pack(side=tk.LEFT,expand=tk.NO,fill=tk.NONE) self.sp=sp if buttonLabels is None: numPorts=self.sp.m_P buttonLabels=[['s'+str(toP+1)+str(fromP+1) for fromP in range(numPorts)] for toP in range(numPorts)] self.referenceImpedance=PartPropertyReferenceImpedance(self.sp.m_Z0) self.referenceImpedanceProperty=ViewerProperty(controlsFrame,self.referenceImpedance,self.onReferenceImpedanceEntered) else: # button labels are a proxy for transfer parameters (until I do something better) self.showPassivityViolations.set(False) self.ShowPassivityViolationsDoer.Activate(False) self.ShowCausalityViolationsDoer.Activate(False) self.ShowImpedanceDoer.Activate(False) #self.LogScaleDoer.Activate(False) self.EnforcePassivityDoer.Activate(False) self.EnforceCausalityDoer.Activate(False) self.WaveletDenoiseDoer.Activate(False) self.ReadSParametersFromFileDoer.Activate(False) self.buttonLabels=buttonLabels self.buttons=[] for toP in range(len(buttonLabels)): buttonrow=[] rowFrame=tk.Frame(self.sButtonsFrame) rowFrame.pack(side=tk.TOP,expand=tk.NO,fill=tk.NONE) for fromP in range(len(buttonLabels[0])): thisButton=tk.Button(rowFrame,text=buttonLabels[toP][fromP],width=len(buttonLabels[toP][fromP]),command=lambda x=toP+1,y=fromP+1: self.onSelectSParameter(x,y)) thisButton.pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) buttonrow.append(thisButton) self.buttons.append(buttonrow) self.fromPort = 1 self.toPort = 1 try: from matplotlib2tikz import save as tikz_save except: self.Matplotlib2tikzDoer.Activate(False) self.buttons[self.toPort-1][self.fromPort-1].config(relief=tk.SUNKEN) self.PlotSParameter() self.deiconify() # self.geometry("%+d%+d" % (self.parent.root.winfo_x()+self.parent.root.winfo_width()/2-self.winfo_width()/2, # self.parent.root.winfo_y()+self.parent.root.winfo_height()/2-self.winfo_height()/2)) def onClosing(self): self.withdraw() self.destroy() def destroy(self): tk.Toplevel.withdraw(self) tk.Toplevel.destroy(self) def PlotSParameter(self): import SignalIntegrity.Lib as si self.topLeftPlot.cla() self.topRightPlot.cla() self.bottomLeftPlot.cla() self.bottomRightPlot.cla() if not SignalIntegrity.App.Preferences['Appearance.PlotCursorValues']: self.topLeftPlot.format_coord = lambda x, y: '' self.topRightPlot.format_coord = lambda x, y: '' self.bottomLeftPlot.format_coord = lambda x, y: '' self.bottomRightPlot.format_coord = lambda x, y: '' fr=self.sp.FrequencyResponse(self.toPort,self.fromPort) ir=fr.ImpulseResponse() y=fr.Response('dB') self.freqLabel=ToSI(fr.Frequencies()[-1],'Hz')[-3:] freqLabelDivisor=FromSI('1. '+self.freqLabel,'Hz') x=fr.Frequencies(freqLabelDivisor) if self.showPassivityViolations.get(): self.passivityViolations=[] s=self.sp._LargestSingularValues() for n in range(len(s)): if s[n]-1 > 1e-15: dotsize=max(min(20.,math.log10(s[0])/math.log10(1.01)*20.),1e-15) self.passivityViolations.append([x[n],y[n],dotsize]) lw=[min(1.,math.sqrt(w))*1.5 for w in fr.Response('mag')] fastway=True # this works - properly displays on log plot, only it is just too slow! # if self.logScale.get(): # fastway=False if self.variableLineWidth.get(): if fastway: segments = [[[x[i],y[i]],[x[i+1],y[i+1]]] for i in range(len(x)-1)] slw=lw[:-1] lc = LineCollection(segments, linewidths=slw,color='blue') self.topLeftPlot.add_collection(lc) else: for i in range(len(x)-1): if self.logScale.get(): self.topLeftPlot.semilogx(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') else: self.topLeftPlot.plot(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') else: if self.logScale.get(): self.topLeftPlot.semilogx(x,y) else: self.topLeftPlot.plot(x,y) if self.showPassivityViolations.get(): self.topLeftPlot.scatter( [c[0] for c in self.passivityViolations], [c[1] for c in self.passivityViolations], s=[c[2] for c in self.passivityViolations], color='red') self.topLeftPlot.set_xlim(xmin=min(x)) self.topLeftPlot.set_xlim(xmax=max(x)) self.topLeftPlot.set_ylim(ymin=max(min(y)-1.,-60.0)) self.topLeftPlot.set_ylim(ymax=max(y)+1.) self.topLeftPlot.set_ylabel('magnitude (dB)',fontsize=10) self.topLeftPlot.set_xlabel('frequency ('+self.freqLabel+')',fontsize=10) y=fr.Response('deg') x=fr.Frequencies(freqLabelDivisor) if self.variableLineWidth.get(): if fastway: segments = [[[x[i],y[i]],[x[i+1],y[i+1]]] for i in range(len(x)-1)] slw=lw[:-1] lc = LineCollection(segments, linewidths=slw,color='blue') self.topRightPlot.add_collection(lc) else: for i in range(len(x)-1): if self.logScale.get(): self.topRightPlot.semilogx(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') else: self.topRightPlot.plot(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') else: if self.logScale.get(): self.topRightPlot.semilogx(x,y) else: self.topRightPlot.plot(x,y) self.topRightPlot.set_xlim(xmin=min(x)) self.topRightPlot.set_xlim(xmax=max(x)) self.topRightPlot.set_ylim(ymin=min(y)-1) self.topRightPlot.set_ylim(ymax=max(y)+1) self.topRightPlot.set_ylabel('phase (degrees)',fontsize=10) self.topRightPlot.set_xlabel('frequency ('+self.freqLabel+')',fontsize=10) if ir is not None: if self.buttonLabels[self.toPort-1][self.fromPort-1][:2]=='i/' or self.buttonLabels[self.toPort-1][self.fromPort-1][:3]=='di/': print('Integrate') ir=si.td.wf.ImpulseResponse(ir.Integral(addPoint=False)) if self.buttonLabels[self.toPort-1][self.fromPort-1][:3]=='di/': print('Integrate') ir=si.td.wf.ImpulseResponse(ir.Integral(addPoint=False)*ir.td.Fs) y=ir.Values() timeLabel=ToSI(ir.Times()[-1],'s')[-2:] timeLabelDivisor=FromSI('1. '+timeLabel,'s') x=ir.Times(timeLabelDivisor) self.bottomLeftPlot.plot(x,y) if self.showCausalityViolations.get(): self.causalityViolations=[] Ts=1./ir.td.Fs/1e-9 for k in range(len(x)): if x[k]<=-Ts and abs(y[k])>0: dotsize=max(min(20.,abs(y[k])/0.1*20.),1e-15) self.causalityViolations.append([x[k],y[k],dotsize]) self.bottomLeftPlot.scatter( [c[0] for c in self.causalityViolations], [c[1] for c in self.causalityViolations], s=[c[2] for c in self.causalityViolations], color='red') self.bottomLeftPlot.set_ylim(ymin=min(min(y)*1.05,-0.1)) self.bottomLeftPlot.set_ylim(ymax=max(max(y)*1.05,0.1)) self.bottomLeftPlot.set_xlim(xmin=min(x)) self.bottomLeftPlot.set_xlim(xmax=max(x)) self.bottomLeftPlot.set_ylabel('amplitude',fontsize=10) self.bottomLeftPlot.set_xlabel('time ('+timeLabel+')',fontsize=10) firFilter=ir.FirFilter() stepWaveformTimeDescriptor=ir.td/firFilter.FilterDescriptor() stepWaveform=si.td.wf.StepWaveform(stepWaveformTimeDescriptor) stepResponse=stepWaveform*firFilter y=stepResponse.Values() x=stepResponse.Times(timeLabelDivisor) if self.showImpedance.get() and (self.fromPort == self.toPort): Z0=self.referenceImpedance.GetValue() y=[3000. if (1-yv)<=.000001 else min(Z0*(1+yv)/(1-yv),3000) for yv in y] x=[xv/2 for xv in x] self.bottomRightPlot.set_ylabel('impedance (Ohms)',fontsize=10) self.bottomRightPlot.set_xlabel('length ('+timeLabel+')',fontsize=10) self.bottomRightPlot.set_ylim(ymin=min(min(y)*1.05,Z0-1)) else: self.bottomRightPlot.set_ylabel('amplitude',fontsize=10) self.bottomRightPlot.set_xlabel('time ('+timeLabel+')',fontsize=10) self.bottomRightPlot.set_ylim(ymin=min(min(y)*1.05,-0.1)) self.bottomRightPlot.plot(x,y) self.bottomRightPlot.set_ylim(ymax=max(max(y)*1.05,0.1)) self.bottomRightPlot.set_xlim(xmin=min(x)) self.bottomRightPlot.set_xlim(xmax=max(x)) self.topLeftCanvas.draw() self.topRightCanvas.draw() self.bottomLeftCanvas.draw() self.bottomRightCanvas.draw() def onSelectSParameter(self,toP,fromP): self.buttons[self.toPort-1][self.fromPort-1].config(relief=tk.RAISED) self.toPort = toP self.fromPort = fromP self.buttons[self.toPort-1][self.fromPort-1].config(relief=tk.SUNKEN) self.delay.SetValueFromString(str(0)) self.delayViewerProperty.onUntouched(None) self.PlotSParameter() def onAutoscale(self): self.plt.autoscale(True) self.f.canvas.draw() def onUnwrap(self): fr=self.sp.FrequencyResponse(self.toPort,self.fromPort) ir=fr.ImpulseResponse() if ir is not None: idx = ir.Values('abs').index(max(ir.Values('abs'))) TD = ir.Times()[idx] # the time of the main peak else: TD=0. self.delay.SetValueFromString(str(TD)) self.delayViewerProperty.onUntouched(None) def onDelayEntered(self): self.topRightPlot.cla() fr=self.sp.FrequencyResponse(self.toPort,self.fromPort) TD = self.delay.GetValue() fr=fr._DelayBy(-TD) lw=[min(1.,math.sqrt(w))*1.5 for w in fr.Response('mag')] y=fr.Response('deg') x=fr.Frequencies('GHz') fastway=True if self.variableLineWidth.get(): if fastway: segments = [[[x[i],y[i]],[x[i+1],y[i+1]]] for i in range(len(x)-1)] slw=lw[:-1] lc = LineCollection(segments, linewidths=slw,color='blue') self.topRightPlot.add_collection(lc) else: for i in range(len(x)-1): if self.logScale.get(): self.topRightPlot.semilogx(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') else: self.topRightPlot.plot(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') else: if self.logScale.get(): self.topRightPlot.semilogx(x,y) else: self.topRightPlot.plot(x,y) self.topRightPlot.set_xlim(xmin=min(x)) self.topRightPlot.set_xlim(xmax=max(x)) self.topRightPlot.set_ylim(ymin=min(y)-1) self.topRightPlot.set_ylim(ymax=max(y)+1) self.topRightPlot.set_ylabel('phase (degrees)',fontsize=10) self.topRightPlot.set_xlabel('frequency ('+self.freqLabel+')',fontsize=10) self.topRightCanvas.draw() def onReferenceImpedanceEntered(self): self.sp.SetReferenceImpedance(self.referenceImpedance.GetValue()) self.PlotSParameter() def onReadSParametersFromFile(self): import SignalIntegrity.Lib as si filename=AskOpenFileName(filetypes=[('s-parameter files', ('*.s*p'))], initialdir=self.fileparts.AbsoluteFilePath(), parent=self) if filename is None: return self.fileparts=FileParts(filename) if self.fileparts.fileext=='': return self.title('S-parameters: '+self.fileparts.FileNameTitle()) self.sp=si.sp.SParameterFile(filename) self.referenceImpedance.SetValueFromString(str(self.sp.m_Z0)) self.referenceImpedanceProperty.propertyString.set(self.referenceImpedance.PropertyString(stype='entry')) for widget in self.sButtonsFrame.winfo_children(): widget.destroy() numPorts=self.sp.m_P self.buttonLabels=[['s'+str(toP+1)+str(fromP+1) for fromP in range(numPorts)] for toP in range(numPorts)] self.buttons=[] for toP in range(numPorts): buttonrow=[] rowFrame=tk.Frame(self.sButtonsFrame) rowFrame.pack(side=tk.TOP,expand=tk.NO,fill=tk.NONE) for fromP in range(numPorts): thisButton=tk.Button(rowFrame,text=self.buttonLabels[toP][fromP],command=lambda x=toP+1,y=fromP+1: self.onSelectSParameter(x,y)) thisButton.pack(side=tk.LEFT,fill=tk.NONE,expand=tk.NO) buttonrow.append(thisButton) self.buttons.append(buttonrow) self.fromPort = 1 self.toPort = 1 self.buttons[self.toPort-1][self.fromPort-1].config(relief=tk.SUNKEN) self.PlotSParameter() def onWriteSParametersToFile(self): ports=self.sp.m_P extension='.s'+str(ports)+'p' filename=AskSaveAsFilename(filetypes=[('s-parameters', extension)], defaultextension=extension, initialdir=self.fileparts.AbsoluteFilePath(), initialfile=self.fileparts.FileNameWithExtension(extension), parent=self) if filename is None: return self.fileparts=FileParts(filename) self.sp.WriteToFile(filename,'R '+str(self.sp.m_Z0)) def onResample(self): import SignalIntegrity.Lib as si self.sp=self.sp.Resample(si.fd.EvenlySpacedFrequencyList( SignalIntegrity.App.Project['CalculationProperties.EndFrequency'], SignalIntegrity.App.Project['CalculationProperties.FrequencyPoints'])) self.PlotSParameter() def onCalculationProperties(self): self.parent.onCalculationProperties() def onMatplotlib2TikZ(self): filename=AskSaveAsFilename(parent=self,filetypes=[('tex', '.tex')], defaultextension='.tex', initialdir=self.fileparts.AbsoluteFilePath(), initialfile=self.fileparts.filename+'Magnitude.tex') if filename is None: return try: PlotTikZ(filename,self.topLeftFigure) except: messagebox.showerror('Export LaTeX','LaTeX could not be generated or written ') fp=FileParts(filename.replace('Magnitude.tex', '')) filename=fp.filename filename=AskSaveAsFilename(parent=self,filetypes=[('tex', '.tex')], defaultextension='.tex', initialdir=self.fileparts.AbsoluteFilePath(), initialfile=filename+'Phase.tex') if filename is None: return try: PlotTikZ(filename,self.topRightFigure) except: messagebox.showerror('Export LaTeX','LaTeX could not be generated or written ') fp=FileParts(filename.replace('Phase.tex', '')) filename=fp.filename filename=AskSaveAsFilename(parent=self,filetypes=[('tex', '.tex')], defaultextension='.tex', initialdir=self.fileparts.AbsoluteFilePath(), initialfile=filename+'ImpulseResponse.tex') if filename is None: return try: PlotTikZ(filename,self.bottomLeftFigure) except: messagebox.showerror('Export LaTeX','LaTeX could not be generated or written ') fp=FileParts(filename.replace('ImpulseResponse.tex', '')) filename=fp.filename filename=AskSaveAsFilename(parent=self,filetypes=[('tex', '.tex')], defaultextension='.tex', initialdir=self.fileparts.AbsoluteFilePath(), initialfile=filename+'StepResponse.tex') if filename is None: return try: PlotTikZ(filename,self.bottomRightFigure) except: messagebox.showerror('Export LaTeX','LaTeX could not be generated or written ') def onHelp(self): if Doer.helpKeys is None: messagebox.showerror('Help System','Cannot find or open this help element') return Doer.helpKeys.Open('sec:S-parameter-Viewer') def onControlHelp(self): Doer.inHelp=True self.config(cursor='question_arrow') def onEscape(self): Doer.inHelp=False self.config(cursor='left_ptr') def onEnforcePassivity(self): self.sp.EnforcePassivity() self.PlotSParameter() def onEnforceCausality(self): self.sp.EnforceCausality() self.PlotSParameter() def onWaveletDenoise(self): self.sp.WaveletDenoise() self.PlotSParameter()
class SimulatorDialog(tk.Toplevel): def __init__(self, parent): tk.Toplevel.__init__(self, parent.parent) self.parent = parent self.withdraw() self.title('Simulation') img = tk.PhotoImage(file=SignalIntegrity.App.IconsBaseDir + 'AppIcon2.gif') self.tk.call('wm', 'iconphoto', self._w, img) self.protocol("WM_DELETE_WINDOW", self.onClosing) # the Doers - the holder of the commands, menu elements, toolbar elements, and key bindings self.WaveformSaveDoer = Doer( self.onWriteSimulatorToFile).AddHelpElement( 'Control-Help:Save-Waveforms') # TODO: someday allow waveform reading self.WaveformReadDoer = Doer( self.onReadSimulatorFromFile).AddHelpElement( 'Control-Help:Read-Waveforms').Activate(False) self.Matplotlib2tikzDoer = Doer(self.onMatplotlib2TikZ).AddHelpElement( 'Control-Help:Output-to-LaTeX') # ------ self.CalculationPropertiesDoer = Doer( self.onCalculationProperties).AddHelpElement( 'Control-Help:Calculation-Properties') self.ExamineTransferMatricesDoer = Doer( self.onExamineTransferMatrices).AddHelpElement( 'Control-Help:View-Transfer-Parameters') self.SimulateDoer = Doer( self.parent.parent.onCalculate).AddHelpElement( 'Control-Help:Recalculate') # ------ self.HelpDoer = Doer( self.onHelp).AddHelpElement('Control-Help:Open-Help-File') self.ControlHelpDoer = Doer( self.onControlHelp).AddHelpElement('Control-Help:Control-Help') # ------ self.EscapeDoer = Doer(self.onEscape).AddKeyBindElement( self, '<Escape>').DisableHelp() # The menu system TheMenu = tk.Menu(self) self.config(menu=TheMenu) FileMenu = tk.Menu(self) TheMenu.add_cascade(label='File', menu=FileMenu, underline=0) self.WaveformSaveDoer.AddMenuElement(FileMenu, label="Save Waveforms", underline=0) self.WaveformReadDoer.AddMenuElement(FileMenu, label="Read Waveforms", underline=0) FileMenu.add_separator() self.Matplotlib2tikzDoer.AddMenuElement(FileMenu, label='Output to LaTeX (TikZ)', underline=10) # ------ CalcMenu = tk.Menu(self) TheMenu.add_cascade(label='Calculate', menu=CalcMenu, underline=0) self.CalculationPropertiesDoer.AddMenuElement( CalcMenu, label='Calculation Properties', underline=12) self.ExamineTransferMatricesDoer.AddMenuElement( CalcMenu, label='View Transfer Parameters', underline=0) CalcMenu.add_separator() self.SimulateDoer.AddMenuElement(CalcMenu, label='Recalculate', underline=0) # ------ HelpMenu = tk.Menu(self) TheMenu.add_cascade(label='Help', menu=HelpMenu, underline=0) self.HelpDoer.AddMenuElement(HelpMenu, label='Open Help File', underline=0) self.ControlHelpDoer.AddMenuElement(HelpMenu, label='Control Help', underline=0) # The Toolbar ToolBarFrame = tk.Frame(self) ToolBarFrame.pack(side=tk.TOP, fill=tk.X, expand=tk.NO) iconsdir = SignalIntegrity.App.IconsDir + '' self.WaveformReadDoer.AddToolBarElement( ToolBarFrame, iconfile=iconsdir + 'document-open-2.gif').Pack(side=tk.LEFT, fill=tk.NONE, expand=tk.NO) self.WaveformSaveDoer.AddToolBarElement( ToolBarFrame, iconfile=iconsdir + 'document-save-2.gif').Pack(side=tk.LEFT, fill=tk.NONE, expand=tk.NO) tk.Frame(self, height=2, bd=2, relief=tk.RAISED).pack(side=tk.LEFT, fill=tk.X, padx=5, pady=5) self.CalculationPropertiesDoer.AddToolBarElement( ToolBarFrame, iconfile=iconsdir + 'tooloptions.gif').Pack(side=tk.LEFT, fill=tk.NONE, expand=tk.NO) self.SimulateDoer.AddToolBarElement( ToolBarFrame, iconfile=iconsdir + 'system-run-3.gif').Pack(side=tk.LEFT, fill=tk.NONE, expand=tk.NO) tk.Frame(ToolBarFrame, height=2, bd=2, relief=tk.RAISED).pack(side=tk.LEFT, fill=tk.X, padx=5, pady=5) self.HelpDoer.AddToolBarElement( ToolBarFrame, iconfile=iconsdir + 'help-contents-5.gif').Pack(side=tk.LEFT, fill=tk.NONE, expand=tk.NO) self.ControlHelpDoer.AddToolBarElement(ToolBarFrame, iconfile=iconsdir + 'help-3.gif').Pack(side=tk.LEFT, fill=tk.NONE, expand=tk.NO) self.f = Figure(figsize=(6, 4), dpi=100) self.plt = self.f.add_subplot(111) self.plt.set_xlabel('time (ns)') self.plt.set_ylabel('amplitude') self.waveformList = None self.waveformNamesList = None self.canvas = FigureCanvasTkAgg(self.f, master=self) #canvas.show() self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.X, expand=1) toolbar = NavigationToolbar2Tk(self.canvas, self) toolbar.update() self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) controlsFrame = tk.Frame(self) tk.Button(controlsFrame, text='autoscale', command=self.onAutoscale).pack(side=tk.LEFT, expand=tk.NO, fill=tk.X) controlsFrame.pack(side=tk.TOP, fill=tk.X, expand=tk.NO) try: from matplotlib2tikz import save as tikz_save except: self.Matplotlib2tikzDoer.Activate(False) self.ExamineTransferMatricesDoer.Activate(False) self.SimulateDoer.Activate(False) self.geometry( "%+d%+d" % (self.parent.parent.root.winfo_x() + self.parent.parent.root.winfo_width() / 2 - self.winfo_width() / 2, self.parent.parent.root.winfo_y() + self.parent.parent.root.winfo_height() / 2 - self.winfo_height() / 2)) def onClosing(self): self.withdraw() self.destroy() def destroy(self): tk.Toplevel.withdraw(self) tk.Toplevel.destroy(self) def onAutoscale(self): self.plt.autoscale(True) self.f.canvas.draw() def UpdateWaveforms(self, waveformList, waveformNamesList): self.lift(self.parent.parent) self.plt.cla() self.plt.set_ylabel('amplitude', fontsize=10) if not SignalIntegrity.App.Preferences['Appearance.PlotCursorValues']: self.plt.format_coord = lambda x, y: '' if not self.waveformList == None: self.plt.autoscale(False) self.waveformList = waveformList self.waveformNamesList = waveformNamesList mint = None maxt = None for wfi in range(len(self.waveformList)): wf = self.waveformList[wfi] wfTimes = wf.Times() if len(wfTimes) == 0: continue wfValues = wf.Values() wfName = str(self.waveformNamesList[wfi]) mint = wfTimes[0] if mint is None else max(mint, wfTimes[0]) maxt = wfTimes[-1] if maxt is None else min(maxt, wfTimes[-1]) timeLabel = 's' timeLabelDivisor = 1. if not self.waveformList is None: if (not mint is None) and (not maxt is None): durLabelTime = (maxt - mint) timeLabel = ToSI(durLabelTime, 's')[-2:] timeLabelDivisor = FromSI('1. ' + timeLabel, 's') mint = mint / timeLabelDivisor maxt = maxt / timeLabelDivisor if not mint is None: self.plt.set_xlim(xmin=mint) if not maxt is None: self.plt.set_xlim(xmax=maxt) for wfi in range(len(self.waveformList)): wf = self.waveformList[wfi] wfTimes = wf.Times(timeLabelDivisor) if len(wfTimes) == 0: continue wfValues = wf.Values() wfName = str(self.waveformNamesList[wfi]) self.plt.plot(wfTimes, wfValues, label=wfName) self.plt.set_xlabel('time (' + timeLabel + ')', fontsize=10) self.plt.legend(loc='upper right', labelspacing=0.1) self.f.canvas.draw() return self def onWriteSimulatorToFile(self): for wfi in range(len(self.waveformNamesList)): outputWaveformName = self.waveformNamesList[wfi] outputWaveform = self.waveformList[wfi] if self.parent.parent.fileparts.filename == '': filename = outputWaveformName else: filename = self.parent.parent.fileparts.filename + '_' + outputWaveformName filename = AskSaveAsFilename( parent=self, filetypes=[('waveform', '.txt')], defaultextension='.txt', initialdir=self.parent.parent.fileparts.AbsoluteFilePath(), initialfile=filename + '.txt') if filename is None: continue outputWaveform.WriteToFile(filename) def onReadSimulatorFromFile(self): pass def onCalculationProperties(self): self.parent.parent.onCalculationProperties() def onExamineTransferMatrices(self): buttonLabelList = [[ out + ' due to ' + inp for inp in self.parent.sourceNames ] for out in self.parent.outputWaveformLabels] maxLength = len( max([item for sublist in buttonLabelList for item in sublist], key=len)) buttonLabelList = [[item.ljust(maxLength) for item in sublist] for sublist in buttonLabelList] sp = self.parent.transferMatrices.SParameters() SParametersDialog( self.parent.parent, sp, self.parent.parent.fileparts.FullFilePathExtension('s' + str(sp.m_P) + 'p'), 'Transfer Parameters', buttonLabelList) def onMatplotlib2TikZ(self): filename = AskSaveAsFilename( parent=self, filetypes=[('tex', '.tex')], defaultextension='.tex', initialdir=self.parent.parent.fileparts.AbsoluteFilePath(), initialfile=self.parent.parent.fileparts.filename + 'Waveforms.tex') if filename is None: return try: PlotTikZ(filename, self.f) except: messagebox.showerror('Export LaTeX', 'LaTeX could not be generated or written ') def onHelp(self): if Doer.helpKeys is None: messagebox.showerror('Help System', 'Cannot find or open this help element') return Doer.helpKeys.Open('sec:Simulator-Dialog') def onControlHelp(self): Doer.inHelp = True self.config(cursor='question_arrow') def onEscape(self): Doer.inHelp = False self.config(cursor='left_ptr')