Ejemplo n.º 1
0
def FuT(roots_in, *kwargs):
    """Select Function-Under-Test (FuT)"""
    return unique_roots(roots_in,
                        tol=1e-3,
                        magsort=magsort,
                        rtype=rtype,
                        rdist=rdist)
Ejemplo n.º 2
0
    def sort_dict_freqs(self):
        """
        - Sort visible filter dict frequency spec entries with ascending frequency if 
             the sort button is activated
        - Update the visible QLineEdit frequency widgets

        The method is called when:
        - update_UI has been called after changing the filter design algorithm                                # that the response type has been changed 
          eg. from LP -> HP, requiring a different order of frequency entries
        - a frequency spec field has been edited
        - the sort button has been clicked (from filter_specs.py)
        """

        f_specs = [
            fb.fil[0][str(self.qlineedit[i].objectName())]
            for i in range(self.n_cur_labels)
        ]
        if fb.fil[0]['freq_specs_sort']:
            f_specs.sort()

        # Make sure normalized freqs are in the range ]0, 0.5[ and are different
        # by at least MIN_FREQ_STEP
        for i in range(self.n_cur_labels):
            if f_specs[i] <= MIN_FREQ:
                logger.warning("Frequencies must be > 0, changed {0} from {1:.4g} to {2:.4g}."\
                               .format(str(self.qlineedit[i].objectName()),f_specs[i]*fb.fil[0]['f_S'],
                                       (MIN_FREQ + MIN_FREQ_STEP)*fb.fil[0]['f_S']))
                f_specs[i] = MIN_FREQ + MIN_FREQ_STEP
            if f_specs[i] >= MAX_FREQ:
                logger.warning("Frequencies must be < f_S /2, changed {0} from {1:.4g} to {2:.4g}."\
                               .format(str(self.qlineedit[i].objectName()),f_specs[i]*fb.fil[0]['f_S'],
                                       (MAX_FREQ - MIN_FREQ_STEP)*fb.fil[0]['f_S']))
                f_specs[i] = MAX_FREQ - MIN_FREQ_STEP

            fb.fil[0][str(self.qlineedit[i].objectName())] = f_specs[i]

        # check for (nearly) identical elements:
        _, mult = unique_roots(f_specs, tol=MIN_FREQ_STEP)
        ident = [x for x in mult if x > 1]
        if ident:
            logger.warning("Frequencies must differ by at least {0:.4g}"\
                           .format(MIN_FREQ_STEP * fb.fil[0]['f_S']))

        self.load_dict()
Ejemplo n.º 3
0
    def sort_dict_freqs(self):
        """
        - Sort visible filter dict frequency spec entries with ascending frequency if 
             the sort button is activated
        - Update the visible QLineEdit frequency widgets

        The method is called when:
        - update_UI has been called after changing the filter design algorithm                                # that the response type has been changed 
          eg. from LP -> HP, requiring a different order of frequency entries
        - a frequency spec field has been edited
        - the sort button has been clicked (from filter_specs.py)
        """
        
        f_specs = [fb.fil[0][str(self.qlineedit[i].objectName())]
                        for i in range(self.n_cur_labels)]
        if fb.fil[0]['freq_specs_sort']:
            f_specs.sort()

        # Make sure normalized freqs are in the range ]0, 0.5[ and are different
        # by at least MIN_FREQ_STEP
        for i in range(self.n_cur_labels):
            if f_specs[i] <= MIN_FREQ:
                logger.warning("Frequencies must be > 0, changed {0} from {1:.4g} to {2:.4g}."\
                               .format(str(self.qlineedit[i].objectName()),f_specs[i]*fb.fil[0]['f_S'],
                                       (MIN_FREQ + MIN_FREQ_STEP)*fb.fil[0]['f_S']))
                f_specs[i] = MIN_FREQ + MIN_FREQ_STEP
            if f_specs[i] >= MAX_FREQ:
                logger.warning("Frequencies must be < f_S /2, changed {0} from {1:.4g} to {2:.4g}."\
                               .format(str(self.qlineedit[i].objectName()),f_specs[i]*fb.fil[0]['f_S'],
                                       (MAX_FREQ - MIN_FREQ_STEP)*fb.fil[0]['f_S']))
                f_specs[i] = MAX_FREQ - MIN_FREQ_STEP

            fb.fil[0][str(self.qlineedit[i].objectName())] = f_specs[i]
            
        # check for (nearly) identical elements:
        _, mult = unique_roots(f_specs, tol = MIN_FREQ_STEP)
        ident = [x for x in mult if x > 1]
        if ident:
            logger.warning("Frequencies must differ by at least {0:.4g}"\
                           .format(MIN_FREQ_STEP * fb.fil[0]['f_S']))

        self.load_dict()
