def integral(J, k, l, wavelet_coef, phi): r''' This function calculates the integral (16) numerically. INPUT: J : int The scale. k : int The translation for the first function. l : int The translation for the second function. wavelet_coef : numpy.float64 The wavelet coefficients, must sum to :math:`\sqrt{2}`. For Daubechies 2 they can be found using `np.flipud(pywt.Wavelet('db2').dec_lo)`. phi : numpy.float64 The phi function, can be made with `pywt.Wavelet(wavelet).wavefun(level=15)`. OUTPUT: out : int The value of the integral. ''' a = int(len(wavelet_coef) / 2) OneStep = len(phi) // (2 * a - 1) phiNorm = np.linalg.norm(BW.downsample(phi, 0, OneStep, J)) phi1 = BW.downsample(phi, k, OneStep, J) / phiNorm phi2 = BW.downsample(phi, l, OneStep, J) / phiNorm phiProd = phi1 * phi2 Integ = simps(phiProd) return Integ
def decom_boundary(signal, J, wavelet, phi): ''' This function makes a wavelet decomposition of a 1D signal in time, using boundary wavelets at the edge. INPUT: signal : numpy.float64 The signal to be decomposed. J : int The scale of the wavelet. wavelet : str The name of the wavelet to use. For instance `'db2'`. phi : numpy.float64 The scaling function at scale 0. (1d array) OUTPUT: x : numpy.float64 The decomposition. ''' h = np.flipud(pywt.Wavelet(wavelet).dec_lo) a = int(len(h) / 2) N = int(np.log2(len(phi) / (len(h) - 1))) AL, AR = Ot.ortho_matrix(J, h, phi) Boundary = BW.boundary_wavelets(phi, J, h, AL=AL, AR=AR) x = np.zeros(2**J) for i in range(a): x[i] = np.inner(Boundary[:, i], signal) for i in range(1, 2**J - 2 * a + 1): x[i - 1 + a] = np.inner( BW.downsample(phi, i, 2**N, J, zero=True) * np.sqrt(2**J), signal) for i in range(a): x[-1 - i] = np.inner(Boundary[:, -1 - i], signal) x /= len(signal) return x
def recon_mirror(wavelet_coef, J, wavelet, phi): ''' This function reconstructs a 1D signal in time from its wavelet coefficients, using mirroring of the signal at the edge. INPUT: wavelet_coef : numpy.float64 The wavelet decomposition. Can be made using decom_mirror(). J : int The scale of the wavelet. wavelet : str The name of the wavelet to use. For instance `'db2'`. phi : numpy.float64 The scaling function at scale 0. (1d array) OUTPUT: x : numpy.float64 The reconstructed signal, the length of the signal is `2**(N-J)*len(wavelet_coef)`. ''' h = np.flipud(pywt.Wavelet(wavelet).dec_lo) N = int(np.log2(len(phi) / (len(h) - 1))) phi = BW.downsample(phi, 0, 2**N, J, zero=False) OneStep = 2**(N - J) a = int(len(phi) / OneStep) - 1 x = np.zeros(OneStep * len(wavelet_coef) + (a) * OneStep, dtype=complex) for i in range(len(wavelet_coef)): x[i * OneStep:i * OneStep + len(phi)] += wavelet_coef[i] * phi * 2**(-(J) / 2) x = x[OneStep * (a):-OneStep * (a)] return x
def decom_mirror(signal, J, wavelet, phi): ''' This function makes a wavelet decomposition of a 1D signal in time, using mirroring of the signal at the edge. INPUT: signal : numpy.float64 The signal to be decomposed. J : int The scale of the wavelet. wavelet : str The name of the wavelet to use. For instance `'db2'`. phi : numpy.float64 The scaling function at scale 0. (1d array) OUTPUT: x : numpy.float64 The decomposition. ''' h = np.flipud(pywt.Wavelet(wavelet).dec_lo) N = int(np.log2(len(phi) / (len(h) - 1))) OneStep = 2**(N - J) a = int(len(h) / 2) x = np.zeros(2**J + (2 * a - 2)) for i in range(2 * a - 2): phi1 = BW.downsample(phi, 0, 2**N, J, zero=False) * np.sqrt(2**J) signal1 = np.concatenate( (np.flipud(signal[:OneStep * (i + 1)]), signal)) signal1 = signal1[:len(phi1)] x[i] = np.inner(phi1, signal1) for i in range(2**J - 2 * a + 2): x[i + 2 * a - 2] = np.inner( BW.downsample(phi, i, 2**N, J, zero=True) * np.sqrt(2**J), signal) for i in range(2 * a - 2): phi1 = BW.downsample(phi, 0, 2**N, J, zero=False) * np.sqrt(2**J) signal1 = np.concatenate( (signal, np.flipud(signal[-OneStep * (i + 1):]))) signal1 = signal1[-len(phi1):] x[2**J + i] = np.inner(phi1, signal1) x /= len(signal) return x
def recon_boundary(wavelet_coef, J, wavelet, phi): ''' This function reconstructs a 1D signal in time from its wavelet coefficients, using boundary wavelets at the edge. INPUT: wavelet_coef : numpy.float64 The wavelet decomposition. Can be made using decom_boundary(). J : int The scale of the wavelet. avelet : str The name of the wavelet to use. For instance `'db2'`. phi : numpy.float64 The scaling function at scale 0. (1d array) OUTPUT: x : numpy.float64 The reconstructed signal, the length of the signal is `2**(N-J)*len(wavelet_coef)`. ''' h = np.flipud(pywt.Wavelet(wavelet).dec_lo) AL, AR = Ot.ortho_matrix(J, h, phi) Q = BW.boundary_wavelets(phi, J, h, AL=AL, AR=AR) N = int(np.log2(len(phi) / (len(h) - 1))) phi = BW.downsample(phi, 0, 2**N, J, zero=False) OneStep = 2**(N - J) m = np.shape(Q)[0] a = np.shape(Q)[1] // 2 Boundary = np.transpose(Q) x = np.zeros(OneStep * len(wavelet_coef), dtype=complex) for i in range(a): x[:m] += wavelet_coef[i] * Boundary[i] k = 1 for i in range(a, len(wavelet_coef) - a): x[k * OneStep:k * OneStep + len(phi)] += wavelet_coef[i] * phi * 2**(-(J) / 2) k += 1 for i in range(a): x[-m:] += wavelet_coef[-i - 1] * Boundary[-i - 1] return x
def general_test(wavelet='db2', J=2, epsilon=1 / 7, length=1792, time_only=False): ''' A test function used in the paper. Plots the boundary wavelets in time and compare them with the boundary wavelets created in frequency by using an inverse Fourier transform. INPUT: wavelet='db2' : str The wavelet to use in the test. J=2 : int The scale. If `J` is too small for the scaling function to be supported within the interval [0,1] it is changed to the smallest possible `J`. epsilon=1/7 : float The sampling dencity in the frequency domain, i.e. the distance between samples. In Generalized sampling this must be at least 1/7 for db2. length=1792 : int The number of samples in the frequency domain. The standard is chosen because :math:`1792/7=256`. time_only=False : bool If `time_only=True` the boundary functions are only constructed in time, not in frequency. ''' WaveCoef = np.flipud(pywt.Wavelet(wavelet).dec_lo) phi = pywt.Wavelet(wavelet).wavefun(level=15)[0][1:] a = int(len(WaveCoef) / 2) OneStep = len(phi) // (2 * a - 1) if J < a: J = a print('J has been changed to', J) AL, AR = ot.ortho_matrix(J, WaveCoef, phi) phiNorm = np.sqrt(1 / OneStep * np.sum(np.abs(bw.downsample(phi, 0, OneStep, J)**2))) BoundaryT = bw.boundary_wavelets(phi / phiNorm, J, WaveCoef, AL=AL, AR=AR) NormT = np.zeros(2 * a) for i in range(2 * a): NormT[i] = np.sqrt(1 / OneStep * np.sum(np.abs(BoundaryT[:, i])**2)) IP = 0 for i in range(a): IP += i LeftInnerProdT = np.zeros(IP) ij = 0 for i in range(a): for j in range(i + 1, a): LeftInnerProdT[ij] = 1 / OneStep * np.sum( BoundaryT[:, i] * BoundaryT[:, j]) ij += 1 RightInnerProdT = np.zeros(IP) ij = 0 for i in range(a): for j in range(i + 1, a): RightInnerProdT[ij] = 1 / OneStep * np.sum( BoundaryT[:, i + a] * BoundaryT[:, j + a]) ij += 1 if time_only: print('Norms of functions in time', NormT) print('Inner products in time', LeftInnerProdT, RightInnerProdT) plt.figure() for i in range(a): plt.plot(np.linspace(0, 1, len(BoundaryT[:, i])), BoundaryT[:, i], label=r'$\phi^L_{' + f'{J},{i}' + r'}$') for i in range(a): plt.plot(np.linspace(0, 1, len(BoundaryT[:, i + a])), BoundaryT[:, i + a], label=r'$\phi^R_{' + f'{J},{i}' + r'}$') plt.legend() plt.xlabel('Time') plt.ylabel('Amplitude') else: s = int(length * epsilon) d = 1 / epsilon scheme = np.linspace(-length * epsilon / 2, length * epsilon / 2, length, endpoint=False) BoundaryF = fbw.fourier_boundary_wavelets(J, scheme, WaveCoef, AL=AL, AR=AR) NormF = np.zeros(2 * a) for i in range(2 * a): NormF[i] = np.sqrt(epsilon * np.sum(np.abs(BoundaryF[:, i])**2)) LeftInnerProdF = np.zeros(IP, dtype=complex) ij = 0 for i in range(a): for j in range(i + 1, a): LeftInnerProdF[ij] = epsilon * np.sum( BoundaryF[:, i] * BoundaryF[:, j]) ij += 1 RightInnerProdF = np.zeros(IP, dtype=complex) ij = 0 for i in range(a): for j in range(i + 1, a): RightInnerProdF[ij] = epsilon * np.sum( BoundaryF[:, i + a] * BoundaryF[:, j + a]) ij += 1 print('Norms of functions in time', NormT) print('Norms of functions i frequency', NormF) print('Inner products in time', LeftInnerProdT, RightInnerProdT) print('Inner products in frequency', LeftInnerProdF, RightInnerProdF) InverseBoundaryF = np.zeros((s, 2 * a), dtype=complex) for i in range(2 * a): InverseBoundaryF[:, i] = d**(1 / 2) * np.fft.ifft( d**(-1 / 2) * np.concatenate( (BoundaryF[len(BoundaryF[:, i]) // 2:, i], BoundaryF[:len(BoundaryF[:, i]) // 2, i])), norm='ortho')[:s] Fnorm = np.sqrt(1 / 256 * np.sum(np.abs(InverseBoundaryF[:, i])**2)) InverseBoundaryF[:, i] /= Fnorm plt.figure() plt.plot(np.linspace(0, 1, len(BoundaryT[:, 0])), BoundaryT[:, 0], label='Scaling functions in time', color='C0') plt.plot(np.linspace(0, 1, s), np.real(InverseBoundaryF[:, 0]), label='Scaling functions in frequency', color='C1') for i in range(1, a): plt.plot(np.linspace(0, 1, len(BoundaryT[:, 0])), BoundaryT[:, i], color='C0') plt.plot(np.linspace(0, 1, s), np.real(InverseBoundaryF[:, i]), color='C1') for i in range(a): plt.plot(np.linspace(0, 1, len(BoundaryT[:, 0])), BoundaryT[:, i + a], color='C0') plt.plot(np.linspace(0, 1, s), np.real(InverseBoundaryF[:, i + a]), color='C1') plt.legend() plt.xlabel('Time') plt.ylabel('Amplitude') return