コード例 #1
0
class PlotPZ(QtGui.QMainWindow):
    def __init__(self,
                 parent=None,
                 DEBUG=False):  # default parent = None -> top Window
        super(PlotPZ, self).__init__(parent)  # initialize QWidget base class
        #        QtGui.QMainWindow.__init__(self) # alternative syntax

        self.DEBUG = DEBUG

        self.layHChkBoxes = QtGui.QHBoxLayout()
        self.layHChkBoxes.addStretch(10)

        self.mplwidget = MplWidget()

        self.mplwidget.layVMainMpl.addLayout(self.layHChkBoxes)

        # make this the central widget, taking all available space:
        self.setCentralWidget(self.mplwidget)

        self.initAxes()

        self.draw()  # calculate and draw phi(f)

#        #=============================================
#        # Signals & Slots
#        #=============================================
#        self.btnWrap.clicked.connect(self.draw)
#        self.cmbUnitsPhi.currentIndexChanged.connect(self.draw)

    def initAxes(self):
        """Initialize and clear the axes
        """
        #        self.ax = self.mplwidget.ax
        self.ax = self.mplwidget.fig.add_subplot(111)
        self.ax.clear()

    def draw(self):
        if self.mplwidget.mplToolbar.enable_update:
            self.draw_pz()

    def draw_pz(self):
        """
        (re)draw P/Z plot
        """

        zpk = fb.fil[0]['zpk']

        self.ax.clear()

        [z, p, k] = pyfda_lib.zplane(self.ax, zpk, verbose=False)

        self.ax.set_title(r'Pole / Zero Plot')
        self.ax.set_xlabel('Real axis')
        self.ax.set_ylabel('Imaginary axis')

        self.ax.axis([-1.1, 1.1, -1.1, 1.1])

        self.mplwidget.redraw()
コード例 #2
0
ファイル: plot_pz.py プロジェクト: euripedesrocha/pyFDA
class PlotPZ(QtGui.QMainWindow):

    def __init__(self, parent = None, DEBUG = False): # default parent = None -> top Window
        super(PlotPZ, self).__init__(parent) # initialize QWidget base class
#        QtGui.QMainWindow.__init__(self) # alternative syntax

        self.DEBUG = DEBUG

        self.layHChkBoxes = QtGui.QHBoxLayout()
        self.layHChkBoxes.addStretch(10)

        self.mplwidget = MplWidget()

        self.mplwidget.layVMainMpl.addLayout(self.layHChkBoxes)

        # make this the central widget, taking all available space:
        self.setCentralWidget(self.mplwidget)
        
        self.initAxes()

        self.draw() # calculate and draw phi(f)

#        #=============================================
#        # Signals & Slots
#        #=============================================
#        self.btnWrap.clicked.connect(self.draw)
#        self.cmbUnitsPhi.currentIndexChanged.connect(self.draw)

    def initAxes(self):
        """Initialize and clear the axes
        """
#        self.ax = self.mplwidget.ax
        self.ax = self.mplwidget.fig.add_subplot(111)
        self.ax.clear()

    def draw(self):
        if self.mplwidget.mplToolbar.enable_update:
            self.draw_pz()

    def draw_pz(self):
        """
        (re)draw P/Z plot
        """

        zpk = fb.fil[0]['zpk']

        self.ax.clear()

        [z, p, k] = pyfda_lib.zplane(self.ax, zpk, verbose = False)

        self.ax.set_title(r'Pole / Zero Plot')
        self.ax.set_xlabel('Real axis')
        self.ax.set_ylabel('Imaginary axis')

        self.ax.axis([-1.1, 1.1, -1.1, 1.1])

        self.mplwidget.redraw()
コード例 #3
0
ファイル: plot_phi.py プロジェクト: euripedesrocha/pyFDA
class PlotPhi(QtGui.QMainWindow):
    def __init__(self,
                 parent=None,
                 DEBUG=False):  # default parent = None -> top Window
        super(PlotPhi, self).__init__(parent)  # initialize QWidget base class

        self.DEBUG = DEBUG

        self.cmbUnitsPhi = QtGui.QComboBox(self)
        units = ["rad", "rad/pi", "deg"]
        scales = [1., 1. / np.pi, 180. / np.pi]
        for unit, scale in zip(units, scales):
            self.cmbUnitsPhi.addItem(unit, scale)
        self.cmbUnitsPhi.setObjectName("cmbUnitsA")
        self.cmbUnitsPhi.setToolTip("Set unit for phase.")
        self.cmbUnitsPhi.setCurrentIndex(0)
        self.cmbUnitsPhi.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)

        self.lblWrap = QtGui.QLabel("Wrapped Phase")
        self.btnWrap = QtGui.QCheckBox()
        self.btnWrap.setChecked(False)
        self.btnWrap.setToolTip("Plot phase wrapped to +/- pi")
        self.layHChkBoxes = QtGui.QHBoxLayout()
        self.layHChkBoxes.addStretch(10)
        self.layHChkBoxes.addWidget(self.cmbUnitsPhi)
        self.layHChkBoxes.addWidget(self.lblWrap)
        self.layHChkBoxes.addWidget(self.btnWrap)
        self.layHChkBoxes.addStretch(10)

        self.mplwidget = MplWidget()
        #        self.mplwidget.setParent(self)

        self.mplwidget.layVMainMpl.addLayout(self.layHChkBoxes)

        #        self.mplwidget.setFocus()
        # make this the central widget, taking all available space:
        self.setCentralWidget(self.mplwidget)

        self.initAxes()

        self.draw()  # calculate and draw phi(f)

        #        #=============================================
        #        # Signals & Slots
        #        #=============================================
        #        self.mplwidget.sldLw.valueChanged.connect(lambda:self.draw())
        self.btnWrap.clicked.connect(self.draw)
        self.cmbUnitsPhi.currentIndexChanged.connect(self.draw)

    def initAxes(self):
        """Initialize and clear the axes
        """
        #        self.ax = self.mplwidget.ax
        self.ax = self.mplwidget.fig.add_subplot(111)
        self.ax.clear()
        self.ax.hold(False)

    def draw(self):
        if self.mplwidget.mplToolbar.enable_update:
            self.draw_phi()

    def draw_phi(self):
        """
        Re-calculate phi(f) and draw the figure
        """

        self.unitPhi = self.cmbUnitsPhi.currentText()

        self.bb = fb.fil[0]['ba'][0]
        self.aa = fb.fil[0]['ba'][1]

        if self.DEBUG:
            print("--- plotPhi.draw() ---")
            print("b,a = ", self.bb, self.aa)

        wholeF = fb.fil[0]['freqSpecsRangeType'] != 'half'
        f_S = fb.fil[0]['f_S']

        [W, H] = sig.freqz(self.bb, self.aa, worN=fb.gD['N_FFT'], whole=wholeF)

        F = W / (2 * np.pi) * f_S

        if fb.fil[0]['freqSpecsRangeType'] == 'sym':
            H = np.fft.fftshift(H)
            F = F - f_S / 2.

