コード例 #1
0
ファイル: filter_design.py プロジェクト: rngeorge/gwpy
def parse_filter(args, analog=False, sample_rate=None):
    """Parse arbitrary input args into a TF or ZPK filter definition

    Parameters
    ----------
    args : `tuple`, `~scipy.signal.lti`
        filter definition, normally just captured positional ``*args``
        from a function call

    analog : `bool`, optional
        `True` if filter definition has analogue coefficients

    sample_rate : `float`, optional
        sampling frequency at which to convert analogue filter to digital
        via bilinear transform, required if ``analog=True``

    Returns
    -------
    ftype : `str`
        either ``'ba'`` or ``'zpk'``
    filt : `tuple`
        the filter components for the returned `ftype`, either a 2-tuple
        for with transfer function components, or a 3-tuple for ZPK
    """
    if analog and not sample_rate:
        raise ValueError("Must give sample_rate frequency to convert "
                         "analog filter to digital")

    # unpack filter
    if isinstance(args, tuple) and len(args) == 1:
        # either packed defintion ((z, p, k)) or simple definition (lti,)
        args = args[0]

    # parse FIR filter
    if isinstance(args, numpy.ndarray) and args.ndim == 1:  # fir
        b, a = args, [1.]
        if analog:
            return 'ba', signal.bilinear(b, a)
        return 'ba', (b, a)

    # parse IIR filter
    if isinstance(args, LinearTimeInvariant):
        lti = args
    elif (isinstance(args, numpy.ndarray) and args.ndim == 2
          and args.shape[1] == 6):
        lti = signal.lti(*signal.sos2zpk(args))
    else:
        lti = signal.lti(*args)

    # convert to zpk format
    lti = lti.to_zpk()

    # convert to digital components
    if analog:
        return 'zpk', bilinear_zpk(lti.zeros,
                                   lti.poles,
                                   lti.gain,
                                   fs=sample_rate)
    # return zpk
    return 'zpk', (lti.zeros, lti.poles, lti.gain)
コード例 #2
0
def plot_sos(sos, worN=5000, fs=44.1e3, show=True):
    """

    Visualize a second order system. 
    
    
    ---------------------------------------------------------------------
    INPUTS
    ---------------------------------------------------------------------
    sos				| as specified in scipy.signal
    ---------------------------------------------------------------------
    otherwise, see plot_zpk
    ---------------------------------------------------------------------

    """
    z, p, k = sig.sos2zpk(sos)
    plot_zpk(z, p, k, worN=worN, fs=fs, show=show)
コード例 #3
0
ファイル: generate_iirs.py プロジェクト: henkmuller/lib_dsp
				filer_str += (q_format_str + '(' +str(-sos[section_index, coef_index]) + '),')
			filer_str += ("\n")
		for section_index in range(sos.shape[0], max_biquad_order):
			for coef_index in range(5):
				filer_str += ('0.0,')
		filer_str += ("},\n")

		print (abs(z),abs(p))

		q_sos = np.zeros(sos.shape)
		one =np.int64(1<<(q_factor+1)) + 1
		for section_index in range(sos.shape[0]):
			for coef_index in range(sos.shape[1]):
				q_sos[section_index, coef_index]= np.float64(int(one*sos[section_index, coef_index])>>1) / np.float64(np.int64(1<<(q_factor)))
			try:
				z,p,k= signal.sos2zpk(q_sos)
				print (abs(z),abs(p))
				print "good"
			except:
				print "bad"

	filer_str += ("},\n")
	q_factor_str += ("},\n")
	biquad_orders_str += ("},\n")

filer_str += "};\n"
q_factor_str += "};\n"
biquad_orders_str+= "};\n"

