def Integral(J, k, l, WaveletCoef, 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. WaveletCoef : 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(WaveletCoef) / 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 DecomBoundary(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.OrthoMatrix(J, h, phi) Boundary = BW.BoundaryWavelets(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 M_AlphaBeta(alpha, beta, J, WaveletCoef, InteMatrix, Side): r''' This function calculates an entry in the martix :math:`M` (15). INPUT: alpha : int alpha beta : int beta J : int The scale. WaveletCoef : 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`). InteMatrix : numpy.float64 A matrix with the values for the integrals calculated with the function :py:func:`Integral` for k and l in the interval [-2*a+2,0] or [2**J-2*a+1,2**J-1]. Side : str `'L'` for left interval boundary and `'R'` for right interval boundary. OUTPUT: M : numpy.float64 Entry (alpha,beta) of the martix M ''' a = int(len(WaveletCoef) / 2) Moment = BW.Moments(WaveletCoef, a - 1) M = 0 if Side == 'L': Interval = range(-2 * a + 2, 1) i = 0 for k in Interval: j = 0 for m in Interval: M += (BW.InnerProductPhiX(alpha, 0, k, Moment) * BW.InnerProductPhiX(beta, 0, m, Moment) * InteMatrix[i, j]) j += 1 i += 1 elif Side == 'R': Interval = range(2**J - 2 * a + 1, 2**J) i = 0 for k in Interval: j = 0 for m in Interval: M += (BW.InnerProductPhiX(alpha, 0, k, Moment) * BW.InnerProductPhiX(beta, 0, m, Moment) * InteMatrix[i, j] * 2**(-J * (alpha + beta))) j += 1 i += 1 else: print('You must choose a side') return M
def ReconMirror(WaveletCoef, J, Wavelet, phi): ''' This function reconstructs a 1D signal in time from its wavelet coefficients, using mirroring of the signal at the edge. INPUT: WaveletCoef : numpy.float64 The wavelet decomposition. Can be made using DecomMirror(). 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(WaveletCoef)`. ''' 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(WaveletCoef) + (a) * OneStep, dtype=complex) for i in range(len(WaveletCoef)): x[i * OneStep:i * OneStep + len(phi)] += WaveletCoef[i] * phi * 2**(-(J) / 2) x = x[OneStep * (a):-OneStep * (a)] return x
def DecomMirror(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 ReconBoundary(WaveletCoef, J, Wavelet, phi): ''' This function reconstructs a 1D signal in time from its wavelet coefficients, using boundary wavelets at the edge. INPUT: WaveletCoef : numpy.float64 The wavelet decomposition. Can be made using DecomBoundary(). 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(WaveletCoef)`. ''' h = np.flipud(pywt.Wavelet(Wavelet).dec_lo) AL, AR = Ot.OrthoMatrix(J, h, phi) Q = BW.BoundaryWavelets(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(WaveletCoef), dtype=complex) for i in range(a): x[:m] += WaveletCoef[i] * Boundary[i] k = 1 for i in range(a, len(WaveletCoef) - a): x[k * OneStep:k * OneStep + len(phi)] += WaveletCoef[i] * phi * 2**(-(J) / 2) k += 1 for i in range(a): x[-m:] += WaveletCoef[-i - 1] * Boundary[-i - 1] return x
def GeneralTest(Wavelet='db2', J=2, epsilon=1 / 7, Length=1792, TimeOnly=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`. TimeOnly=False : bool If `TimeOnly=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.OrthoMatrix(J, WaveCoef, phi) phiNorm = np.sqrt(1 / OneStep * np.sum(np.abs(BW.DownSample(phi, 0, OneStep, J)**2))) BoundaryT = BW.BoundaryWavelets(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 TimeOnly: 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.FourierBoundaryWavelets(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
def FourierBoundaryWavelets(J, Scheme, WaveletCoef, AL=None, AR=None, Win=Rectangle): r''' This function evaluates the Fourier transformed boundary functions for db2. INPUT: J : int The scale. Scheme : numpy.float64 The sampling scheme in the Fourier domain. WaveletCoef : numpy.float64 The wavelet coefficients, must sum to :math:`\sqrt{2}`. For Daubeshies 2 they can be found using `np.flipud(pywt.Wavelet('db2').dec_lo)`. AL=None : numpy.float64 The left orthonormalisation matrix, if this is not supplied the functions will not be orthonormalized. Can be computed using :py:func:`boundwave.Orthonormal.OrthoMatrix`. AR=None : numpy.float64 The right orthonormalisation matrix, if this is not supplied the functions will not be orthonormalized. Can be computed using :py:func:`boundwave.Orthonormal.OrthoMatrix`. Win= :py:func:`Rectangle` : numpy.complex128 The window to use on the boundary functions. OUTPUT: x : numpy.complex128 2d numpy array with the boundary functions in the columns; orthonormalised if `AL` and `AR` given. ''' a = int(len(WaveletCoef) / 2) kLeft = np.arange(-2 * a + 2, 1) kRight = np.arange(2**J - 2 * a + 1, 2**J) xj = np.zeros((len(Scheme), 2 * a), dtype=complex) Moment = BW.Moments(WaveletCoef, a - 1) FourierPhiLeft = np.zeros((len(kLeft), len(Scheme)), dtype=complex) FourierPhiRight = np.zeros((len(kRight), len(Scheme)), dtype=complex) Window = Win(Scheme) for i in range(len(kLeft)): FourierPhiLeft[i] = ScalingFunctionFourier(WaveletCoef, J, kLeft[i], Scheme, Window) FourierPhiRight[i] = ScalingFunctionFourier(WaveletCoef, J, kRight[i], Scheme, Window) for b in range(a): xj[:, b] = np.sum(np.multiply(BW.InnerProductPhiX(b, J, kLeft, Moment), np.transpose(FourierPhiLeft)), axis=1) xj[:, b + a] = np.sum(np.multiply( BW.InnerProductPhiX(b, J, kRight, Moment), np.transpose(FourierPhiRight)), axis=1) if type(AL) is None or type(AR) is None: return xj else: x = np.zeros(np.shape(xj), dtype=complex) for i in range(a): for j in range(a): x[:, i] += xj[:, j] * AL[i, j] for i in range(a): for j in range(a): x[:, i + a] += xj[:, j + a] * AR[i, j] return x