#        scale = self.cmbUnitsPhi.itemData(self.cmbUnitsPhi.currentIndex())
        y_str = r'$\angle H(\mathrm{e}^{\mathrm{j} \Omega})$'
        if self.unitPhi == 'rad':
            y_str += ' in rad ' + r'$\rightarrow $'
            scale = 1.
        elif self.unitPhi == 'rad/pi':
            y_str += ' in rad' + r'$ / \pi \;\rightarrow $'
            scale = 1. / np.pi
        else:
            y_str += ' in deg ' + r'$\rightarrow $'
            scale = 180. / np.pi
        fb.fil[0]['plt_phiLabel'] = y_str
        fb.fil[0]['plt_phiUnit'] = self.unitPhi

        if self.btnWrap.isChecked():
            phi_plt = np.angle(H) * scale
        else:
            phi_plt = np.unwrap(np.angle(H)) * scale

        self.ax.clear()
        #---------------------------------------------------------
        line_phi, = self.ax.plot(F, phi_plt, lw=fb.gD['rc']['lw'])
        #---------------------------------------------------------

        self.ax.set_title(r'Phase Frequency Response')
        self.ax.set_xlabel(fb.fil[0]['plt_fLabel'])
        self.ax.set_ylabel(y_str)
        self.ax.set_xlim(fb.fil[0]['freqSpecsRange'])

        self.mplwidget.redraw()
コード例 #4
0
class PlotTauG(QtGui.QMainWindow):

    def __init__(self, parent = None, DEBUG = False): # default parent = None -> top Window
        super(PlotTauG, self).__init__(parent) # initialize QWidget base class
#        QtGui.QMainWindow.__init__(self) # alternative syntax

        self.DEBUG = DEBUG
#
#        self.lblWrap = QtGui.QLabel("Wrapped Phase")
#        self.btnWrap = QtGui.QCheckBox()
#        self.btnWrap.setChecked(False)
#        self.btnWrap.setToolTip("Plot phase wrapped to +/- pi")
        self.layHChkBoxes = QtGui.QHBoxLayout()
        self.layHChkBoxes.addStretch(10)
#        self.layHChkBoxes.addWidget(self.cmbUnitsPhi)

        self.mplwidget = MplWidget()
#        self.mplwidget.setParent(self)
        
        self.mplwidget.layVMainMpl.addLayout(self.layHChkBoxes)

#        self.mplwidget.setFocus()
        # make this the central widget, taking all available space:
        self.setCentralWidget(self.mplwidget)
        
        self.initAxes()

        self.draw() # calculate and draw phi(f)

#        #=============================================
#        # Signals & Slots
#        #=============================================
#        self.btnWrap.clicked.connect(self.draw)
#        self.cmbUnitsPhi.currentIndexChanged.connect(self.draw)

    def initAxes(self):
        """Initialize and clear the axes
        """
#        self.ax = self.mplwidget.ax
        self.ax = self.mplwidget.fig.add_subplot(111)
        self.ax.clear()
        self.ax.set_title(r'Group Delay $ \tau_g$')
        self.ax.hold(False)
        
        #plt.gca().cla()
        #p.clf()
        
    def draw(self):
        if self.mplwidget.mplToolbar.enable_update:
            self.draw_taug()

    def draw_taug(self):
        """
        Draw group delay
        """
        bb = fb.fil[0]['ba'][0]
        aa = fb.fil[0]['ba'][1]

        wholeF = fb.fil[0]['freqSpecsRangeType'] != 'half'
        f_S = fb.fil[0]['f_S']

#        scale = self.cmbUnitsPhi.itemData(self.cmbUnitsPhi.currentIndex())

        [tau_g, w] = pyfda_lib.grpdelay(bb,aa, fb.gD['N_FFT'],
                        whole = wholeF)

        F = w / (2 * np.pi) * fb.fil[0]['f_S']
        if fb.fil[0]['freqSpecsRangeType'] == 'sym':
            tau_g = np.fft.fftshift(tau_g)
            F = F - f_S / 2.

        self.ax.plot(F, tau_g, lw = fb.gD['rc']['lw'], label = "Group Delay")

        self.ax.set_xlabel(fb.fil[0]['plt_fLabel'])
        self.ax.set_ylabel(r'$ \tau_g(\mathrm{e}^{\mathrm{j} \Omega}) / T_S \; \rightarrow $')
        # widen limits to suppress numerical inaccuracies when tau_g = constant
        self.ax.axis(fb.fil[0]['freqSpecsRange'] + [max(min(tau_g)-0.5,0), max(tau_g) + 0.5])


        self.mplwidget.redraw()
コード例 #5
0
class PlotHf(QtGui.QMainWindow):

# TODO: inset plot should have useful preset range, depending on filter type,
#       stop band or pass band should be selectable as well as lin / log scale
# TODO: position and size of inset plot should be selectable


    def __init__(self, parent = None, DEBUG = False): # default parent = None -> top Window
        super(PlotHf, self).__init__(parent) # initialize QWidget base class
#        QtGui.QMainWindow.__init__(self) # alternative syntax

        self.DEBUG = DEBUG

        modes = ['| H |', 're{H}', 'im{H}']
        self.cmbShowH = QtGui.QComboBox(self)
        self.cmbShowH.addItems(modes)
        self.cmbShowH.setObjectName("cmbUnitsH")
        self.cmbShowH.setToolTip("Show magnitude, real / imag. part of H or H \n"
        "without linear phase (acausal system).")
        self.cmbShowH.setCurrentIndex(0)

        self.lblIn = QtGui.QLabel("in")

        units = ["dB", "V", "W"]
        self.cmbUnitsA = QtGui.QComboBox(self)
        self.cmbUnitsA.addItems(units)
        self.cmbUnitsA.setObjectName("cmbUnitsA")
        self.cmbUnitsA.setToolTip("Set unit for y-axis:\n"
        "dB is attenuation (positive values)\nV and W are less than 1.")
        self.cmbUnitsA.setCurrentIndex(0)

        self.cmbShowH.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
        self.cmbUnitsA.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)

        self.lblLinphase = QtGui.QLabel("Acausal system")
        self.chkLinphase = QtGui.QCheckBox()
        self.chkLinphase.setToolTip("Remove linear phase according to filter order.\n"
           "Attention: this makes no sense for a non-linear phase system!")

        self.lblInset = QtGui.QLabel("Inset")

        self.cmbInset = QtGui.QComboBox(self)
        self.cmbInset.addItems(['off', 'edit', 'fixed'])
        self.cmbInset.setObjectName("cmbInset")
        self.cmbInset.setToolTip("Display/edit second inset plot")
        self.cmbInset.setCurrentIndex(0)
        self.inset_idx = 0 # store previous index for comparison

        self.lblSpecs = QtGui.QLabel("Show Specs")
        self.chkSpecs = QtGui.QCheckBox()
        self.chkSpecs.setChecked(False)
        self.chkSpecs.setToolTip("Display filter specs as hatched regions")

        self.lblPhase = QtGui.QLabel("Phase")
        self.chkPhase = QtGui.QCheckBox()
        self.chkPhase.setToolTip("Overlay phase")


        self.layHChkBoxes = QtGui.QHBoxLayout()
        self.layHChkBoxes.addStretch(10)
        self.layHChkBoxes.addWidget(self.cmbShowH)
        self.layHChkBoxes.addWidget(self.lblIn)
        self.layHChkBoxes.addWidget(self.cmbUnitsA)
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.lblLinphase)
        self.layHChkBoxes.addWidget(self.chkLinphase)
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.lblInset)
        self.layHChkBoxes.addWidget(self.cmbInset)
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.lblSpecs)
        self.layHChkBoxes.addWidget(self.chkSpecs)
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.lblPhase)
        self.layHChkBoxes.addWidget(self.chkPhase)
        self.layHChkBoxes.addStretch(10)

        self.mplwidget = MplWidget()
