示例#1
0
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)
示例#2
0
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()
示例#3
0
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)
示例#4
0
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()
示例#5
0
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')