############################################################################### # We can also write a preconditioned problem, whose cost function is # # .. math:: # J= ||\mathbf{y} - \mathbf{R} \mathbf{P} \mathbf{p}||_2^2 # # where :math:`\mathbf{P}` is the precondioned operator, :math:`\mathbf{p}` is # the projected model in the preconditioned space, and # :math:`\mathbf{x}=\mathbf{P}\mathbf{p}` is the model in the original model # space we want to solve for. Note that a preconditioned problem converges # much faster to its solution than its corresponding regularized problem. # This can be done using the routine # :py:func:`pylops.optimization.leastsquares.PreconditionedInversion`. # Create regularization operator Sop = pylops.Smoothing1D(nsmooth=11, dims=[N], dtype='float64') # Invert for interpolated signal xprec = \ pylops.optimization.leastsquares.PreconditionedInversion(Rop, Sop, y, returninfo=False, **dict(damp=np.sqrt(1e-9), iter_lim=20, show=0)) ############################################################################### # Let's finally visualize these solutions # sphinx_gallery_thumbnail_number=4 fig = plt.figure(figsize=(12, 4)) plt.plot(t[iava], y, '.k', ms=20, label='available samples')
# Add noise yn = y + np.random.normal(0, 4e-1, y.shape) # Numerical derivative Dop = pylops.FirstDerivative(nt, sampling=dt) xder = Dop * yn # Regularized derivative Rop = pylops.SecondDerivative(nt) xreg = pylops.RegularizedInversion(Cop, [Rop], yn, epsRs=[1e0], **dict(iter_lim=100, atol=1e-5)) # Preconditioned derivative Sop = pylops.Smoothing1D(41, nt) xp = pylops.PreconditionedInversion(Cop, Sop, yn, **dict(iter_lim=10, atol=1e-3)) # Visualize data and inversion fig, axs = plt.subplots(1, 2, figsize=(18, 5)) axs[0].plot(t, y, 'k', LineWidth=3, label='data') axs[0].plot(t, yn, '--g', LineWidth=3, label='noisy data') axs[0].legend() axs[0].set_title('Causal integration') axs[1].plot(t, x, 'k', LineWidth=8, label='original') axs[1].plot(t[1:-1], xder[1:-1], 'r', LineWidth=3, label='numerical derivative')
import matplotlib.pyplot as plt import pylops plt.close('all') ############################################################################### # Define the input parameters: number of samples of input signal (``N``) and # lenght of the smoothing filter regression coefficients (:math:`n_{smooth}`). # In this first case the input signal is one at the center and zero elsewhere. N = 31 nsmooth = 7 x = np.zeros(N) x[int(N/2)] = 1 Sop = pylops.Smoothing1D(nsmooth=nsmooth, dims=[N], dtype='float32') y = Sop*x xadj = Sop.H*y fig, ax = plt.subplots(1, 1, figsize=(10, 3)) ax.plot(x, 'k', lw=2, label=r'$x$') ax.plot(y, 'r', lw=2, label=r'$y=Ax$') ax.set_title('Smoothing in 1st direction', fontsize=14, fontweight='bold') ax.legend() ############################################################################### # Let's repeat the same exercise with a random signal as input. After applying smoothing, # we will also try to invert it. N = 120 nsmooth = 13
axs[1].grid() axs[1].legend(loc='upper right') axs[1].axis('tight') ############################################################################### # Finally we repeat the same exercise, but this time we use a *preconditioner*. # Initially, our preconditioner is a :py:class:`pylops.Symmetrize` operator # to ensure that our estimated wavelet is zero-phase. After we chain # the :py:class:`pylops.Symmetrize` and the :py:class:`pylops.Smoothing1D` # operators to also guarantee a smooth wavelet. # Create symmetrize operator Sop = pylops.Symmetrize((ntwav + 1) // 2) # Create smoothing operator Smop = pylops.Smoothing1D(5, dims=((ntwav + 1) // 2, ), dtype='float64') # Invert for interpolated signal wavn_prec_est = \ pylops.optimization.leastsquares.PreconditionedInversion(Wavesop, Sop, dn.T.flatten(), returninfo=False, **dict(damp=np.sqrt(1e-4), iter_lim=200, show=0)) wavn_smooth_est = \ pylops.optimization.leastsquares.PreconditionedInversion(Wavesop, Sop*Smop, dn.T.flatten(), returninfo=False, **dict(damp=np.sqrt(1e-4),
def MovingAverage1D(window_size: int, shape: tuple, axis: int = 0, dtype='float64'): r""" 1D moving average. Apply moving average to a multi-dimensional array along a specific axis. Parameters ---------- window_size: int Size of the window for moving average (must be *odd*). shape: tuple Shape of the input array. axis: int Axis along which moving average is applied. dtype: str Type of elements in input array. Returns ------- :py:class:`pycsou.linop.base.PyLopLinearOperator` 1D moving average operator. Examples -------- .. plot:: import numpy as np import matplotlib.pyplot as plt from pycsou.linop.conv import MovingAverage1D from scipy import signal sig = np.zeros(shape=(100,100)) sig[sig.shape[0] // 2 - 2:sig.shape[0] // 2 + 3, sig.shape[1] // 2 - 2:sig.shape[1] // 2 + 3] = 1 MAOp = MovingAverage1D(window_size=25, shape=sig.shape, axis=0) moving_average = (MAOp * sig.ravel()).reshape(sig.shape) plt.figure() plt.subplot(1,2,1) plt.imshow(sig, cmap='plasma'); plt.title('Signal') plt.subplot(1,2,2) plt.imshow(moving_average, cmap='plasma'); plt.title('Moving Average') plt.show() Notes ----- The ``MovingAverage1D`` operator is a special type of convolution operator that convolves along a specific axis an array with a constant filter of size :math:`n_{smooth}`: .. math:: \mathbf{h} = [ 1/n_{smooth}, 1/n_{smooth}, ..., 1/n_{smooth} ] For example, for a 3D array :math:`x`, ``MovingAverage1D`` applied to the first axis yields: .. math:: y[i,j,k] = 1/n_{smooth} \sum_{l=-(n_{smooth}-1)/2}^{(n_{smooth}-1)/2} x[l,j,k]. Note that since the filter is symmetrical, the ``MovingAverage1D`` operator is self-adjoint. """ PyLop = pylops.Smoothing1D(nsmooth=window_size, dims=shape, dir=axis, dtype=dtype) return PyLopLinearOperator(PyLop)