#        self.mplwidget.setParent(self)

        self.mplwidget.layVMainMpl.addLayout(self.layHChkBoxes)
#        self.mplwidget.layVMainMpl1.addWidget(self.mplwidget)

#        self.mplwidget.setFocus()
        # make this the central widget, taking all available space:
        self.setCentralWidget(self.mplwidget)

        self.initAxes()

        self.draw() # calculate and draw |H(f)|

#        #=============================================
#        # Signals & Slots
#        #=============================================
        self.cmbUnitsA.currentIndexChanged.connect(self.draw)
        self.cmbShowH.currentIndexChanged.connect(self.draw)

        self.chkLinphase.clicked.connect(self.draw)
        self.cmbInset.currentIndexChanged.connect(self.draw_inset)

        self.chkSpecs.clicked.connect(self.draw)
        self.chkPhase.clicked.connect(self.draw_phase)

    def initAxes(self):
        """Initialize and clear the axes
        """
#        self.ax = self.mplwidget.ax
        self.ax = self.mplwidget.fig.add_subplot(111)
        self.ax.clear()

    def plotSpecLimits(self, specAxes):
        """
        Plot the specifications limits (F_SB, A_SB, ...) as lines and as
        hatched areas.
        """
#        fc = (0.8,0.8,0.8) # color for shaded areas
        fill_params = {'facecolor':'none','hatch':'/', 'edgecolor':'k', 'lw':0.0}
        line_params = {'linewidth':1.0, 'color':'blue', 'linestyle':'--'}
        ax = specAxes

        # extract from filterTree the parameters that are actually used
