def test_identity_single(): """Test that x = inv_dwt(dwt(x)) for a single level DWT""" for filter_name in ["db3", "db4"]: for nx in [20, 21, 22, 23]: x = np.linspace(1, nx, nx) # np.random.randn(nx) Ux = 0.1 * (1 + np.random.random(nx)) ld, hd, lr, hr = filter_design(filter_name) # single decomposition y_approx, U_approx, y_detail, U_detail, _ = dwt(x, Ux, ld, hd) # single reconstruction xr, Uxr, _ = inv_dwt(y_approx, U_approx, y_detail, U_detail, lr, hr) if x.size % 2 == 0: assert x.size == xr.size assert Ux.size == Uxr.size assert_allclose(x, xr) else: assert x.size + 1 == xr.size assert Ux.size + 1 == Uxr.size assert_allclose(x, xr[:-1])
def test_dwt(): """Compare :func:`dwt` to the implementation of :mod:`PyWavelets`""" for filter_name in ["db3", "db4"]: for nx in [20, 21, 22, 23]: x = np.random.randn(nx) Ux = 0.1 * (1 + np.random.random(nx)) ld, hd, _, _ = filter_design(filter_name) # execute single level DWT y1, Uy1, y2, Uy2, _ = dwt(x, Ux, ld, hd) # all output has same length assert y1.size == y2.size assert y1.size == Uy1.size assert Uy1.size == Uy2.size # output is half the length of (input + filter - 1) assert (x.size + ld.size - 1) // 2 == y1.size # compare to pywt ca, cd = pywt.dwt(x, filter_name, mode="constant") assert ca.size == y1.size assert cd.size == y2.size assert_allclose(ca, y1, atol=1e-15) assert_allclose(cd, y2, atol=1e-15)
def test_inv_dwt(): """Compare :func:`inv_dwt` to the implementation of :mod:`PyWavelets`""" for filter_name in ["db3", "db4"]: for nc in [20, 21, 22, 23]: c_approx = np.random.randn(nc) Uc_approx = 0.1 * (1 + np.random.random(nc)) c_detail = np.random.randn(nc) Uc_detail = 0.1 * (1 + np.random.random(nc)) _, _, lr, hr = filter_design(filter_name) # execute single level DWT x, Ux, _ = inv_dwt(c_approx, Uc_approx, c_detail, Uc_detail, lr, hr) # all output has same length assert x.size == Ux.size # output double the size of input minus filter assert 2 * c_approx.size - lr.size + 2 == x.size # compare to pywt r = pywt.idwt(c_approx, c_detail, filter_name, mode="constant") assert_allclose(x, r)
def test_wave_rec(): """Compare :func:`wave_rec` to the implementation of :mod:`PyWavelets`""" for filter_name in ["db2", "db3"]: for nx in [20, 21]: # generate required coeffs-structure coeff_lengths = [ len(c) for c in pywt.wavedec( np.zeros(nx), filter_name, mode="constant") ] coeffs = [] Ucoeffs = [] for i in coeff_lengths: coeffs.append(np.random.random(i)) Ucoeffs.append(np.random.random(i)) # define a filter _, _, lr, hr = filter_design(filter_name) x, _ = wave_rec(coeffs, Ucoeffs, lr, hr) # compare to the output of PyWavelet result_pywt = pywt.waverec(coeffs, filter_name, mode="constant") # compare output of both methods assert len(result_pywt) == len(x) assert_allclose(result_pywt, x)
def test_filter_design(): """Check if connection to PyWavelets works as expected.""" for filter_name in ["db3", "db4", "rbio3.3"]: ld, hd, lr, hr = filter_design(filter_name) assert isinstance(ld, np.ndarray) assert isinstance(hd, np.ndarray) assert isinstance(lr, np.ndarray) assert isinstance(hr, np.ndarray)
def test_decomposition_realtime(): """Check if repetitive calls to :func:`wave_dec_realtime` yield the same result as a single call to the same function. (Because of different treatment of initial conditions, this can't be directly compared to :func:`wave_dec`.) """ for filter_name in ["db2", "db3"]: for nx in [20, 21]: x = np.random.randn(nx) Ux = 0.1 * (1 + np.random.random(nx)) ld, hd, _, _ = filter_design(filter_name) # run x all at once coeffs_a, Ucoeffs_a, _, _ = wave_dec_realtime(x, Ux, ld, hd, n=2) # slice x into smaller chunks and process them in batches # this tests the internal state options coeffs_list = [] Ucoeffs_list = [] z_b = None n_splits = 3 for x_batch, Ux_batch in zip(np.array_split(x, n_splits), np.array_split(Ux, n_splits)): coeffs_b, Ucoeffs_b, _, z_b = wave_dec_realtime( x_batch, Ux_batch, ld, hd, n=2, level_states=z_b) coeffs_list.append(coeffs_b) Ucoeffs_list.append(Ucoeffs_b) coeffs_b = [ np.concatenate([coeffs[level] for coeffs in coeffs_list], axis=0) for level in range(len(coeffs_list[0])) ] Ucoeffs_b = [ np.concatenate([Ucoeffs[level] for Ucoeffs in Ucoeffs_list], axis=0) for level in range(len(Ucoeffs_list[0])) ] # compare output depth assert len(coeffs_a) == len(coeffs_b) assert len(Ucoeffs_a) == len(Ucoeffs_b) # compare output in detail for a, b in zip(coeffs_a, coeffs_b): assert len(a) == len(b) assert_allclose(a, b) # compare output uncertainty in detail for a, b in zip(Ucoeffs_a, Ucoeffs_b): assert len(a) == len(b) assert_allclose(a, b)
def test_identity_multi(): """Test that x = inv_dwt(dwt(x)) for a multi level DWT""" for filter_name in ["db3", "db4"]: for nx in [20, 21, 203]: x = np.linspace(1, nx, nx) Ux = np.ones(nx) Ux[nx // 2:] = 2 Ux = 0.1 * Ux ld, hd, lr, hr = filter_design(filter_name) # full decomposition coeffs, Ucoeffs, ol = wave_dec(x, Ux, ld, hd) # full reconstruction xr, Uxr = wave_rec(coeffs, Ucoeffs, lr, hr, original_length=ol) assert x.size == xr.size assert_allclose(x, xr) assert Ux.size == Uxr.size
def test_wave_dec(): """Compare :func:`wave_dec` to the implementation of :mod:`PyWavelets`""" for filter_name in ["db2", "db3"]: for nx in [20, 21]: x = np.random.randn(nx) Ux = 0.1 * (1 + np.random.random(nx)) ld, hd, _, _ = filter_design(filter_name) coeffs, _, _ = wave_dec(x, Ux, ld, hd) # compare to the output of PyWavelet result_pywt = pywt.wavedec(x, filter_name, mode="constant") # compare output depth assert len(result_pywt) == len(coeffs) # compare output in detail for a, b in zip(result_pywt, coeffs): assert len(a) == len(b) assert_allclose(a, b, atol=1e-15)
from PyDynamic.uncertainty.propagate_DWT import dwt, filter_design, inv_dwt # monte carlo validation n_mc = 1000 # monte carlo runs for filter_name in ["db9"]: for nx in [101]: # define input signal and uncertainty of input signal x = np.clip(np.linspace(1, nx, nx), -10, 30) Ux = np.ones(nx) Ux[nx // 2:] = 2 Ux = 1.0 * Ux ld, hd, lr, hr = filter_design(filter_name) # single decomposition with uncertainty c_approx, U_approx, c_detail, U_detail, _ = dwt(x, Ux, ld, hd) # single reconstruction with uncertainty xr, Uxr, _ = inv_dwt(c_approx, U_approx, c_detail, U_detail, lr, hr) # actual monte carlo # MC: decomposition tmp_c = [] for i in range(n_mc): x_mc = x + np.random.randn(nx) * Ux c_approx_mc, c_detail_mc = pywt.dwt(x_mc, filter_name,
def main(): # basics buffer_length = 120 signal = Buffer(maxlen=buffer_length, return_type="arrays") cycle_duration = 0.1 # seconds plot_counter = 0 dwt_counter = 0 cycle_counter = 0 # init wavelet stuff ld, hd, _, _ = wavelet.filter_design("db2") dwt_length = 21 # init multi level wavelet stuff n_levels = 4 output_multi_level = [n_levels] + [ level for level in list(range(1, n_levels + 1))[::-1] ] # highest level twice because we store detail + approx output_multi_buffer_maxlen = [ buffer_length // 2 ** level for level in output_multi_level ] output_multi = [ Buffer(maxlen=maxlen, return_type="arrays") for maxlen in output_multi_buffer_maxlen ] # list of buffer (different lengths to approximately cover the same timespan) level_states = None # init plot plt.ion() fig = plt.figure() ax = fig.subplots(nrows=1 + len(output_multi), ncols=1, sharex=True) # init signal plot ax[0].set_ylabel("$x^{(0)}$") ax[0].set_ylim([-2, 2]) (sm,) = ax[0].plot(0, 0, "-k") # signal (su,) = ax[0].plot(0, 0, ":k", linewidth=0.8) # upper unc (sl,) = ax[0].plot(0, 0, ":k", linewidth=0.8) # lower unc # init coefficient plots c_lines = [] for i, (level, _ax) in enumerate(zip(output_multi_level[::-1], ax[1:])): if i == len(ax[1:]) - 1: _ax.set_ylabel("$a^{{({0})}}$".format(level)) else: _ax.set_ylabel("$d^{{({0})}}$".format(level)) _ax.set_ylim(auto=True) ce = _ax.errorbar( 0, 0, yerr=0, linewidth=0, elinewidth=2, color="gray", capsize=5 ) cm = _ax.scatter([0], [0], c="r", s=10) # (detail) coeffs c_lines.append([cm, ce]) _ax.set_ylim([-3, 3]) # simulate infinite stream of data while True: cycle_counter += 1 # ti = tm.time() ti = cycle_counter * cycle_duration ui = 0.15 * (np.sin(2 * ti) + 2) xi = np.sin(ti) + np.random.randn() * ui signal.add(time=ti, val=xi, val_unc=ui) # run DWT every <dwt_length> iterations dwt_counter += 1 if dwt_counter % dwt_length == 0: t, _, v, u = signal.show(dwt_length) # multi level dwt with uncertainty coeffs, Ucoeffs, _, level_states = wavelet.wave_dec_realtime( v, u, ld, hd, n=n_levels, level_states=level_states ) # assign correct timestamps to the coefficients i0_old = (level_states["counter"] - len(t)) % 2 ** n_levels time_indices = np.arange(i0_old, i0_old + len(t)) # save results to data structure for c, u, buffer, level in zip( coeffs, Ucoeffs, output_multi, output_multi_level ): time_indices_level = (time_indices + 1) % 2 ** level == 0 if ( time_indices_level.sum() > 0 ): # otherwise error from time-series-buffer buffer.add(time=t[time_indices_level], val=c, val_unc=u) dwt_counter = 0 # set dwt length until next cycle dwt_length = random.choice( [1, 2, 10, 21] ) # could also be constant, e.g. dwt_length = 20 print(dwt_length) # update plot every 5 iterations plot_counter += 1 if ( plot_counter % 5 == 0 and cycle_counter > buffer_length ): # skip plotting at startup, when buffer is still not fully filled # update plot # get data to plot t_signal, _, v_signal, u_signal = signal.show(-1) # update signal lines sm.set_xdata(t_signal) su.set_xdata(t_signal) sl.set_xdata(t_signal) sm.set_ydata(v_signal) su.set_ydata(v_signal + u_signal) sl.set_ydata(v_signal - u_signal) ax[0].set_xlim([min(t_signal), max(t_signal)]) # update dwt lines for buffer, _ax, c_line in zip(output_multi[::-1], ax[1:], c_lines): if len(buffer) > 0: # otherwise error from time-series-buffer t_coeff, _, v_coeff, u_coeff = buffer.show(-1) # change the scatter data = np.c_[t_coeff, v_coeff] c_line[0].set_offsets(data) c_line[0].set_facecolor(["r"] * len(t_coeff)) # change the error bars c_line[1].remove() c_line[1] = _ax.errorbar( t_coeff, v_coeff, yerr=u_coeff, linewidth=0, elinewidth=1.5, color="gray", capsize=3, zorder=0, ) upper_unc = v_coeff + u_coeff lower_unc = v_coeff - u_coeff if v_coeff.size != 0: lim = [np.min(lower_unc), np.max(upper_unc)] _ax.set_ylim(lim) # finally update the plot itself fig.tight_layout() fig.align_ylabels(ax) fig.canvas.draw() fig.canvas.flush_events() # reset plot counter plot_counter = 0