Пример #1
0
    def process(self):

        if (self.signals is None or len(self.signals) == 0):
            raise NameError('No signal to beamform')

        if self.processing is 'FrequencyDomain':

            # create window function
            win = np.concatenate((np.zeros(self.zpf),
                                  windows.hann(self.L), 
                                  np.zeros(self.zpb)))

            # do real STFT of first signal
            tfd_sig = stft.stft(self.signals[0], 
                                self.L, 
                                self.hop, 
                                zp_back=self.zpb, 
                                zp_front=self.zpf,
                                transform=np.fft.rfft, 
                                win=win) * np.conj(self.weights[0])
            for i in xrange(1, self.M):
                tfd_sig += stft.stft(self.signals[i],
                                     self.L,
                                     self.hop,
                                     zp_back=self.zpb,
                                     zp_front=self.zpf,
                                     transform=np.fft.rfft,
                                     win=win) * np.conj(self.weights[i])

            #  now reconstruct the signal
            output = stft.istft(
                tfd_sig,
                self.L,
                self.hop,
                zp_back=self.zpb,
                zp_front=self.zpf,
                transform=np.fft.irfft)

            # remove the zero padding from output signal
            if self.zpb is 0:
                output = output[self.zpf:]
            else:
                output = output[self.zpf:-self.zpb]

        elif self.processing is 'TimeDomain':

            # go back to time domain and shift DC to center
            tw = np.sqrt(self.weights.shape[1])*np.fft.irfft(np.conj(self.weights), axis=1)
            tw = np.concatenate((tw[:, self.N/2:], tw[:, :self.N/2]), axis=1)

            from scipy.signal import fftconvolve

            # do real STFT of first signal
            output = fftconvolve(tw[0], self.signals[0])
            for i in xrange(1, len(self.signals)):
                output += fftconvolve(tw[i], self.signals[i])

        elif self.processing is 'Total':

            W = np.concatenate((self.weights, np.conj(self.weights[:,-2:0:-1])), axis=1)
            W[:,0] = np.real(W[:,0])
            W[:,self.N/2] = np.real(W[:,self.N/2])

            F_sig = np.zeros(self.signals.shape[1], dtype=complex)
            for i in xrange(self.M):
                F_sig += np.fft.fft(self.signals[i])*np.conj(W[i,:])

            f_sig = np.fft.ifft(F_sig)
            print np.abs(np.imag(f_sig)).mean()
            print np.abs(np.real(f_sig)).mean()

            output = np.real(np.fft.ifft(F_sig))

        return output