#        myParams = fb.filTree[rt][ft][dm][fo]['par']
#        freqParams = [l for l in myParams if l[0] == 'F']

        if fb.fil[0]['ft'] == "FIR":
            A_PB_max = self.A_PB # 20*log10(1+del_PB)
            A_PB2_max = self.A_PB2
        else: # IIR log
            A_PB_max = A_PB2_max = 0

        if self.unitA == 'V':
            dBMul = 20.
        elif self.unitA == 'W':
            dBMul = 10.

        if self.unitA == 'dB':
            A_PB_min = -self.A_PB
            A_PB2_min = -self.A_PB2
            A_PB_minx = min(A_PB_min, A_PB2_min) - 10# 20*log10(1-del_PB)
            A_SB = -self.A_SB
            A_SB2 = -self.A_SB2
            A_SBx = A_SB - 10
        else:
            A_PB_max = 10**(A_PB_max/dBMul)# 1 + del_PB
            A_PB2_max = 10**(A_PB2_max/dBMul)# 1 + del_PB
            A_PB_min = 10**(-self.A_PB/dBMul) #1 - del_PB
            A_PB2_min = 10**(-self.A_PB2/dBMul) #1 - del_PB
            A_PB_minx = A_PB_min / 2
            A_SB = 10**(-self.A_SB/dBMul)
            A_SB2 = 10**(-self.A_SB2/dBMul)
            A_SBx = A_SB / 5

        F_max = self.f_S/2
        F_PB = self.F_PB
        F_SB = fb.fil[0]['F_SB'] * self.f_S
        F_SB2 = fb.fil[0]['F_SB2'] * self.f_S
        F_PB2 = fb.fil[0]['F_PB2'] * self.f_S

        y_min =  A_PB_minx
        y_max = ax.get_ylim()[1]

        F_lim_lor = []
        A_lim_lor = []

        if fb.fil[0]['rt'] == 'LP':
            F_lim_up = [0,        F_SB,     F_SB, F_max]
            A_lim_up = [A_PB_max, A_PB_max, A_SB, A_SB]
            F_lim_lo = [0,        F_PB,     F_PB]
            A_lim_lo = [A_PB_min, A_PB_min, A_PB_minx]

        if fb.fil[0]['rt'] == 'HP':
            F_lim_up = [0,    F_SB, F_SB,     F_max]
            A_lim_up = [A_SB, A_SB, A_PB_max, A_PB_max]
            F_lim_lo = [F_PB,      F_PB,     F_max]
            A_lim_lo = [A_PB_minx, A_PB_min, A_PB_min]

        if fb.fil[0]['rt'] == 'BS':
            F_lim_up = [0,        F_SB,     F_SB, F_SB2, F_SB2,     F_max]
            A_lim_up = [A_PB_max, A_PB_max, A_SB, A_SB,  A_PB2_max, A_PB2_max]
            # lower limits left:
            F_lim_lo = [0,        F_PB,     F_PB]
            A_lim_lo = [A_PB_min, A_PB_min, A_PB_minx]
            # lower limits right:
            F_lim_lor = [F_PB2, F_PB2, F_max]
            A_lim_lor = [A_PB_minx, A_PB2_min, A_PB2_min]

        if fb.fil[0]['rt'] in {"BP", "HIL"}:
            F_lim_up = [0,    F_SB, F_SB,     F_SB2,    F_SB2, F_max]
            A_lim_up = [A_SB, A_SB, A_PB_max, A_PB_max, A_SB2, A_SB2]
            F_lim_lo = [F_PB,      F_PB,     F_PB2,    F_PB2]
            A_lim_lo = [A_PB_minx, A_PB_min, A_PB_min, A_PB_minx]

        F_lim_up = np.array(F_lim_up)
        F_lim_lo = np.array(F_lim_lo)
        F_lim_lor = np.array(F_lim_lor)

        # upper limits:
        ax.plot(F_lim_up, A_lim_up, **line_params)
        ax.fill_between(F_lim_up, y_max, A_lim_up, **fill_params)
        # lower limits:
        ax.plot(F_lim_lo, A_lim_lo, F_lim_lor, A_lim_lor, **line_params)
        ax.fill_between(F_lim_lo, y_min, A_lim_lo, **fill_params)
        ax.fill_between(F_lim_lor, y_min, A_lim_lor, **fill_params)

        if fb.fil[0]['freqSpecsRangeType'] != 'half': # frequency axis +/- f_S/2
            # plot limits for other half of the spectrum
            if fb.fil[0]['freqSpecsRangeType'] == 'sym': # frequency axis +/- f_S/2
                F_lim_up = -F_lim_up
                F_lim_lo = -F_lim_lo
                F_lim_lor = -F_lim_lor
            else: # -> 'whole'
                F_lim_up = self.f_S - F_lim_up
                F_lim_lo = self.f_S - F_lim_lo
                F_lim_lor = self.f_S - F_lim_lor
            # upper limits:
            ax.plot(F_lim_up, A_lim_up, **line_params)
            ax.fill_between(F_lim_up, y_max, A_lim_up, **fill_params)
            # lower limits:
            ax.plot(F_lim_lo, A_lim_lo, F_lim_lor, A_lim_lor, **line_params)
            ax.fill_between(F_lim_lo, y_min, A_lim_lo, **fill_params)
            ax.fill_between(F_lim_lor, y_min, A_lim_lor, **fill_params)

    def draw(self):
        if self.mplwidget.mplToolbar.enable_update:
            self.draw_hf()

    def draw_hf(self):
        """
        Re-calculate |H(f)| and draw the figure
        """
        self.unitA = self.cmbUnitsA.currentText()

        # Linphase settings only makes sense for amplitude plot
        self.chkLinphase.setCheckable(self.unitA == 'V')
        self.chkLinphase.setEnabled(self.unitA == 'V')
        self.lblLinphase.setEnabled(self.unitA == 'V')

        self.specs = self.chkSpecs.isChecked()
        self.phase = self.chkPhase.isChecked()
        self.linphase = self.chkLinphase.isChecked()

        self.bb = fb.fil[0]['ba'][0]
        self.aa = fb.fil[0]['ba'][1]

        self.f_S  = fb.fil[0]['f_S']
        self.F_PB = fb.fil[0]['F_PB'] * self.f_S
        self.F_SB = fb.fil[0]['F_SB'] * self.f_S

        self.A_PB  = fb.fil[0]['A_PB']
        self.A_PB2 = fb.fil[0]['A_PB2']
        self.A_SB  = fb.fil[0]['A_SB']
        self.A_SB2 = fb.fil[0]['A_SB2']

        f_lim = fb.fil[0]['freqSpecsRange']
        wholeF = fb.fil[0]['freqSpecsRangeType'] != 'half'


        if self.DEBUG:
            print("--- plotHf.draw() --- ")
            print("b, a = ", self.bb, self.aa)

        # calculate H_c(W) (complex) for W = 0 ... pi:
        [W, self.H_c] = sig.freqz(self.bb, self.aa, worN = fb.gD['N_FFT'],
            whole = wholeF)
        self.F = W / (2 * np.pi) * self.f_S

        if fb.fil[0]['freqSpecsRangeType'] == 'sym':
            self.H_c = np.fft.fftshift(self.H_c)
            self.F = self.F - self.f_S/2.

        if self.linphase: # remove the linear phase
            self.H_c = self.H_c * np.exp(1j * W * fb.fil[0]["N"]/2.)

        if self.cmbShowH.currentIndex() == 0: # show magnitude of H
            H = abs(self.H_c)
            H_str = r'$|H(\mathrm{e}^{\mathrm{j} \Omega})|$'
        elif self.cmbShowH.currentIndex() == 1: # show real part of H
            H = self.H_c.real
            H_str = r'$\Re \{H(\mathrm{e}^{\mathrm{j} \Omega})\}$'
        else:  # show imag. part of H
            H = self.H_c.imag
            H_str = r'$\Im \{H(\mathrm{e}^{\mathrm{j} \Omega})\}$'


        # clear the axes and (re)draw the plot
        #
        if self.ax.get_navigate():

            self.ax.clear()

            #================ Main Plotting Routine =========================

            if self.unitA == 'dB':
                A_lim = [-self.A_SB -10, self.A_PB +1]
                self.H_plt = 20*np.log10(abs(H))
                H_str += ' in dB ' + r'$\rightarrow$'
            elif self.unitA == 'V': #  'lin'
                A_lim = [10**((-self.A_SB-10)/20), 10**((self.A_PB+1)/20)]
                self.H_plt = H
                H_str +=' in V ' + r'$\rightarrow $'
                self.ax.axhline(linewidth=1, color='k') # horizontal line at 0
            else: # unit is W
                A_lim = [10**((-self.A_SB-10)/10), 10**((self.A_PB+0.5)/10)]
                self.H_plt = H * H.conj()
                H_str += ' in W ' + r'$\rightarrow $'

            plt_lim = f_lim + A_lim

            #-----------------------------------------------------------
            self.ax.plot(self.F, self.H_plt, lw = fb.gD['rc']['lw'], label = 'H(f)')
            #-----------------------------------------------------------
            self.ax_bounds = [self.ax.get_ybound()[0], self.ax.get_ybound()[1]]#, self.ax.get]

            self.ax.axis(plt_lim)

            if self.specs: self.plotSpecLimits(specAxes = self.ax)

            self.ax.set_title(r'Magnitude Frequency Response')
            self.ax.set_xlabel(fb.fil[0]['plt_fLabel'])
            self.ax.set_ylabel(H_str)

        self.mplwidget.redraw()

    def draw_phase(self):
        self.phase = self.chkPhase.isChecked()
        if self.phase:
            self.ax_p = self.ax.twinx() # second axes system with same x-axis for phase

            phi_str = r'$\angle H(\mathrm{e}^{\mathrm{j} \Omega})$'
            if fb.fil[0]['plt_phiUnit'] == 'rad':
                phi_str += ' in rad ' + r'$\rightarrow $'
                scale = 1.
            elif fb.fil[0]['plt_phiUnit'] == 'rad/pi':
                phi_str += ' in rad' + r'$ / \pi \;\rightarrow $'
                scale = 1./ np.pi
            else:
                phi_str += ' in deg ' + r'$\rightarrow $'
                scale = 180./np.pi
        #-----------------------------------------------------------
            self.ax_p.plot(self.F,np.unwrap(np.angle(self.H_c))*scale,
                               'b--', lw = fb.gD['rc']['lw'], label = "Phase")
        #-----------------------------------------------------------
            self.ax_p.set_ylabel(phi_str, color='blue')
            nbins = len(self.ax.get_yticks()) # number of ticks on main y-axis
            # http://stackoverflow.com/questions/28692608/align-grid-lines-on-two-plots
            # http://stackoverflow.com/questions/3654619/matplotlib-multiple-y-axes-grid-lines-applied-to-both
            # http://stackoverflow.com/questions/20243683/matplotlib-align-twinx-tick-marks
            # manual setting:
            #self.ax_p.set_yticks( np.linspace(self.ax_p.get_ylim()[0],self.ax_p.get_ylim()[1],nbins) )
            #ax1.set_yticks(np.linspace(ax1.get_ybound()[0], ax1.get_ybound()[1], 5))
            #ax2.set_yticks(np.linspace(ax2.get_ybound()[0], ax2.get_ybound()[1], 5))
            #http://stackoverflow.com/questions/3654619/matplotlib-multiple-y-axes-grid-lines-applied-to-both
            
            # use helper functions from matplotlib.ticker:
            #   MaxNLocator: set no more than nbins + 1 ticks
            #self.ax_p.yaxis.set_major_locator( matplotlib.ticker.MaxNLocator(nbins = nbins) )
            # further options: integer = False,
            #                   prune = [‘lower’ | ‘upper’ | ‘both’ | None] Remove edge ticks
            #   AutoLocator:
            #self.ax_p.yaxis.set_major_locator( matplotlib.ticker.AutoLocator() )
            #   LinearLocator:
            #self.ax_p.yaxis.set_major_locator( matplotlib.ticker.LinearLocator(numticks = nbins -1 ) )

#            self.ax_p.locator_params(axis = 'y', nbins = nbins)
#
#            self.ax_p.set_yticks(np.linspace(self.ax_p.get_ybound()[0],
#                                             self.ax_p.get_ybound()[1],
#                                             len(self.ax.get_yticks())-1))

            #N = source_ax.xaxis.get_major_ticks()
            #target_ax.xaxis.set_major_locator(LinearLocator(N))
        else:
            try:
                self.mplwidget.fig.delaxes(self.ax_p)
            except (KeyError, AttributeError):
                pass
        self.draw()

    def draw_inset(self):
        """
        Construct / destruct second axes for an inset second plot
        """
        # TODO:  try   ax1 = zoomed_inset_axes(ax, 6, loc=1) # zoom = 6
        # TODO: choose size & position of inset, maybe dependent on filter type
        #        or specs (i.e. where is passband etc.)
        if self.DEBUG:
            print(self.cmbInset.currentIndex(), self.mplwidget.fig.axes) # list of axes in Figure
            for ax in self.mplwidget.fig.axes:
                print(ax)
                print("cmbInset, inset_idx:",self.cmbInset.currentIndex(), self.inset_idx)
        if self.cmbInset.currentIndex() > 0:
            if self.inset_idx == 0:
                # Inset was turned off before, create a new one
                #  Add an axes at position rect [left, bottom, width, height]:
                self.ax_i = self.mplwidget.fig.add_axes([0.65, 0.61, .3, .3])
                self.ax_i.clear() # clear old plot and specs

                # draw an opaque background with the extent of the inset plot:
