Ejemplo n.º 1
0
    def _process_waveforms(self, waveforms):
        """Process the waveforms with the DataLogger information."""
        # Correcting electric Field with actual length of dipole
        for runid in self.runlist:
            try:
                mask = ((waveforms.index > self.runinfo[runid]['Start']) &
                        (waveforms.index < self.runinfo[runid]['End']))
                waveforms["QN"].loc[mask] *= (100.0/self.runinfo[runid]['Ex'])  # mV/km
                waveforms["QE"].loc[mask] *= (100.0/self.runinfo[runid]['Ey'])  # mV/km

            # If there's no info about length, then use default length.
            except KeyError:
                pass

        if self.zpk is None:
            return waveforms

        # Filtering waveforms by NIMS system response
        for channel in waveforms:   # loop for FE, FN, FZ, QN, QE
            for filt in self.zpk[channel]:   # loop for filter
                zval = self.zpk[channel][filt]['z']
                pval = self.zpk[channel][filt]['p']
                kval = self.zpk[channel][filt]['k']

                # convert analog zpk to digital filter
                zval, pval, kval = bilinear_zpk(zval, pval, kval, self.samplingrate)
                b, a = zpk2tf(zval, pval, kval)

                waveforms[channel] = filtfilt(b, a, waveforms[channel].interpolate())
        return waveforms
Ejemplo n.º 2
0
    def C_Sos_design(self):
        """
        Create filter coefficients of the C-weighting filter. Uses the bilinear
        transform to convert the analog filter to a digital one.

        Returns:
            Sos: Second order sections
        """
        fs = self.fs
        p1 = 2 * np.pi * self.f1
        p4 = 2 * np.pi * self.f4
        zeros_analog = [0, 0]
        poles_analog = [-p1, -p1, -p4, -p4]
        k_analog = p4**2 / self._C_uncor(self.fr)

        z, p, k = bilinear_zpk(zeros_analog, poles_analog, k_analog, fs)
        sos = zpk2sos(z, p, k)
        return sos
Ejemplo n.º 3
0
def PinkNoise(fs, fstart=10, fend=None, N=3):
    """
    Creates SOS filter for pink noise. The filter has a flat response below
    fstart, and rolls of close to Nyquist, or flattens out above fend. The
    ripple (i.e.) closeness the filter rolls of depends on the number of
    sections. The default, N=3 results in

    Args:
        fs: Sampling frequency [Hz]
        fstart: Frequency of first pole of the filter
        fend: Frequency of last pole of the filter, if not given, set to 5/6th
        of the Nyquist frequency.
        N: Number of sections.

    Returns:
        sos: Array of digital filter coefficients

    """
    order = N * 2
    if fend is None:
        fend = 5 * fs / 6 / 2
    # Not the fastest implementation, but this will not be the bottleneck
    # anyhow.
    fpoles = np.array(
        [fstart * (fend / fstart)**(n / (order - 1)) for n in range(order)])

    # Put zeros inbetween poles
    fzeros = np.sqrt(fpoles[1:] * fpoles[:-1])

    poles = -2 * np.pi * fpoles
    zeros = -2 * np.pi * fzeros

    z, p, k = bilinear_zpk(zeros, poles, 1, fs=fs)

    # Compute the frequency response and search for the gain at fstart, we
    # normalize such that this gain is ~ 0 dB. Rounded to an integer frequency
    # in Hz.
    Omg, h = freqz_zpk(z, p, k, worN=int(fs / 2), fs=fs)
    h_fstart = np.abs(h[int(fstart)])
    k *= 1 / h_fstart

    sos = zpk2sos(z, p, k)

    return sos
Ejemplo n.º 4
0
exit()

# numtaps_iir = 55
# b, a = utils.yulewalk(numtaps_iir, filt_gains_freq / np.max(filt_gains_freq), filt_gains_clean)
# w, h = freqz(b, a, worN=32768)
# w_hz = w / max(w) * RATE / 2
#
# utils.plot_resp(abs(h), w_hz, '-', '%i tap IIR filter' % numtaps_iir, meas_type='IIR/gain filter response', plot_in_db=True, xlim=[st_freq, en_freq], log_x=plot_log)
# plt.legend()
# # plt.ylim([-2, 10])
# plt.savefig('plot_%s_iir-%i_fir-%i.png' % (freq_filt_str, numtaps_iir, numtaps_fir))
# plt.show()


z, p, k = bilinear_zpk([0.0, 0.0, 0.0, 0.0], [-129.4, -129.4, -676.7, -4636.0, -76655.0, -76655.0], 7.39705E9, RATE)
b, a = zpk2tf(z, p, k)