Пример #2
0
def tf_agc(d, sr, t_scale=0.5, f_scale=1.0, causal_tracking=True, plot=False):
    """
    Perform frequency-dependent automatic gain control on an auditory
    frequency axis.
    d is the input waveform (at sampling rate sr);
    y is the output waveform with approximately constant
    energy in each time-frequency patch.
    t_scale is the "scale" for smoothing in time (default 0.5 sec).
    f_scale is the frequency "scale" (default 1.0 "mel").
    causal_tracking == 0 selects traditional infinite-attack, exponential release.
    causal_tracking == 1 selects symmetric, non-causal Gaussian-window smoothing.
    D returns actual STFT used in analysis.  E returns the
    smoothed amplitude envelope divided out of D to get gain control.
    """

    hop_size = 0.032  # in seconds

    # Make STFT on ~32 ms grid
    ftlen = int(2 ** np.round(np.log(hop_size * sr) / np.log(2.)))
    winlen = ftlen
    hoplen = winlen / 2
    D = stft(d, winlen, hoplen)  # using my code
    ftsr = sr / hoplen
    ndcols = D.shape[1]

    # Smooth in frequency on ~ mel resolution
    # Width of mel filters depends on how many you ask for,
    # so ask for fewer for larger f_scales
    nbands = max(10, 20 / f_scale)  # 10 bands, or more for very fine f_scale
    mwidth = f_scale * nbands / 10  # will be 2.0 for small f_scale
    (f2a_tmp, _) = fft2melmx(ftlen, sr, int(nbands), mwidth)
    f2a = f2a_tmp[:, :ftlen / 2 + 1]
    audgram = np.dot(f2a, np.abs(D))

    if causal_tracking:
        # traditional attack/decay smoothing
        fbg = np.zeros(audgram.shape)
        # state = zeros(size(audgram,1),1);
        state = np.zeros(audgram.shape[0])
        alpha = np.exp(-(1. / ftsr) / t_scale)
        for i in range(audgram.shape[1]):
            state = np.maximum(alpha * state, audgram[:, i])
            fbg[:, i] = state

    else:
        # noncausal, time-symmetric smoothing
        # Smooth in time with tapered window of duration ~ t_scale
        tsd = np.round(t_scale * ftsr) / 2
        htlen = 6 * tsd  # Go out to 6 sigma
        twin = np.exp(-0.5 * (((np.arange(-htlen, htlen + 1)) / tsd) ** 2)).T

        # reflect ends to get smooth stuff
        AD = audgram
        x = np.hstack((np.fliplr(AD[:, :htlen]),
                       AD,
                       np.fliplr(AD[:, -htlen:]),
                       np.zeros((AD.shape[0], htlen))))
        fbg = signal.lfilter(twin, 1, x, 1)

        # strip "warm up" points
        fbg = fbg[:, twin.size + np.arange(ndcols)]

    # map back to FFT grid, flatten bark loop gain
    sf2a = np.sum(f2a, 0)
    sf2a_fix = sf2a
    sf2a_fix[sf2a == 0] = 1.
    E = np.dot(np.dot(np.diag(1. / sf2a_fix), f2a.T), fbg)
    # Remove any zeros in E (shouldn't be any, but who knows?)
    E[E <= 0] = np.min(E[E > 0])

    # invert back to waveform
    y = istft(D / E, winlen, hoplen, window=np.ones(winlen))  # using my code

    if plot:
        try:
            import matplotlib.pyplot as plt
            plt.subplot(3, 1, 1)
            plt.imshow(20. * np.log10(np.flipud(np.abs(D))))
            plt.subplot(3, 1, 2)
            plt.imshow(20. * np.log10(np.flipud(np.abs(E))))
            A = stft(y, winlen, hoplen)  # using my code
            plt.subplot(3, 1, 3)
            plt.imshow(20. * np.log10(np.flipud(np.abs(A))))
            plt.show()
        except Exception, e:
            print "Failed to plot results"
            print e
    def process(self, FD=False):

        if self.signals is None or len(self.signals) == 0:
            raise NameError('No signal to beamform')

        if FD is True:

            # STFT processing

            if self.weights is None and self.filters is not None:
                self.weightsFromFilters()
            elif self.weights is None and self.filters is None:
                raise NameError('Beamforming weights or filters need to be computed first.')

            # create window function
            win = np.concatenate((np.zeros(self.zpf),
                                  windows.hann(self.L), 
                                  np.zeros(self.zpb)))

            # do real STFT of first signal
            tfd_sig = stft.stft(self.signals[0], 
                                self.L, 
                                self.hop, 
                                zp_back=self.zpb, 
                                zp_front=self.zpf,
                                transform=np.fft.rfft, 
                                win=win) * np.conj(self.weights[0])
            for i in xrange(1, self.M):
                tfd_sig += stft.stft(self.signals[i],
                                     self.L,
                                     self.hop,
                                     zp_back=self.zpb,
                                     zp_front=self.zpf,
                                     transform=np.fft.rfft,
                                     win=win) * np.conj(self.weights[i])

            #  now reconstruct the signal
            output = stft.istft(
                tfd_sig,
                self.L,
                self.hop,
                zp_back=self.zpb,
                zp_front=self.zpf,
                transform=np.fft.irfft)

            # remove the zero padding from output signal
            if self.zpb is 0:
                output = output[self.zpf:]
            else:
                output = output[self.zpf:-self.zpb]

        else:

            # TD processing

            if self.weights is not None and self.filters is None:
                self.filtersFromWeights()
            elif self.weights is None and self.filters is None:
                raise NameError('Beamforming weights or filters need to be computed first.')

            from scipy.signal import fftconvolve

            # do real STFT of first signal
            output = fftconvolve(self.filters[0], self.signals[0])
            for i in xrange(1, len(self.signals)):
                output += fftconvolve(self.filters[i], self.signals[i])


        return output