#                self.ax_i.patch.set_facecolor('green') # without label area
#                self.mplwidget.fig.patch.set_facecolor('green') # whole figure
                extent = self.mplwidget.full_extent(self.ax_i, pad = 0.0)
                # Transform this back to figure coordinates - otherwise, it
                #  won't behave correctly when the size of the plot is changed:
                extent = extent.transformed(self.mplwidget.fig.transFigure.inverted())
                rect = Rectangle((extent.xmin, extent.ymin), extent.width,
                        extent.height, facecolor=(1.0,1.0,1.0), edgecolor='none',
                        transform=self.mplwidget.fig.transFigure, zorder=-1)
                self.ax_i.patches.append(rect)

                self.ax_i.set_xlim(fb.fil[0]['freqSpecsRange'])
                self.ax_i.plot(self.F, self.H_plt, lw = fb.gD['rc']['lw'])

            if self.cmbInset.currentIndex() == 1: # edit / navigate inset
                self.ax_i.set_navigate(True)
                self.ax.set_navigate(False)
                if self.specs:
                    self.plotSpecLimits(specAxes = self.ax_i)
            else: # edit / navigate main plot
                self.ax_i.set_navigate(False)
                self.ax.set_navigate(True)
        else:  # inset has been turned off, delete it
            self.ax.set_navigate(True)
            try:
                #remove ax_i from the figure
                self.mplwidget.fig.delaxes(self.ax_i)
            except AttributeError:
                pass

        self.inset_idx = self.cmbInset.currentIndex() # update index
        self.draw()
コード例 #6
0
ファイル: plot_3d.py プロジェクト: euripedesrocha/pyFDA
class Plot3D(QtGui.QMainWindow):
    
    """
    Class for various 3D-plots:
    - lin / log line plot of H(f)
    - lin / log surf plot of H(z)
    - optional display of poles / zeros
    """

    def __init__(self, parent = None, DEBUG = False): # default parent = None -> top Window
        super(Plot3D, self).__init__(parent) # initialize QWidget base class
#        QtGui.QMainWindow.__init__(self) # alternative syntax

        self.DEBUG = DEBUG
        self.zmin = 0
        self.zmax = 4
        self.zmin_dB = -80
        
        self.lblLog = QtGui.QLabel("Log.")
        self.chkLog = QtGui.QCheckBox(self)
        self.chkLog.setObjectName("chkLog")
        self.chkLog.setToolTip("Logarithmic scale")
        self.chkLog.setChecked(False)
        
        self.lblBottom = QtGui.QLabel("Bottom:")

        self.ledBottom = QtGui.QLineEdit(self)
        self.ledBottom.setObjectName("ledBottom")
        self.ledBottom.setText(str(self.zmin))
        self.ledBottom.setToolTip("Minimum display value.")
        
        self.lblTop = QtGui.QLabel("Top:")

        self.ledTop = QtGui.QLineEdit(self)
        self.ledTop.setObjectName("ledTop")
        self.ledTop.setText(str(self.zmax))
        self.ledTop.setToolTip("Maximum display value.")
#        self.ledTop.setSizePolicy(QtGui.QSizePolicy.Maximum, QtGui.QSizePolicy.Maximum)

        self.lblUC = QtGui.QLabel(self)
        self.lblUC.setText("UC")
        self.chkUC = QtGui.QCheckBox(self)
        self.chkUC.setObjectName("chkUC")
        self.chkUC.setToolTip("Plot unit circle")
        self.chkUC.setChecked(True)
        
        self.lblPZ = QtGui.QLabel(self)
        self.lblPZ.setText("P/Z")
        self.chkPZ = QtGui.QCheckBox(self)
        self.chkPZ.setObjectName("chkPZ")
        self.chkPZ.setToolTip("Plot poles and zeros")
        self.chkPZ.setChecked(True)
        
        self.lblHf = QtGui.QLabel(self)
        self.lblHf.setText("H(f)")
        self.chkHf = QtGui.QCheckBox(self)
        self.chkHf.setObjectName("chkHf")
        self.chkHf.setToolTip("Plot H(f) along the unit circle")
        self.chkHf.setChecked(True)
        
        modes = ['None', 'Mesh', 'Surf', 'Contour']
        self.cmbMode3D = QtGui.QComboBox(self)
        self.cmbMode3D.addItems(modes)
        self.cmbMode3D.setObjectName("cmbShow3D")
        self.cmbMode3D.setToolTip("Select 3D-plot mode.")
        self.cmbMode3D.setCurrentIndex(0)
        self.cmbMode3D.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
        
        self.lblColBar = QtGui.QLabel(self)
        self.lblColBar.setText("Colorbar")
        self.chkColBar = QtGui.QCheckBox(self)
        self.chkColBar.setObjectName("chkColBar")
        self.chkColBar.setToolTip("Show colorbar")
        self.chkColBar.setChecked(False)
        
        self.diaAlpha = QtGui.QDial(self)
        self.diaAlpha.setRange(0.,10.)
        self.diaAlpha.setValue(5)
        self.diaAlpha.setTracking(False) # produce less events when turning
        self.diaAlpha.setFixedHeight(30)
        self.diaAlpha.setFixedWidth(30)
        self.diaAlpha.setWrapping(False)
        self.diaAlpha.setToolTip("Set transparency for surf and contour plot.")
        
        self.diaHatch = QtGui.QDial(self)
        self.diaHatch.setRange(0.,9.)
        self.diaHatch.setValue(5)
        self.diaHatch.setTracking(False) # produce less events when turning
        self.diaHatch.setFixedHeight(30)
        self.diaHatch.setFixedWidth(30)
        self.diaHatch.setWrapping(False)
        self.diaHatch.setToolTip("Set hatching for H(jw).")
        
        self.lblContour2D = QtGui.QLabel(self)
        self.lblContour2D.setText("Contour2D")
        self.chkContour2D = QtGui.QCheckBox(self)
        self.chkContour2D.setObjectName("chkContour2D")
        self.chkContour2D.setToolTip("Plot 2D-contours for real and imaginary part")
        self.chkContour2D.setChecked(False)
        
        self.layHChkBoxes = QtGui.QHBoxLayout()
        self.layHChkBoxes.addStretch(10)

        self.layHChkBoxes.addWidget(self.lblLog)
        self.layHChkBoxes.addWidget(self.chkLog)
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.lblBottom)
        self.layHChkBoxes.addWidget(self.ledBottom)
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.lblTop)
        self.layHChkBoxes.addWidget(self.ledTop)
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.lblUC)
        self.layHChkBoxes.addWidget(self.chkUC)  
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.lblPZ)
        self.layHChkBoxes.addWidget(self.chkPZ)                   
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.lblHf)
        self.layHChkBoxes.addWidget(self.chkHf)        
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.cmbMode3D)
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.lblColBar)
        self.layHChkBoxes.addWidget(self.chkColBar)
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.diaAlpha)
        self.layHChkBoxes.addWidget(self.diaHatch)
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.lblContour2D)
        self.layHChkBoxes.addWidget(self.chkContour2D) 

        self.layHChkBoxes.addStretch(1)        


        self.mplwidget = MplWidget()