Ejemplo n.º 4
0
def FuT(roots_in, *kwargs):
    """Select Function-Under-Test (FuT)"""
    return unique_roots(roots_in, tol=1e-3, magsort = magsort, rtype = rtype, rdist = rdist)
Ejemplo n.º 5
0
   def zplane(self, b=None, a=1, z=None, p=None, k =1,  pn_eps=1e-3, analog=False, plt_ax = None,
             verbose=False, style='square', anaCircleRad=0, lw=2,
             mps = 10, mzs = 10, mpc = 'r', mzc = 'b', plabel = '', zlabel = ''):
       """
       Plot the poles and zeros in the complex z-plane either from the
       coefficients (`b,`a) of a discrete transfer function `H`(`z`) (zpk = False)
       or directly from the zeros and poles (z,p) (zpk = True).
   
       When only b is given, an FIR filter with all poles at the origin is assumed.
   
       Parameters
       ----------
       b :  array_like
            Numerator coefficients (transversal part of filter)
            When b is not None, poles and zeros are determined from the coefficients
            b and a
   
       a :  array_like (optional, default = 1 for FIR-filter)
            Denominator coefficients (recursive part of filter)
            
       z :  array_like, default = None
            Zeros
            When b is None, poles and zeros are taken directly from z and p
   
       p :  array_like, default = None
            Poles
   
       analog : boolean (default: False)
           When True, create a P/Z plot suitable for the s-plane, i.e. suppress
           the unit circle (unless anaCircleRad > 0) and scale the plot for
           a good display of all poles and zeros.
   
       pn_eps : float (default : 1e-2)
            Tolerance for separating close poles or zeros
            
       plt_ax : handle to axes for plotting (default: None)
           When no axes is specified, the current axes is determined via plt.gca()
   
       pltLib :  string (default: 'matplotlib')
            Library for plotting the P/Z plane. Currently, only matplotlib is
            implemented. When pltLib = 'none' or when matplotlib is not
            available, only pass the poles / zeros and their multiplicity
   
       verbose : boolean (default: False)
           When verbose == True, print poles / zeros and their multiplicity.
   
       style : string (default: 'square')
           Style of the plot, for style == 'square' make scale of x- and y-
           axis equal.
   
       mps : integer  (default: 10)
           Size for pole marker
           
       mzs : integer (default: 10)
           Size for zero marker
           
       mpc : char (default: 'r')
           Pole marker colour
           
       mzc : char (default: 'b')
           Zero marker colour
           
       lw : integer (default:  2)
           Linewidth for unit circle
   
       plabel, zlabel : string (default: '')
           This string is passed to the plot command for poles and zeros and
           can be displayed by legend()
   
   
       Returns
       -------
       z, p, k : ndarray
   
   
       Notes
       -----
   
       """
       # TODO:
       # - polar option
       # - add keywords for size, color etc. of markers and circle -> **kwargs
       # - add option for multi-dimensional arrays and zpk data
   
       # make sure that all inputs are arrays
       b = np.atleast_1d(b) 
       a = np.atleast_1d(a)
       z = np.atleast_1d(z) # make sure that p, z  are arrays
       p = np.atleast_1d(p)
   
       if b.any(): # coefficients were specified
           if len(b) < 2 and len(a) < 2:
               logger.error('No proper filter coefficients: both b and a are scalars!')
               return z, p, k
           
           # The coefficients are less than 1, normalize the coefficients
           if np.max(b) > 1:
               kn = np.max(b)
               b = b / float(kn) 
           else:
               kn = 1.
   
           if np.max(a) > 1:
               kd = np.max(a)
               a = a / abs(kd)
           else:
               kd = 1.
   
           # Calculate the poles, zeros and scaling factor
           p = np.roots(a)
           z = np.roots(b)
           k = kn/kd
       elif not (len(p) or len(z)): # P/Z were specified
               logger.error('Either b,a or z,p must be specified!')
               return z, p, k
 
       # find multiple poles and zeros and their multiplicities
       if len(p) < 2: # single pole, [None] or [0]
           if not p or p == 0: # only zeros, create equal number of poles at origin
               p = np.array(0,ndmin=1) # 
               num_p = np.atleast_1d(len(z))
           else:
               num_p = [1.] # single pole != 0
       else:
           #p, num_p = sig.signaltools.unique_roots(p, tol = pn_eps, rtype='avg')
           p, num_p = unique_roots(p, tol = pn_eps, rtype='avg')
   #        p = np.array(p); num_p = np.ones(len(p))
       if len(z) > 0:
           z, num_z = unique_roots(z, tol = pn_eps, rtype='avg')
   #        z = np.array(z); num_z = np.ones(len(z))
           #z, num_z = sig.signaltools.unique_roots(z, tol = pn_eps, rtype='avg')
       else:
           num_z = []
   
   
       ax = plt_ax#.subplot(111)
       if analog == False:
           # create the unit circle for the z-plane
           uc = patches.Circle((0,0), radius=1, fill=False,
                               color='grey', ls='solid', zorder=1)
           ax.add_patch(uc)
           if style == 'square':
               r = 1.1
               ax.axis([-r, r, -r, r], 'equal')
               ax.axis('equal')
       #    ax.spines['left'].set_position('center')
       #    ax.spines['bottom'].set_position('center')
       #    ax.spines['right'].set_visible(True)
       #    ax.spines['top'].set_visible(True)
   
       else: # s-plane
           if anaCircleRad > 0:
               # plot a circle with radius = anaCircleRad
               uc = patches.Circle((0,0), radius=anaCircleRad, fill=False,
                                   color='grey', ls='solid', zorder=1)
               ax.add_patch(uc)
           # plot real and imaginary axis
           ax.axhline(lw=2, color = 'k', zorder=1)
           ax.axvline(lw=2, color = 'k', zorder=1)
   
       # Plot the zeros
       ax.scatter(z.real, z.imag, s=mzs*mzs, zorder=2, marker = 'o',
                  facecolor = 'none', edgecolor = mzc, lw = lw, label=zlabel)
   #        t1 = plt.plot(z.real, z.imag, 'go', ms=10, label=label)
   #        plt.setp( t1, markersize=mzs, markeredgewidth=2.0,
   #                  markeredgecolor=mzc, markerfacecolor='none')
       # Plot the poles
       ax.scatter(p.real, p.imag, s=mps*mps, zorder=2, marker='x',
                  color=mpc, lw=lw, label=plabel)
   
        # Print multiplicity of poles / zeros
       for i in range(len(z)):
           if verbose == True: print('z', i, z[i], num_z[i])
           if num_z[i] > 1:
               ax.text(np.real(z[i]), np.imag(z[i]),'  (' + str(num_z[i]) +')',va = 'bottom')
   
       for i in range(len(p)):
           if verbose == True: print('p', i, p[i], num_p[i])
           if num_p[i] > 1:
               ax.text(np.real(p[i]), np.imag(p[i]), '  (' + str(num_p[i]) +')',va = 'bottom')
   
           # increase distance between ticks and labels
           # to give some room for poles and zeros
       for tick in ax.get_xaxis().get_major_ticks():
           tick.set_pad(12.)
           tick.label1 = tick._get_text1()
       for tick in ax.get_yaxis().get_major_ticks():
           tick.set_pad(12.)
           tick.label1 = tick._get_text1()
   
       xl = ax.get_xlim(); Dx = max(abs(xl[1]-xl[0]), 0.05)
       yl = ax.get_ylim(); Dy = max(abs(yl[1]-yl[0]), 0.05)
       ax.set_xlim((xl[0]-Dx*0.05, max(xl[1]+Dx*0.05,0)))
       ax.set_ylim((yl[0]-Dy*0.05, yl[1] + Dy*0.05))
   #    print(ax.get_xlim(),ax.get_ylim())
   
   
       return z, p, k
