예제 #1
0
def test_background():
    #=======================================================================
    "Check that dipolar kernel builds with the background included"
    t = np.linspace(0, 3, 80)
    r = np.linspace(2, 6, 100)
    B = bg_exp(t, 0.5)

    lam = 0.25
    KBref = (1 - lam +
             lam * dipolarkernel(t, r, integralop=False)) * B[:, np.newaxis]
    KB = dipolarkernel(t, r, mod=lam, bg=B, integralop=False)

    assert np.all(abs(KB - KBref) < 1e-5)
예제 #2
0
def test_regularized_global():
    #=======================================================================
    "Check global SNLLS of a nonlinear-constrained + linear-regularized problem"

    t1 = np.linspace(0, 3, 150)
    t2 = np.linspace(0, 4, 200)
    r = np.linspace(2.5, 5, 80)
    P = dd_gauss2(r, 3.7, 0.5, 0.5, 4.3, 0.3, 0.5)
    kappa = 0.50
    lam1 = 0.25
    lam2 = 0.35
    K1 = dipolarkernel(t1, r, mod=lam1, bg=bg_exp(t1, kappa))
    K2 = dipolarkernel(t2, r, mod=lam2, bg=bg_exp(t2, kappa))
    V1 = K1 @ P
    V2 = K2 @ P

    # Global non-linear model
    def globalKmodel(par):
        # Unpack parameters
        kappa, lam1, lam2 = par
        K1 = dipolarkernel(t1, r, mod=lam1, bg=bg_exp(t1, kappa))
        K2 = dipolarkernel(t2, r, mod=lam2, bg=bg_exp(t2, kappa))
        return K1, K2

    # Non-linear parameters
    # [kappa lambda1 lambda2]
    par0 = [0.5, 0.5, 0.5]
    lb = [0, 0, 0]
    ub = [1, 1, 1]
    # Linear parameters: non-negativity
    lbl = np.zeros(len(r))
    ubl = []

    # Separable LSQ fit
    fit = snlls([V1, V2], globalKmodel, par0, lb, ub, lbl, ubl, uq=False)
    Pfit = fit.lin

    assert ovl(P, Pfit) > 0.9
예제 #3
0
def test_filtered_savgol():
    #============================================================
    "Check estimation of noiselevel using a Savitzky-Golay filter"

    np.random.seed(1)
    t = np.linspace(0, 3, 200)
    r = np.linspace(2, 6, 100)
    P = dd_gauss(r, 3, 0.5)
    lam = 0.25
    B = bg_exp(t, 1.5)
    noise = whitegaussnoise(t, 0.03)
    V = dipolarkernel(t, r, mod=lam, bg=B) @ P + noise

    truelevel = np.std(noise)
    approxlevel = noiselevel(V, 'savgol', 11, 3)

    assert abs(approxlevel - truelevel) < 1e-2
예제 #4
0
def test_der():
    #============================================================
    "Check estimation of noiselevel using a moving-mean filter"

    np.random.seed(1)
    t = np.linspace(0, 3, 200)
    r = np.linspace(2, 6, 100)
    P = dd_gauss(r, 3, 0.5)
    lam = 0.25
    B = bg_exp(t, 1.5)
    noise = whitegaussnoise(t, 0.05)
    V = dipolarkernel(t, r, mod=lam, bg=B) @ P + noise

    truelevel = np.std(noise)
    approxlevel = noiselevel(V, 'der')

    assert abs(approxlevel - truelevel) < 1e-2
예제 #5
0
def test_reference():
    #============================================================
    "Check estimation of noiselevel using a reference signal"

    np.random.seed(1)
    t = np.linspace(0, 3, 200)
    r = np.linspace(2, 6, 100)
    P = dd_gauss(r, 3, 0.5)
    lam = 0.25
    B = bg_exp(t, 1.5)
    Vref = dipolarkernel(t, r, mod=lam, bg=B) @ P
    noise = whitegaussnoise(t, 0.03)
    V = Vref + noise

    truelevel = np.std(noise)
    approxlevel = noiselevel(V, 'reference', Vref)

    assert abs(approxlevel - truelevel) < 1e-2