#        self.mplwidget.setParent(self)

        self.mplwidget.layVMainMpl.addLayout(self.layHChkBoxes)

#        self.mplwidget.setFocus()
        # make this the central widget, taking all available space:
        self.setCentralWidget(self.mplwidget)
        
        self.initAxes()
        
        self.initCoord()

        self.draw() # calculate and draw phi(f)

#        #=============================================
#        # Signals & Slots
#        #=============================================
        self.chkLog.clicked.connect(self.logClicked)
        self.ledBottom.editingFinished.connect(self.logClicked)
        self.ledTop.editingFinished.connect(self.logClicked)
        self.chkUC.clicked.connect(self.draw)
        self.chkHf.clicked.connect(self.draw)
        self.chkPZ.clicked.connect(self.draw)
        self.cmbMode3D.currentIndexChanged.connect(self.draw)
        self.chkColBar.clicked.connect(self.draw)
        self.diaAlpha.valueChanged.connect(self.draw)
        self.diaHatch.valueChanged.connect(self.draw)
        self.chkContour2D.clicked.connect(self.draw)


    def initCoord(self):
        """ Initialize coordinates for the unit circle """
        # TODO: move creation of x,y-grid here as well 
        self.phi_EK = np.linspace(0, 2*pi, 400, endpoint = True)
        self.xy_UC = np.exp(1j * self.phi_EK) # x,y coordinates of unity circle

    def initAxes(self):
        """Initialize and clear the axes
        see http://stackoverflow.com/questions/4575588/matplotlib-3d-plot-with-pyqt4-in-qtabwidget-mplwidget
        """
        self.mplwidget.fig.clf() # needed to get rid of colormap 
        self.ax3d = self.mplwidget.fig.add_subplot(111, projection = '3d')

        
    def logClicked(self):
        """ Change scale and settings to log / lin """
        self.log = self.chkLog.isChecked()
        if self.sender().objectName() == 'chkLog': # origin of signal that triggered the slot
            if self.log:
                
                self.ledBottom.setText(str(self.zmin_dB))
                self.zmax_dB = np.round(20 * log10(self.zmax),2)
                self.ledTop.setText(str(self.zmax_dB))
            else:
                self.ledBottom.setText(str(self.zmin))
                self.zmax = np.round(10**(self.zmax_dB / 20),2)
                self.ledTop.setText(str(self.zmax))
        else:
            if self.log:
                self.zmin_dB = float(self.ledBottom.text())
                self.zmax_dB = float(self.ledTop.text())
            else:
                self.zmin = float(self.ledBottom.text())  
                self.zmax = float(self.ledTop.text()) 
            
        self.draw()
        


    def draw(self):
        if self.mplwidget.mplToolbar.enable_update:
            self.draw_3d()


    def draw_3d(self):
        """
        Draw various 3D plots
        """
        self.initAxes() # needed to get rid of colormap

        
        bb = fb.fil[0]['ba'][0]
        aa = fb.fil[0]['ba'][1]
        
        zz = np.array(fb.fil[0]['zpk'][0])
        pp = np.array(fb.fil[0]['zpk'][1])

        wholeF = fb.fil[0]['freqSpecsRangeType'] != 'half'
        f_S = fb.fil[0]['f_S']
        N_FFT = fb.gD['N_FFT']
        alpha = self.diaAlpha.value()/10.
        
        #-----------------------------------------------------------------------------
        # Define 3D-Plotting Options
        #-----------------------------------------------------------------------------
        
        OPT_3D_POLAR_SPEC = True # Plot circular range in 3D-Plot
        OPT_3D_FORCE_ZMAX = True # Enforce absolute limit for 3D-Plot
        OPT_3D_MSTRIDE = 1 # Schrittweite für MESH und CONT3D
        OPT_3D_ALPHA = alpha#0.5 # Transparency for surface plot
        cmap = cm.jet
        # Colormaps: 'hsv', 'jet_r', 'bone', 'prism' 'gray', 'prism', 'coolwarm'
        # *_r colormaps reverse the color order
        #
        steps = 100               # number of steps for x, y, r, phi
        rmin = 0;    rmax = 1.2  # polar range definition
        #
        xmin = -1.5; xmax = 1.5  # cartesian range definition
        ymin = -1.5; ymax = 1.5
        #
        zmax_rel = 5 # Max. displayed z - value relative to max|H(f)|
        
        # Calculate limits etc. for 3D-Plots
        dr = rmax / steps * 2 
        dphi = pi / steps # grid size for polar range
        dx = (xmax - xmin) / steps  
        dy = (ymax - ymin) / steps # grid size cartesian range
        if OPT_3D_POLAR_SPEC == True: # polar grid
            [r, phi] = np.meshgrid(np.arange(rmin, rmax, dr), 
                                np.linspace(0, 2 * pi, steps, endpoint = True))
            x = r * cos(phi)
            y = r * sin(phi)
        else: # cartesian grid
            [x, y] = np.meshgrid(np.arange(xmin,xmax,dx), np.arange(ymin,ymax,dy)) 
        
        z = x + 1j*y # create coordinate grid for complex plane

        [w, H] = sig.freqz(bb, aa, N_FFT, wholeF) # calculate H(w) along the 
                                                # upper half of unity circle
                                                # w runs from 0 ... pi, length = N_FFT
        f = w / (2 * pi) * f_S                  # translate w to absolute frequencies

        H_abs = abs(H)
        H_max = max(H_abs)
        H_max_dB = 20*log10(H_max)
        F_max = f[np.argmax(H_abs)]
         
        
        H_min = min(H_abs)
        H_min_dB = 20*log10(H_min)
        F_min = f[np.argmin(H_abs)]

        plevel_rel = 1.05 # height of plotted pole position relative to zmax
        zlevel_rel = 0.1 # height of plotted zero position relative to zmax

    
        # calculate H(jw)| along the unity circle and |H(z)|, each clipped 
        # between bottom and top
        if self.chkLog.isChecked():
            bottom = np.floor(max(self.zmin_dB, H_min_dB) / 10) * 10 
            top = self.zmax_dB
            plevel_top = top + (top - bottom) * (plevel_rel - 1)
            plevel_btm = top
            zlevel = bottom - (top - bottom) * (zlevel_rel)
            H_UC = pyfda_lib.H_mag(bb, aa, self.xy_UC, top, H_min = bottom, 
                                   log = True)
            Hmag = pyfda_lib.H_mag(bb, aa, z, top, H_min = bottom, log = True)

        else: 
            bottom = max(self.zmin, H_min)
            top = self.zmax
        #   top = zmax_rel * H_max # calculate display top from max. of H(f)
            H_UC = pyfda_lib.H_mag(bb, aa, self.xy_UC, top, H_min = bottom)
            Hmag = pyfda_lib.H_mag(bb, aa, z, top, H_min = bottom)

            zlevel = zlevel_rel * top # height of displayed zero position

            if self.cmbMode3D.currentText() == 'None': # "Poleposition" for H(f) plot only
                plevel_top = H_max * 0.3 # plevel = H_max * 0.1 / zlevel = 0.1
                plevel_btm = bottom
            else:
                plevel_top = plevel_rel * top # height of displayed pole position
                plevel_btm = top

        #===============================================================
        ## plot unit circle
        #===============================================================       
        if self.chkUC.isChecked():        
        # Plot unit circle and marker at (1,0):
            self.ax3d.plot(self.xy_UC.real, self.xy_UC.imag, 
                           ones(len(self.xy_UC)) * bottom, lw = 2, color = 'k')
            self.ax3d.plot([0.97, 1.03],[0,0], [bottom, bottom], lw = 2, color = 'k')

        #===============================================================
        ## plot ||H(f)| along unit circle as 3D-lineplot
        #===============================================================        
        if self.chkHf.isChecked():
            self.ax3d.plot(self.xy_UC.real, self.xy_UC.imag, H_UC,
                           lw = fb.gD['rc']['lw'])
            self.ax3d.plot(self.xy_UC.real, self.xy_UC.imag, H_UC,
                           'w--', lw = fb.gD['rc']['lw'])

                           
            NL = 10 - self.diaHatch.value() # plot line every NL points on the UC
            if NL < 10:
                for k in range(len(self.xy_UC[::NL])):
                    self.ax3d.plot([self.xy_UC.real[::NL][k], self.xy_UC.real[::NL][k]],
                        [self.xy_UC.imag[::NL][k], self.xy_UC.imag[::NL][k]],
                        [np.ones(len(self.xy_UC[::NL]))[k]*bottom, H_UC[::NL][k]],
                         linewidth=1, color=(0.5, 0.5, 0.5))
        #===============================================================
        ## plot Poles and Zeros
        #===============================================================        
        if self.chkPZ.isChecked():

            PN_SIZE = 8 # size of P/N symbols
            
            # Plot zero markers at |H(z_i)| = zlevel with "stems":     
            self.ax3d.plot(zz.real, zz.imag, ones(len(zz)) * zlevel, 'o',
               markersize = PN_SIZE, markeredgecolor='blue', markeredgewidth=2.0,
                markerfacecolor = 'none') 
            for k in range(len(zz)): # plot zero "stems"
                self.ax3d.plot([zz[k].real, zz[k].real], [zz[k].imag, zz[k].imag],
                            [bottom, zlevel], linewidth=1, color='b')
                            
            # Plot the poles at |H(z_p)| = plevel with "stems":
            self.ax3d.plot(np.real(pp), np.imag(pp), plevel_top,
              'x', markersize = PN_SIZE, markeredgewidth=2.0, markeredgecolor='red') 
            for k in range(len(pp)): # plot pole "stems"
                self.ax3d.plot([pp[k].real, pp[k].real], [pp[k].imag, pp[k].imag],
                            [plevel_btm, plevel_top], linewidth=1, color='r')

        #===============================================================
        ## 3D-Plots of |H(z)| clipped between |H(z)| = top
        #===============================================================
        #
        ## Mesh plot
        if self.cmbMode3D.currentText() == 'Mesh':
        #    fig_mlab = mlab.figure(fgcolor=(0., 0., 0.), bgcolor=(1, 1, 1))
        #    self.ax3d.set_zlim(0,2)
            self.ax3d.plot_wireframe(x, y, Hmag, rstride=5,
                    cstride=OPT_3D_MSTRIDE, linewidth = 1, color = 'gray') 

        #---------------------------------------------------------------
        ## 3D-surface plot;
        elif self.cmbMode3D.currentText() == 'Surf':
            s = self.ax3d.plot_surface(x, y, Hmag, 
                    alpha = OPT_3D_ALPHA, rstride=1, cstride=1, cmap = cmap,
                    linewidth=0, antialiased=False, shade = True) # facecolors= cmap ??
            s.set_edgecolor('gray') 

        #---------------------------------------------------------------
        ## 3D-Contour plot
        elif self.cmbMode3D.currentText() == 'Contour': 
            s = self.ax3d.contourf3D(x, y, Hmag, 20, alpha = alpha,
                    rstride=OPT_3D_MSTRIDE, cstride=OPT_3D_MSTRIDE, cmap = cmap)
                                 
        #---------------------------------------------------------------
        ## 2D-Contour plot
        # TODO: 2D contour plots do not plot correctly together with 3D plots in
        #       current matplotlib 1.4.3 -> disable them for now
        # TODO: zdir = x / y delivers unexpected results -> rather plot max(H)
        #       along the other axis?
        # TODO: colormap is created depending on the zdir = 'z' contour plot
        #       -> set limits of (all) other plots manually?
        if self.chkContour2D.isChecked():
