def test_FakeInterface_output(self): h_pri = np.random.normal(0, 1, 5) h_sec = np.random.normal(0, 1, 24) buffsize = 16 buffers = 100 signal = np.random.normal(0, 1, size=buffers * buffsize) sim = FakeInterface(buffsize, signal, h_pri=h_pri, h_sec=h_sec) ys = [] xs = [] es = [] us = [] ds = [] for _ in range(buffers): y = np.random.normal(0, 1, buffsize) x, e, u, d = sim.playrec(y, send_signal=True) xs.append(x) es.append(e) ds.append(d) us.append(u) ys.append(y) y = np.concatenate(ys) x = np.concatenate(xs) e = np.concatenate(es) u = np.concatenate(us) d = np.concatenate(ds) assert np.all(x == signal) npt.assert_almost_equal(d, olafilt(h_pri, x)) npt.assert_almost_equal(u, olafilt(h_sec, y)) npt.assert_almost_equal(e, u + d)
def playrec(self, y, send_signal=True): """Simulatenously play through secondary path while recording the result. Parameters ---------- y : (blocklength,) ndarray Control signal. send_signal : bool, optional If `False`, turn of the disturbance. Can be used to 'measure' the secondary path. Returns ------- x, e, u, d : (blocklength,) ndarray Reference signal, error signal, control signal at error microphone, primary at error microphone. """ if y is None: y = np.zeros((self.blocklength, *self._orig_h_sec.shape[3:4])) else: y = np.atleast_1d(y) if send_signal: x = np.atleast_1d(next(self.signal)) # reference signal else: x = np.zeros((self.blocklength, *self._orig_signal.shape[1:2])) subscripts_sec = ( "nlm"[: self._orig_h_sec.ndim - 1] + "," + "nm"[: y.ndim] + "->n" ) subscripts_pri = ( "nlk"[: self._orig_h_pri.ndim - 1] + "," + "nk"[: self._orig_signal.ndim] + "->n" ) if self._orig_h_sec.ndim - 1 > 1: subscripts_sec += "l" subscripts_pri += "l" # primary path signal at error mic d, self._zi_pri = olafilt(next(self.h_pri), x, subscripts_pri, zi=self._zi_pri) # secondary path signal at error mic u, self._zi_sec = olafilt(next(self.h_sec), y, subscripts_sec, zi=self._zi_sec) e = d + u # error signal if self.noise is not None: e += next(self.noise) return x, e, u, d
def test_wiener_filter_unconstrained_causal(self): h = [1, -1, 0.5] x = np.random.normal(size=2**16) y = olafilt(h, x) h_est = -np.real( np.fft.ifft(wiener_filter(x, y, 32, constrained=False))) npt.assert_almost_equal(h, h_est[:len(h)], decimal=2)
def test_wiener_filter_constrained_noncausal(self): h = [1, 0, 1] x = np.random.normal(size=2**16) y = olafilt(h, x) h_est = -np.real( np.fft.ifft(wiener_filter(x, y, 256, g=[0, 1], constrained=True))) npt.assert_almost_equal([0, 1, 0], h_est[:len(h)], decimal=2)
def test_FakeInterface_output_multichannel(self): L, M, K = 10, 5, 3 npri = 1024 nsec = 512 h_pri = np.random.normal(size=(npri, L, K)) h_sec = np.random.normal(size=(nsec, L, M)) buffsize = 16 buffers = 100 signal = np.random.normal(size=(buffers * buffsize, K)) noise = np.random.normal(size=(buffers * buffsize, L)) sim = FakeInterface(buffsize, signal, noise=noise, h_pri=h_pri, h_sec=h_sec) ys = [] xs = [] es = [] us = [] ds = [] for _ in range(buffers): y = np.random.normal(size=(buffsize, M)) x, e, u, d = sim.playrec(y, send_signal=True) ys.append(y) xs.append(x) es.append(e) ds.append(d) us.append(u) y = np.concatenate(ys) x = np.concatenate(xs) e = np.concatenate(es) u = np.concatenate(us) d = np.concatenate(ds) assert np.all(x == signal) npt.assert_almost_equal(d, olafilt(h_pri, x, "nlk,nk->nl")) npt.assert_almost_equal(u, olafilt(h_sec, y, "nlm,nm->nl")) npt.assert_almost_equal(e, u + d + noise)
def test_nozi_multiple_inputs(self): m = 123 n = 1024 L, M = (1, 3) h = np.random.normal(size=(m, L, M)) x = np.random.normal(size=(n, )) yola = olafilt(h, x, "nlm,n->nl", zi=None) y = 0 for m in range(M): yt = lfilter(h[:, 0, m], 1, x, zi=None) y += yt npt.assert_almost_equal(y, yola[:, 0])
def test_multiple_outputs(self): m = 123 n = 1024 L = 7 h = np.random.normal(size=(m, L)) x = np.random.normal(size=n) zi = np.random.normal(size=(m - 1, L)) yola, zfola = olafilt(h, x, "nl,n->nl", zi=zi) for l in range(L): y, zf = lfilter(h[:, l], 1, x, zi=zi[:, l]) npt.assert_almost_equal(y, yola[:, l]) npt.assert_almost_equal(zf, zfola[:, l])
def test_shape(L, M, K): m = 123 n = 1024 h = np.random.normal(size=(m, L, M)) x = np.random.normal(size=(n, K)) yola = olafilt(h, x, "nlm,nk->nl") for l in range(L): y = 0 for m in range(M): for k in range(K): y += lfilter(h[:, l, m], 1, x[:, k], zi=None) npt.assert_almost_equal(y, yola[:, l], err_msg=f"{L, M, K}")
def test_behaves_like_scipy(self): m = 123 n = 1024 h = np.random.normal(size=m) x = np.random.normal(size=n) zi = np.random.normal(size=m - 1) yola, zfola = olafilt(h, x, zi=zi) y, zf = lfilter(h, 1, x, zi=zi) npt.assert_almost_equal(yola, y) npt.assert_almost_equal(zfola, zf) assert np.array_equal(zi.shape, zfola.shape) assert np.array_equal(zi.shape, zf.shape)
def test_nozi_many_to_many(self): m = 123 n = 1024 L, M = (10, 5) h = np.random.normal(size=(m, L, M)) x = np.random.normal(size=(n, )) yola = olafilt(h, x, "nlm,n->nl", zi=None) y = np.zeros((n, L)) for l in range(L): for m in range(M): yt = lfilter(h[:, l, m], 1, x, zi=None) y[:, l] += yt npt.assert_almost_equal(y, yola)
def test_does_not_modify_inputs(self): m = 123 n = 1024 K, L = (4, 8) x = np.random.normal(size=(n, K)) h = np.random.normal(size=(m, L, K)) zi = np.random.normal(size=(m - 1, L)) x0 = x.copy() zi0 = zi.copy() h0 = h.copy() yola, zfola = olafilt(h, x, "nlk,nk->nl", zi=zi) np.array_equal(h, h0) np.array_equal(x, x0) np.array_equal(zi, zi0)
def test_does_not_sum(self): m = 123 n = 1024 L, M, K = (4, 3, 2) h = np.random.normal(size=(m, L, M)) x = np.random.normal(size=(n, K)) zi = np.random.normal(size=(m - 1, L, M, K)) yola, zfola = olafilt(h, x, "nlm,nk->nlmk", zi=zi) y = np.zeros((n, L)) zf = np.zeros((m - 1, L)) for l in range(L): for m in range(M): for k in range(K): y, zf = lfilter(h[:, l, m], 1, x[:, k], zi=zi[:, l, m, k]) npt.assert_almost_equal(y, yola[:, l, m, k]) npt.assert_almost_equal(zf, zfola[:, l, m, k])
def test_filt(self): """MultiChannelBlockLMS.filt behaves like lfilter or olafilt.""" for (M, K) in [(M, K) for M in range(1, 4) for K in range(1, 4)]: length = 16 blocks = 16 blocklength = 16 w = np.random.normal(size=(length, M, K)) # Random filter coefficients xs = np.random.normal(size=(blocks, blocklength, K)) # blockwise input x = np.concatenate(xs) filt = MultiChannelBlockLMS( length=length, blocklength=blocklength, initial_coeff=w, Nin=K, Nout=M, Nsens=1, ) # w set correctly npt.assert_almost_equal(w, filt.w) # many blocks y = [] for xb in xs: xb_copy = xb.copy() y.append(filt.filt(xb)) assert np.array_equal(xb_copy, xb) # test that xb is not changed y = np.concatenate(y) npt.assert_almost_equal(olafilt(w, x, "nmk,nk->nm"), y) # like olafilt yref = np.zeros(y.shape) for m in range(M): for k in range(K): yref[:, m] += lfilter(w[:, m, k], 1, x[:, k]) npt.assert_almost_equal(y, yref, err_msg=f"shape: {(M, K)}") # like lfiter
def test_multiple_inputs(self): m = 123 n = 1024 L, M = (1, 3) h = np.random.normal(size=(m, L, M)) x = np.random.normal(size=(n, )) ziall = np.random.normal(size=(m - 1, L, M)) zi = ziall.sum(axis=-1) yola, zfola = olafilt(h, x, "nlm,n->nl", zi=zi) y = 0 zf = 0 for m in range(M): yt, zft = lfilter(h[:, 0, m], 1, x, zi=ziall[:, 0, m]) y += yt zf += zft npt.assert_almost_equal(zf, zfola[:, 0]) npt.assert_almost_equal(y, yola[:, 0])
def test_many_to_many(self): m = 123 n = 1024 L, M = (10, 5) x = np.random.normal(size=(n, )) h = np.random.normal(size=(m, L, M)) ziall = np.random.normal(size=(m - 1, L, M)) zi = ziall.sum(axis=-1) yola, zfola = olafilt(h, x, "nlm,n->nl", zi=zi) y = np.zeros((n, L)) zf = np.zeros((m - 1, L)) for l in range(L): for m in range(M): yt, zft = lfilter(h[:, l, m], 1, x, zi=ziall[:, l, m]) y[:, l] += yt zf[:, l] += zft npt.assert_almost_equal(y, yola) npt.assert_almost_equal(zf, zfola)
def test_shape(L, M, K): m = 123 n = 1024 h = np.random.normal(size=(m, L, M)) x = np.random.normal(size=(n, K)) ziall = np.random.normal(size=(m - 1, L, M, K)) zi = ziall.sum(axis=(-1, -2)) yola, zfola = olafilt(h, x, "nlm,nk->nl", zi=zi) for l in range(L): y = 0 zf = 0 for m in range(M): for k in range(K): yt, zft = lfilter(h[:, l, m], 1, x[:, k], zi=ziall[:, l, m, k]) y += yt zf += zft npt.assert_almost_equal(y, yola[:, l], err_msg=f"{L, M, K}") npt.assert_almost_equal(zf, zfola[:, l], err_msg=f"{L, M, K}")
signal = np.random.normal(0, 1, size=n_buffers * blocklength) # the adaptive filter filt = FastBlockLMSFilter(length, blocklength, stepsize=0.1, leakage=0.9999) # secondary path estimate has to account for block size plant_model = FIRFilter(np.concatenate((np.zeros(blocklength), h_sec))) # simulates an audio interface with primary and secondary paths and 40 dB SNR noise # at the error sensor sim = FakeInterface( blocklength, signal, h_pri=h_pri, h_sec=h_sec, noise=wgn(olafilt(h_pri, signal), 40, "dB"), ) elog = [] y = np.zeros(blocklength) # control signal is zero for first block for i in range(n_buffers): # record reference signal x and error signal e while playing back y x, e, _, _ = sim.playrec(-y) # filter the reference signal fx = plant_model(x) # adapt filter filt.adapt(fx, e) # filter y = filt.filt(x) # log error elog.append(e)