예제 #6
0
def test_phenomenological():
    #==================================================================================
    "Check that phenomenological background models are propely used"

    t = np.linspace(0, 5, 150)
    kappa = 0.3
    lam = 0.5

    #Reference
    Bref = bg_exp(t, 0.3)

    #Output
    Bmodel = lambda t: bg_hom3d(t, kappa, 1)
    path = [[], []]
    path[0] = [1 - lam]
    path[1] = [lam, 0]
    B = dipolarbackground(t, path, Bmodel)

    assert max(abs(B - Bref) < 1e-8)
예제 #7
0
def test_complex():
    #============================================================
    "Check estimation of noiselevel using a complex signal"

    t = np.linspace(0, 3, 200)
    r = np.linspace(2, 6, 100)
    P = dd_gauss(r, 4, 0.4)
    lam = 0.25
    B = bg_exp(t, 1.5)

    np.random.seed(1)
    noise = whitegaussnoise(t, 0.03)
    np.random.seed(2)
    noisec = 1j * whitegaussnoise(t, 0.03)
    V = dipolarkernel(t, r, mod=lam, bg=B) @ P
    Vco = V * np.exp(-1j * np.pi / 5)
    Vco = Vco + noise + noisec
    truelevel = np.std(noise)
    approxlevel = noiselevel(Vco, 'complex')

    assert abs(truelevel - approxlevel) < 1e-2
예제 #8
0
def correctscale(V, t, tmax=[], model='deer'):
    r""" 
Amplitude scale correction

Takes the experimental dipolar signal (V) on a given time axis (t) and
rescales it so that it is 1 at time zero, taking into account the noise.
It fits a model specified in (model) over the interval ``abs(t)<tmax`` around time zero.
It returns the rescaled signal (Vc) and the scaling factor (V0).

Parameters
----------
V : array_like
    Experimenal signal.
    
t : array_like 
    Time axis, in microseconds. 

tmax : scalar, optional
    Time cutoff for fit range, in microseconds.

model : string, optional
    Model to fit over ``abs(t)<tmax``
    * ``'deer'`` - DEER model with Gaussian distribution.
    * ``'gauss'`` - Raised Gaussian.
    
    The default is ``'deer'``

Returns
-------
Vc : ndarray
    Rescaled signal.
    """
    if not all(np.isreal(V)):
        raise ValueError('Input signal cannot be complex.')

    if isempty(tmax):
        tmax = max(t)
    # Approximate scaling
    Amp0 = max(V)
    V_ = V / Amp0

    # Limit fit to region around time zero
    idx = abs(t) <= tmax
    V_ = V_[idx]
    t_ = t[idx]

    if model == 'deer':
        # DEER model with Gaussian distribution
        if len(V_) < 5:
            raise KeyError(
                'Number of points in fit range cannot be smaller than number of model parameters. Increase tmax.'
            )
        r = np.linspace(0.5, 20, 300)
        fitmodel = lambda p: p[0] * (dipolarkernel(
            t_, r, mod=p[1], bg=bg_exp(t_, p[4])) @ dd_gauss(r, *p[[2, 3]]))
        # parameters: amplitude, mod depth, Gauss position, Gauss std, conc
        par0 = [1, 0.5, 3, 0.3, 0.2]
        lb = [1e-3, 0.01, 0, 0.01, 0]
        ub = [10, 1, 20, 5, 100]
    elif model == 'gauss':
        # Gaussian function
        if len(V_) < 3:
            raise KeyError(
                'Number of points in fit range cannot be smaller than number of model parameters. Increase tmax.'
            )
        fitmodel = lambda p: (p[0] - p[1]) + p[1] * np.exp(-t_**2 / p[2]**2)
        par0 = [1, 1, 1]
        lb = [1e-3, 1e-3, 1e-3]
        ub = [10, 1000, 10000]
    else:
        raise KeyError(f"Unknown model '{model}'")

    # Run the parametric model fitting
    fit = snlls(V_, fitmodel, par0, lb, ub, uq=False, lin_frozen=[1])

    # Get the fitted signal amplitude and scale the signal
    V0 = Amp0 * fit.param[0]
    Vc = V / V0

    return Vc
예제 #9
0
 def globalKmodel(par):
     # Unpack parameters
     kappa, lam1, lam2 = par
     K1 = dipolarkernel(t1, r, mod=lam1, bg=bg_exp(t1, kappa))
     K2 = dipolarkernel(t2, r, mod=lam2, bg=bg_exp(t2, kappa))
     return K1, K2