#            self.ax3d.contourf(x, y, Hmag, 20, zdir='x', offset=xmin, 
#                                 cmap=cmap, alpha = alpha)#, vmin = bottom)#, vmax = top, vmin = bottom)
#            self.ax3d.contourf(x, y, Hmag, 20, zdir='y', offset=ymax, 
#                               cmap=cmap, alpha = alpha)#, vmin = bottom)#, vmax = top, vmin = bottom)
            s = self.ax3d.contourf(x, y, Hmag, 20, zdir='z', 
                               offset = bottom - (top - bottom) * 0.05, 
                                cmap=cmap, alpha = alpha)
                                
        if self.cmbMode3D.currentText() in {'Contour', 'Surf'}\
                    or self.chkContour2D.isChecked():
                        if self.chkColBar.isChecked():
                            self.colb = self.mplwidget.fig.colorbar(s, 
                                ax = self.ax3d, shrink=0.8, aspect=20,
                                pad = 0.02, fraction = 0.08)
                        
                        
        self.ax3d.set_xlim3d(xmin, xmax)
        self.ax3d.set_ylim3d(ymin, ymax)
        self.ax3d.set_zlim3d(bottom, top)
        
        self.ax3d.set_xlabel('Re')#(fb.fil[0]['plt_fLabel'])
        self.ax3d.set_ylabel('Im') #(r'$ \tau_g(\mathrm{e}^{\mathrm{j} \Omega}) / T_S \; \rightarrow $')
#        self.ax3d.set_zlabel(r'$|H(z)|\; \rightarrow $')
        self.ax3d.set_title(r'3D-Plot of $|H(\mathrm{e}^{\mathrm{j} \Omega})|$ and $|H(z)|$')
        
        self.mplwidget.redraw()