Ejemplo n.º 6
0
#vals = np.roots(np.convolve(ones(500),ones(100))) # 100 double and 400 single complex roots,
#vals = np.roots(np.convolve(ones(500),ones(500))) # 500 double complex roots

#vals = np.roots(np.convolve(ones(5),ones(7))) # 4 double complex roots

## tests with nans 
#vals = list(ones(5) * 1j); vals.append(np.nan); vals.append(np.nan)
#vals = []
#print(vals)

Navg = 1000
rtype = 'min'
print('============ dsp.unique_roots() ================================')
t1 = time.clock()
for i in range(Navg):
    roots, mult = dsp.unique_roots(vals, rtype = rtype, rdist='manhattan')
t2 = time.clock()
T_dsp = (t2 - t1)/Navg
print (mult)

print('============ signal.unique_roots() =============================')
t1 = time.clock()
for i in range(Navg):
    roots, mult = sig.unique_roots(vals, rtype = rtype)
t2 = time.clock()
T_sig = (t2 - t1)/Navg
print (mult)

print("T_dsp = ",T_dsp, " s")
print("T_sig = ",T_sig, " s")
print("T_dsp / T_sig = ", T_dsp / T_sig)
Ejemplo n.º 7
0
   def zplane(self, b=None, a=1, z=None, p=None, k =1,  pn_eps=1e-3, analog=False, plt_ax = None,
             verbose=False, style='square', anaCircleRad=0, lw=2,
             mps = 10, mzs = 10, mpc = 'r', mzc = 'b', plabel = '', zlabel = ''):
       """
       Plot the poles and zeros in the complex z-plane either from the
       coefficients (`b,`a) of a discrete transfer function `H`(`z`) (zpk = False)
       or directly from the zeros and poles (z,p) (zpk = True).
   
       When only b is given, an FIR filter with all poles at the origin is assumed.
   
       Parameters
       ----------
       b :  array_like
            Numerator coefficients (transversal part of filter)
            When b is not None, poles and zeros are determined from the coefficients
            b and a
   
       a :  array_like (optional, default = 1 for FIR-filter)
            Denominator coefficients (recursive part of filter)
            
       z :  array_like, default = None
            Zeros
            When b is None, poles and zeros are taken directly from z and p
   
       p :  array_like, default = None
            Poles
   
       analog : boolean (default: False)
           When True, create a P/Z plot suitable for the s-plane, i.e. suppress
           the unit circle (unless anaCircleRad > 0) and scale the plot for
           a good display of all poles and zeros.
   
       pn_eps : float (default : 1e-2)
            Tolerance for separating close poles or zeros
            
       plt_ax : handle to axes for plotting (default: None)
           When no axes is specified, the current axes is determined via plt.gca()
   
       pltLib :  string (default: 'matplotlib')
            Library for plotting the P/Z plane. Currently, only matplotlib is
            implemented. When pltLib = 'none' or when matplotlib is not
            available, only pass the poles / zeros and their multiplicity
   
       verbose : boolean (default: False)
           When verbose == True, print poles / zeros and their multiplicity.
   
       style : string (default: 'square')
           Style of the plot, for style == 'square' make scale of x- and y-
           axis equal.
   
       mps : integer  (default: 10)
           Size for pole marker
           
       mzs : integer (default: 10)
           Size for zero marker
           
       mpc : char (default: 'r')
           Pole marker colour
           
       mzc : char (default: 'b')
           Zero marker colour
           
       lw : integer (default:  2)
           Linewidth for unit circle
   
       plabel, zlabel : string (default: '')
           This string is passed to the plot command for poles and zeros and
           can be displayed by legend()
   
   
       Returns
       -------
       z, p, k : ndarray
   
   
       Notes
       -----
   
       """
       # TODO:
       # - polar option
       # - add keywords for size, color etc. of markers and circle -> **kwargs
       # - add option for multi-dimensional arrays and zpk data
   
       # make sure that all inputs are arrays
       b = np.atleast_1d(b) 
       a = np.atleast_1d(a)
       z = np.atleast_1d(z) # make sure that p, z  are arrays
       p = np.atleast_1d(p)
   
       if b.any(): # coefficients were specified
           if len(b) < 2 and len(a) < 2:
               logger.error('No proper filter coefficients: both b and a are scalars!')
               return z, p, k
           
           # The coefficients are less than 1, normalize the coefficients
           if np.max(b) > 1:
               kn = np.max(b)
               b = b / float(kn) 
           else:
               kn = 1.
   
           if np.max(a) > 1:
               kd = np.max(a)
               a = a / abs(kd)
           else:
               kd = 1.
   
           # Calculate the poles, zeros and scaling factor
           p = np.roots(a)
           z = np.roots(b)
           k = kn/kd
       elif not (len(p) or len(z)): # P/Z were specified
           logger.error('Either b,a or z,p must be specified!')
           return z, p, k
 
       # find multiple poles and zeros and their multiplicities
       if len(p) < 2: # single pole, [None] or [0]
           if not p or p == 0: # only zeros, create equal number of poles at origin
               p = np.array(0,ndmin=1) # 
               num_p = np.atleast_1d(len(z))
           else:
               num_p = [1.] # single pole != 0
       else:
           #p, num_p = sig.signaltools.unique_roots(p, tol = pn_eps, rtype='avg')
           p, num_p = unique_roots(p, tol = pn_eps, rtype='avg')
   #        p = np.array(p); num_p = np.ones(len(p))
       if len(z) > 0:
           z, num_z = unique_roots(z, tol = pn_eps, rtype='avg')
   #        z = np.array(z); num_z = np.ones(len(z))
           #z, num_z = sig.signaltools.unique_roots(z, tol = pn_eps, rtype='avg')
       else:
           num_z = []
   
   
       ax = plt_ax#.subplot(111)
       if analog == False:
           # create the unit circle for the z-plane
           uc = patches.Circle((0,0), radius=1, fill=False,
                               color='grey', ls='solid', zorder=1)
           ax.add_patch(uc)
           if style == 'square':
               r = 1.1
               ax.axis([-r, r, -r, r], 'equal')
               ax.axis('equal')
       #    ax.spines['left'].set_position('center')
       #    ax.spines['bottom'].set_position('center')
       #    ax.spines['right'].set_visible(True)
       #    ax.spines['top'].set_visible(True)
   
       else: # s-plane
           if anaCircleRad > 0:
               # plot a circle with radius = anaCircleRad
               uc = patches.Circle((0,0), radius=anaCircleRad, fill=False,
                                   color='grey', ls='solid', zorder=1)
               ax.add_patch(uc)
           # plot real and imaginary axis
           ax.axhline(lw=2, color = 'k', zorder=1)
           ax.axvline(lw=2, color = 'k', zorder=1)
   
       # Plot the zeros
       ax.scatter(z.real, z.imag, s=mzs*mzs, zorder=2, marker = 'o',
                  facecolor = 'none', edgecolor = mzc, lw = lw, label=zlabel)
   #        t1 = plt.plot(z.real, z.imag, 'go', ms=10, label=label)
   #        plt.setp( t1, markersize=mzs, markeredgewidth=2.0,
   #                  markeredgecolor=mzc, markerfacecolor='none')
       # Plot the poles
       ax.scatter(p.real, p.imag, s=mps*mps, zorder=2, marker='x',
                  color=mpc, lw=lw, label=plabel)
   
        # Print multiplicity of poles / zeros
       for i in range(len(z)):
           if verbose == True: print('z', i, z[i], num_z[i])
           if num_z[i] > 1:
               ax.text(np.real(z[i]), np.imag(z[i]),'  (' + str(num_z[i]) +')',va = 'bottom')
   
       for i in range(len(p)):
           if verbose == True: print('p', i, p[i], num_p[i])
           if num_p[i] > 1:
               ax.text(np.real(p[i]), np.imag(p[i]), '  (' + str(num_p[i]) +')',va = 'bottom')
   
           # increase distance between ticks and labels
           # to give some room for poles and zeros
       for tick in ax.get_xaxis().get_major_ticks():
           tick.set_pad(12.)
           tick.label1 = tick._get_text1()
       for tick in ax.get_yaxis().get_major_ticks():
           tick.set_pad(12.)
           tick.label1 = tick._get_text1()
   
       xl = ax.get_xlim(); Dx = max(abs(xl[1]-xl[0]), 0.05)
       yl = ax.get_ylim(); Dy = max(abs(yl[1]-yl[0]), 0.05)
       ax.set_xlim((xl[0]-Dx*0.05, max(xl[1]+Dx*0.05,0)))
       ax.set_ylim((yl[0]-Dy*0.05, yl[1] + Dy*0.05))
   #    print(ax.get_xlim(),ax.get_ylim())
   
       return z, p, k