print('B taps:')
for tap in b:
    print('{:10.12f}'.format(tap))

print('A taps:')
for tap in a:
    print('{:10.12f}'.format(tap))

w, h = freqz(b, a, worN=32768)
w_hz = w / max(w) * RATE / 2

utils.plot_resp(abs(h), w_hz, '-', '%i tap A weighting IIR filter' % len(a), meas_type='IIR/gain filter response', plot_in_db=True, xlim=[st_freq, en_freq], log_x=plot_log)
plt.show()
Ejemplo n.º 5
0
def crrc_shaper(order, peaktime, dt=1E-9, pz=0.0):
    rc = peaktime / order
    poles = np.full(order + 1, -1. / rc)
    zeros = np.array([-pz])
    dzpk = signal.bilinear_zpk(zeros, poles, 1, 1. / dt)
    return dzpk, (zeros, poles)
Ejemplo n.º 6
0
def gaussian_shaper(order, peaktime, dt=1E-9, pz=0.0, user_tf=None):

    # Based on Ohkawa 1976
    #"Direct synthesis of the Gaussian filter for nuclear pulse amplifiers"

    if order == 1:
        tf = 2 * 1.0844
        poles = [complex(-1, 0)]
    elif order == 2:
        tf = 9.734458e-01
        c = np.sqrt(np.sqrt(2) + 2) * 0.5
        poles = [
            c * complex(-1,
                        np.sqrt(2) - 1), c * complex(-1, 1 - np.sqrt(2))
        ]
    elif order == 3:
        tf = 6.740357e-01
        poles = [
            complex(-1.2633573, 0),
            complex(-1.1490948, 0.7864188),
            complex(-1.1490948, -0.7864188)
        ]
    elif order == 4:
        tf = 5.106046e-01
        poles = [
            complex(-1.3553576, 0.3277948),
            complex(-1.3553576, -0.3277948),
            complex(-1.1810803, 1.0603749),
            complex(-1.1810803, -1.0603749)
        ]
    elif order == 5:
        tf = 4.267639e-01
        poles = [
            complex(-1.4766878, 0),
            complex(-1.4166647, 0.5978596),
            complex(-1.4166647, -0.5978596),
            complex(-1.2036832, 1.2994843),
            complex(-1.2036832, -1.2994843)
        ]
    elif order == 6:
        tf = 3.737515e-01
        poles = [
            complex(-1.5601279, 0.2686793),
            complex(-1.5601279, -0.2686793),
            complex(-1.4613750, 0.8329565),
            complex(-1.4613750, -0.8329565),
            complex(-1.2207388, 1.5145343),
            complex(-1.2207388, -1.5145343)
        ]
    elif order == 7:
        tf = 3.371212e-01
        poles = [
            complex(-1.6610245, 0),
            complex(-1.6229725, 0.5007975),
            complex(-1.6229725, -0.5007975),
            complex(-1.4949993, 1.0454546),
            complex(-1.4949993, -1.0454546),
            complex(-1.2344141, 1.7113028),
            complex(-1.2344141, -1.7113028)
        ]
    else:
        raise ValueError(
            'only gaussian shaper orders between 1 and 7 are supported')

    #this gave roughly the right answer, but a separate script solved for the tf values above, which give extremely acurate peaking times
    #sigma = 2 * 1.0844 * peaktime * (1./order)
    if user_tf is not None:
        tf = user_tf
    sigma = tf * peaktime
    poles = np.array(poles) / sigma
    zeros = np.array([-pz])
    dzpk = signal.bilinear_zpk(zeros, poles, 1, 1. / dt)
    return dzpk, (zeros, poles)
from scipy import signal
import matplotlib.pyplot as plt

fs = 100
bf = 2 * np.pi * np.array([7, 13])
filts = signal.lti(*signal.butter(4, bf, btype='bandpass', analog=True, output='zpk'))
filtz = signal.lti(*signal.bilinear_zpk(filts.zeros, filts.poles, filts.gain, fs))
wz, hz = signal.freqz_zpk(filtz.zeros, filtz.poles, filtz.gain)
ws, hs = signal.freqs_zpk(filts.zeros, filts.poles, filts.gain, worN=fs*wz)
plt.semilogx(wz*fs/(2*np.pi), 20*np.log10(np.abs(hz).clip(1e-15)), label=r'$|H(j \omega)|$')
plt.semilogx(wz*fs/(2*np.pi), 20*np.log10(np.abs(hs).clip(1e-15)), label=r'$|H_z(e^{j \omega})|$')
plt.legend()
plt.xlabel('Frequency [Hz]')
plt.ylabel('Magnitude [dB]')
plt.grid()