impl_file.write(filer_str)
impl_file.write(biquad_orders_str)
コード例 #4
0
def fil_convert(fil_dict, format_in):
    """
    Convert between poles / zeros / gain, filter coefficients (polynomes)
    and second-order sections and store all formats not generated by the filter
    design routine in the passed dictionary 'fil_dict'.

    Parameters
    ----------
    fil_dict :  dictionary
         filter dictionary
    
    format_in :  string or set of strings
         format(s) generated by the filter design routine. Must be one of
         'zpk': [z,p,k] where z is the array of zeros, p the array of poles and
             k is a scalar with the gain
         'ba' : [b, a] where b and a are the polynomial coefficients
         'sos' : a list of second order sections
    

    """

    if 'zpk' in format_in:  # z, p, k have been generated,convert to other formats
        zpk = fil_dict['zpk']
        if 'ba' not in format_in:
            fil_dict['ba'] = sig.zpk2tf(zpk[0], zpk[1], zpk[2])
        if 'sos' not in format_in and SOS_AVAIL:
            try:
                fil_dict['sos'] = sig.zpk2sos(zpk[0], zpk[1], zpk[2])
            except ValueError:
                fil_dict['sos'] = 'None'
                print(
                    "WARN (pyfda_lib): Complex-valued coefficients, could not convert to SOS."
                )

    elif 'sos' in format_in and SOS_AVAIL:
        if 'zpk' not in format_in:
            fil_dict['zpk'] = list(sig.sos2zpk(fil_dict['sos']))
            # check whether sos conversion has created a additional (superfluous)
            # pole and zero at the origin and delete them:
            z_0 = np.where(fil_dict['zpk'][0] == 0)[0]
            p_0 = np.where(fil_dict['zpk'][1] == 0)[0]
            if p_0 and z_0:  # eliminate z = 0 and p = 0 from list:
                fil_dict['zpk'][0] = np.delete(fil_dict['zpk'][0], z_0)
                fil_dict['zpk'][1] = np.delete(fil_dict['zpk'][1], p_0)

        if 'ba' not in format_in:
            fil_dict['ba'] = list(sig.sos2tf(fil_dict['sos']))
            # check whether sos conversion has created additional (superfluous)
            # highest order polynomial with coefficient 0 and delete them
            if fil_dict['ba'][0][-1] == 0 and fil_dict['ba'][1][-1] == 0:
                fil_dict['ba'][0] = np.delete(fil_dict['ba'][0], -1)
                fil_dict['ba'][1] = np.delete(fil_dict['ba'][1], -1)

    elif 'ba' in format_in:  # arg = [b,a]
        b, a = fil_dict['ba'][0], fil_dict['ba'][1]
        fil_dict['zpk'] = list(sig.tf2zpk(b, a))
        if SOS_AVAIL:
            try:
                fil_dict['sos'] = sig.tf2sos(b, a)
            except ValueError:
                fil_dict['sos'] = 'None'
                print(
                    "WARN (pyfda_lib): Complex-valued coefficients, could not convert to SOS."
                )

    else:
        raise ValueError("Unknown input format {0:s}".format(format_in))
コード例 #5
0
    sos_e = signal.ellip(2 * n_ellip,
                         ripple,
                         stop,
                         Fs_cut / Fs_in,
                         btype='low',
                         output='sos')
    if n_ellip > 1:
        k = np.sqrt(np.sum(sos_e[0, :3]**2))
        k_n = k**(1 / (n_ellip - 1))
        sos_e[0, :3] /= k
        sos_e[1:, :3] *= k_n
    sos = np.vstack((sos, sos_e))

sos_q = np.around((sos - 1e-9) * 2**23) / 2**23

z, p, k = signal.sos2zpk(sos)
zq, pq, kq = signal.sos2zpk(sos_q)
plt.figure()
plt.plot(np.real(z), np.imag(z), 'o')
plt.plot(np.real(p), np.imag(p), 'x')
plt.plot(np.real(zq), np.imag(z), 'ro')
plt.plot(np.real(pq), np.imag(p), 'rx')
ucx = np.cos(np.linspace(0, 2 * np.pi, 1000))
ucy = np.sin(np.linspace(0, 2 * np.pi, 1000))
plt.plot(ucx, ucy, 'k-')
plt.axis('equal')

# Plot response
b, a = signal.sos2tf(sos)
bq, aq = signal.sos2tf(sos_q)
w, h = signal.freqz(b, a=a)
コード例 #6
0
w = np.logspace(np.log10(wmin), np.log10(wmax), num=num_w)