コード例 #7
0
class PlotImpz(QtGui.QMainWindow):
    def __init__(self,
                 parent=None,
                 DEBUG=False):  # default parent = None -> top Window
        super(PlotImpz, self).__init__(parent)  # initialize QWidget base class
        #        QtGui.QMainWindow.__init__(self) # alternative syntax

        self.DEBUG = DEBUG
        self.ACTIVE_3D = False

        self.lblLog = QtGui.QLabel(self)
        self.lblLog.setText("Log.")
        self.chkLog = QtGui.QCheckBox(self)
        self.chkLog.setObjectName("chkLog")
        self.chkLog.setToolTip("Show logarithmic impulse / step response.")
        self.chkLog.setChecked(False)

        self.lblLogBottom = QtGui.QLabel("Log. bottom:")

        self.ledLogBottom = QtGui.QLineEdit(self)
        self.ledLogBottom.setText("-80")
        self.ledLogBottom.setToolTip("Minimum display value for log. scale.")

        self.lblNPoints = QtGui.QLabel("<i>N</i> =")

        self.ledNPoints = QtGui.QLineEdit(self)
        self.ledNPoints.setText("0")
        self.ledNPoints.setToolTip(
            "Number of points to calculate and display.\n"
            "N = 0 chooses automatically.")

        self.lblStep = QtGui.QLabel("Step Response")
        self.chkStep = QtGui.QCheckBox()
        self.chkStep.setChecked(False)
        self.chkStep.setToolTip(
            "Show step response instead of impulse response.")

        self.lblLockZoom = QtGui.QLabel("Lock Zoom")
        self.chkLockZoom = QtGui.QCheckBox()
        self.chkLockZoom.setChecked(False)
        self.chkLockZoom.setToolTip("Lock zoom to current setting.")

        self.layHChkBoxes = QtGui.QHBoxLayout()
        self.layHChkBoxes.addStretch(10)
        self.layHChkBoxes.addWidget(self.lblLog)
        self.layHChkBoxes.addWidget(self.chkLog)
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.lblLogBottom)
        self.layHChkBoxes.addWidget(self.ledLogBottom)
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.lblStep)
        self.layHChkBoxes.addWidget(self.chkStep)
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.lblLockZoom)
        self.layHChkBoxes.addWidget(self.chkLockZoom)
        self.layHChkBoxes.addStretch(1)
        self.layHChkBoxes.addWidget(self.lblNPoints)
        self.layHChkBoxes.addWidget(self.ledNPoints)
        self.layHChkBoxes.addStretch(10)

        self.mplwidget = MplWidget()
        #        self.mplwidget.setParent(self)

        self.mplwidget.layVMainMpl.addLayout(self.layHChkBoxes)
        #        self.mplwidget.layVMainMpl1.addWidget(self.mplwidget)

        #        self.mplwidget.setFocus()
        # make this the central widget, taking all available space:
        self.setCentralWidget(self.mplwidget)

        #        self.setLayout(self.layHChkBoxes)

        self.draw()  # calculate and draw |H(f)|

        #        #=============================================
        #        # Signals & Slots
        #        #=============================================
        self.chkLog.clicked.connect(self.draw)
        self.chkStep.clicked.connect(self.draw)
        self.ledNPoints.editingFinished.connect(self.draw)
        self.ledLogBottom.editingFinished.connect(self.draw)

    def initAxes(self):
        # clear the axes and (re)draw the plot
        #
        try:
            self.mplwidget.fig.delaxes(self.ax_r)
            self.mplwidget.fig.delaxes(self.ax_i)
        except (KeyError, AttributeError, UnboundLocalError):
            pass

        if self.cmplx:
            self.ax_r = self.mplwidget.fig.add_subplot(211)
            self.ax_r.clear()
            self.ax_i = self.mplwidget.fig.add_subplot(212)
            self.ax_i.clear()
        else:
            self.ax_r = self.mplwidget.fig.add_subplot(111)
            self.ax_r.clear()

        if self.ACTIVE_3D:
            self.ax3d = Axes3D(fig)

    def draw(self):
        if self.mplwidget.mplToolbar.enable_update:
            self.draw_impz()

    def draw_impz(self):
        """
        (Re-)calculate h[n] and draw the figure
        """
        log = self.chkLog.isChecked()
        step = self.chkStep.isChecked()
        self.lblLogBottom.setEnabled(log)
        self.ledLogBottom.setEnabled(log)

        #        if np.ndim(fb.fil[0]['coeffs']) == 1: # FIR

        self.bb = fb.fil[0]['ba'][0]
        self.aa = fb.fil[0]['ba'][1]

        self.f_S = fb.fil[0]['f_S']
        self.F_PB = fb.fil[0]['F_PB'] * self.f_S
        self.F_SB = fb.fil[0]['F_SB'] * self.f_S

        self.A_PB = fb.fil[0]['A_PB']
        self.A_PB2 = fb.fil[0]['A_PB2']
        self.A_SB = fb.fil[0]['A_SB']
        self.A_SB2 = fb.fil[0]['A_SB2']

        if self.DEBUG:
            print("--- plotHf.draw() --- ")
            print("b, a = ", self.bb, self.aa)

        # calculate h[n]
        [h, t] = pyfda_lib.impz(self.bb,
                                self.aa,
                                self.f_S,
                                step=step,
                                N=int(self.ledNPoints.text()))

        if step:
            title_str = r'Step Response'
            H_str = r'$h_{\epsilon}[n]$'
        else:
            title_str = r'Impulse Response'
            H_str = r'$h[n]$'

        self.cmplx = np.any(np.iscomplex(h))
        if self.cmplx:
            h_i = h.imag
            h = h.real
            H_i_str = r'$\Im\{$' + H_str + '$\}$'
            H_str = r'$\Re\{$' + H_str + '$\}$'
        if log:
            bottom = float(self.ledLogBottom.text())
            H_str = r'$\log$ ' + H_str + ' in dB'
            h = np.maximum(20 * np.log10(abs(h)), bottom)
            if self.cmplx:
                h_i = np.maximum(20 * np.log10(abs(h_i)), bottom)
                H_i_str = r'$\log$ ' + H_i_str + ' in dB'
        else:
            bottom = 0

        self.initAxes()

        #================ Main Plotting Routine =========================
        [ml, sl, bl] = self.ax_r.stem(t,
                                      h,
                                      bottom=bottom,
                                      markerfmt='bo',
                                      linefmt='r')
        self.ax_r.set_xlim([min(t), max(t)])
        self.ax_r.set_title(title_str)

        if self.cmplx:
            [ml_i, sl_i, bl_i] = self.ax_i.stem(t,
                                                h_i,
                                                bottom=bottom,
                                                markerfmt='rd',
                                                linefmt='b')
            self.ax_i.set_xlabel(fb.fil[0]['plt_tLabel'])
            self.ax_r.set_ylabel(H_str + r'$\rightarrow $')
            self.ax_i.set_ylabel(H_i_str + r'$\rightarrow $')
        else:
            self.ax_r.set_xlabel(fb.fil[0]['plt_tLabel'])
            self.ax_r.set_ylabel(H_str + r'$\rightarrow $')

        if self.ACTIVE_3D:  # not implemented yet

            # plotting the stems
            for i in range(len(t)):
                self.ax3d.plot([t[i], t[i]], [h[i], h[i]], [0, h_i[i]],
                               '-',
                               linewidth=2,
                               color='b',
                               alpha=.5)

            # plotting a circle on the top of each stem
            self.ax3d.plot(t,
                           h,
                           h_i,
                           'o',
                           markersize=8,
                           markerfacecolor='none',
                           color='b',
                           label='ib')

            self.ax3d.set_xlabel('x')
            self.ax3d.set_ylabel('y')
            self.ax3d.set_zlabel('z')

#        fig.setp(ml, 'markerfacecolor', 'r', 'markersize', 8)
#       ax.setp(sl, lw = fb.gD['rc']['lw'])
#      print(self.mplwidget.plt_lim)
#      ax.axis(self.mplwidget.plt_lim)

#        if self.mplwidget.plt_lim == [] or not self.chkLockZoom.isChecked():
#
#            self.mplwidget.plt_lim = t_lim + y_lim
#            self.mplwidget.x_lim = t_lim

        self.mplwidget.redraw()