# Filter design
shelving_filters = []
zpks = []
H = np.zeros((len(Biquad_per_octave), num_w), dtype='complex')
Gain = np.zeros(len(Biquad_per_octave))
for n, biquad_per_octave in enumerate(Biquad_per_octave):
    num_biquad, Gb, G = \
        shelving_filter_parameters(biquad_per_octave=biquad_per_octave,
                                   Gd=Gd, BWd=BWd)
    Gain[n] = G
    sos = low_shelving_2nd_cascade(w0, Gb, num_biquad, biquad_per_octave)
    H[n] = sosfreqs(sos, worN=w)[1]
    shelving_filters.append(sos)
    zpks.append(sos2zpk(sos))

# desired response
wl, wh = w0 * 2**(-BWd), w0
Hmag = np.clip(np.log2(w / w0) * slope, G, 0)
Hmag = np.log2(w / w0) * slope

# Plots
Glim = -0.21, 0.21
philim = -3, 47
wlim = wmin, wmax
wticks = 2**(np.arange(
    np.ceil(np.log2(w)[0] / 2) * 2,
    np.floor(np.log2(w[-1]) / 2) * 2 + 2, 2))
kw = {'lw': 2, 'alpha': 1, 'basex': 2}
colors = cm.get_cmap('Blues')
コード例 #7
0
                   zoh='Zero-Order Hold')

num_freqs = 200
images_path = pathlib.Path('images/experiments/')
images_path.mkdir(parents=True, exist_ok=True)

for i, filter_type in enumerate(filter_list):
    for j, method in enumerate(method_list):

        # Get filter (meta)data
        filter_filename = f'type-{filter_type}_method-{method}.npz'
        filter_data = np.load(filter_filename, allow_pickle=True)
        sos = filter_data['sos']
        sos_quant = filter_data['sos_quant']
        final_spec = filter_data['final_spec'].item()
        discrete_system = signal.sos2zpk(sos)

        # Get filter experiment data
        experiment_filename = f'experiments/exp-{filter_type}_{method}.csv'
        data = pd.read_csv(experiment_filename).to_dict('series')

        # print(data['freq'].values, data['amp'].values)
        # exit(0)

        print(
            f'Analog filter: {filter_type} | Analog-to-Discrete Method: {method}'
        )

        # Plot
        fig, ax = plt.subplots()
        # filtdesign.plot_digital(sos_quant, Qformat, fp, fs, Amax, Amin, magnitude=sinewave_amplitude, num_freqs=num_freqs, ax=ax, plot_focus='all')
コード例 #8
0
# Time-domain evaluation
fs = 48000
ws = 2 * np.pi * fs
Lh = 1500
t = np.arange(Lh) / fs
xin = unit_impulse(Lh)
t = np.arange(Lh) / fs
s2z = matchedz_zpk
# s2z = bilinear_zpk

# Analog filter
H = np.zeros(num_w, dtype='complex')
num_biquad, Gb, G = shelving_filter_parameters(
    biquad_per_octave=biquad_per_octave, slope=slope, BWd=BWd)
sos_sdomain = low_shelving_2nd_cascade(w0, Gb, num_biquad, biquad_per_octave)
zs, ps, ks = sos2zpk(sos_sdomain)

# Digital filter
zpk = s2z(zs * 2 * np.pi * fc, ps * 2 * np.pi * fc, ks, fs=fs)
sos_zdomain = zpk2sos(*zpk)
H = sosfreqz(sos_zdomain, worN=f, fs=fs)[1]
h = sosfilt(sos_zdomain, xin)

# Plots
flim = fmin, fmax
fticks = fc * 2.**np.arange(-8, 4, 2)
fticklabels = ['7.8', '31.3', '125', '500', '2k', '8k']
fticks = 1000 * 2.**np.arange(-6, 6, 2)
fticklabels = ['15.6', '62.5', '250', '1k', '4k', '16k']
kw = dict(c='C0', lw=2, alpha=1)
コード例 #9
0
ファイル: lp_butter.py プロジェクト: hidmic/fwliir
ax.plot(w, np.angle(h_t))
ax.set_xlabel('Frecuencia [Hz]')
ax.set_ylabel('Fase [rad]')
ax.grid(which='both', axis='both')

ax = fig.add_subplot(313)
ax.plot(t, im_min_n)
ax.plot(t, im_min_err)
ax.plot(t, im_t)
ax.set_xlabel('Tiempo [s]')
ax.set_ylabel('Amplitud [1]')
ax.grid(which='both', axis='both')

zeros_o, poles_o, gains_o = [], [], []
for iir in pool:
    z, p, k = signal.sos2zpk(fwliir.iir2sos(iir))
    zeros_o.extend(z)
    poles_o.extend(p)
    gains_o.append(k)
zeros_t, poles_t, gain_t = signal.tf2zpk(b_t, a_t)
zeros_min_n, poles_min_n, gain_min_n = signal.sos2zpk(sos_min_n)
zeros_min_err, poles_min_err, gain_min_err = signal.sos2zpk(sos_min_err)

fig = plt.figure()
ax = fig.add_subplot(311)
# ax.scatter(x=np.real(zeros_o), y=np.imag(zeros_o), color='yellow')
ax.scatter(x=np.real(zeros_t), y=np.imag(zeros_t), color='blue')
ax.scatter(x=np.real(zeros_min_err), y=np.imag(zeros_min_err), color='red')
ax.scatter(x=np.real(zeros_min_n), y=np.imag(zeros_min_n), color='green')
ax.axis([-2, 2, -2, 2])
ax = fig.add_subplot(312)
コード例 #10
0
# frequency response
fig, ax = plt.subplots(figsize=(10, 4), ncols=2, gridspec_kw={'wspace': 0.1})
ax[0].semilogx(w, db(H_biquads.T), c='gray', **kw, zorder=2)
ax[0].semilogx(w, Hmag, 'k:', **kw)
ax[0].semilogx(w, db(H), c='C0', **kw, zorder=3)

ax[1].plot([-1, 0], [1, 0], 'C7:', lw=1)

# Pole zero plot
kw_z = dict(c='C0', marker='o', ms=9, ls='none', mew=1, mfc='none', alpha=1)
kw_p = dict(c='k', marker='x', ms=9, ls='none', mew=1)
kw_dot = dict(marker='.', ms=10)
ylim = ax[0].get_ylim()
for n, sosi in enumerate(sos):
    z, p, _ = sos2zpk(sosi[np.newaxis, :])
    z, p = z[0], p[0]
    wc = np.abs(np.sqrt(z * p))

    ax[0].plot((wc, wc), (-3, 0), **kw_dotted)
    ax[0].plot(wc, Gb / 2, c='gray', zorder=2, **kw_dot)
    ax[1].plot(wc * -np.cos(np.pi / 4),
               wc * np.sin(np.pi / 4),
               c='gray',
               **kw_dot)
    ax[1].plot(np.real(p), np.imag(p), **kw_p)
    ax[1].plot(np.real(z), np.imag(z), **kw_z)
    circle = plt.Circle(xy=(0, 0), radius=wc, facecolor='none', **kw_artist)
    ax[1].add_artist(circle)
ax[0].plot(np.sqrt(wh * wl), G / 2, 'C0', **kw_dot)
コード例 #11
0
num_freqs = 200
images_path = pathlib.Path('images')
images_path.mkdir(parents=True, exist_ok=True)

for i, filter_type in enumerate(filter_list):
    for j, method in enumerate(method_list):

        # Get filter (meta)data
        filter_filename = f'type-{filter_type}_method-{method}.npz'
        filter_data = np.load(filter_filename, allow_pickle=True)

        sos = filter_data['sos']
        sos_quant = filter_data['sos_quant']
        final_spec = filter_data['final_spec'].item()
        discrete_system = signal.sos2zpk(sos)

        print(f'Analog filter: {filter_type} | Analog-to-Discrete Method: {method}')
        # print(f'Biquads:\n', sos)
        # print(f'Quantized biquads (Q{Qformat[0]}.{Qformat[1]}):\n', np.round(sos_quant * 2 ** Qformat[1]).astype(int))

        print_biquads(sos_quant)

        zd, pd, kd = signal.sos2zpk(sos)
        zq, pq, kq = signal.sos2zpk(sos_quant)

        
        # Plot
        fig, ax = plt.subplots()
        unit_circle = patches.Circle((0,0), radius=1, fill=False, color='black', ls='solid', alpha=0.1)
        ax.add_patch(unit_circle)