Spline with constraints at border

后端 未结 3 1892
执笔经年
执笔经年 2020-12-31 02:58

I have measured data on a three dimensional grid, e.g. f(x, y, t). I want to interpolate and smooth this data in the direction of t with splines. C

3条回答
  •  一生所求
    2020-12-31 03:34

    The best thing I can think of is to do a minimization with a constraint with scipy.optimize.minimize. It is pretty easy to take the derivative of a spline, so the constraint is simply. I would use a regular spline fit (UnivariateSpline) to get the knots (t), and hold the knots fixed (and degree k, of course), and vary the coefficients c. Maybe there is a way to vary the knot locations as well but I will leave that to you.

    import numpy as np
    from scipy.interpolate import UnivariateSpline, splev, splrep
    from scipy.optimize import minimize
    
    def guess(x, y, k, s, w=None):
        """Do an ordinary spline fit to provide knots"""
        return splrep(x, y, w, k=k, s=s)
    
    def err(c, x, y, t, k, w=None):
        """The error function to minimize"""
        diff = y - splev(x, (t, c, k))
        if w is None:
            diff = np.einsum('...i,...i', diff, diff)
        else:
            diff = np.dot(diff*diff, w)
        return np.abs(diff)
    
    def spline_neumann(x, y, k=3, s=0, w=None):
        t, c0, k = guess(x, y, k, s, w=w)
        x0 = x[0] # point at which zero slope is required
        con = {'type': 'eq',
               'fun': lambda c: splev(x0, (t, c, k), der=1),
               #'jac': lambda c: splev(x0, (t, c, k), der=2) # doesn't help, dunno why
               }
        opt = minimize(err, c0, (x, y, t, k, w), constraints=con)
        copt = opt.x
        return UnivariateSpline._from_tck((t, copt, k))
    

    And then we generate some fake data that should have zero initial slope and test it:

    import matplotlib.pyplot as plt
    
    n = 10
    x = np.linspace(0, 2*np.pi, n)
    y0 = np.cos(x) # zero initial slope
    std = 0.5
    noise = np.random.normal(0, std, len(x))
    y = y0 + noise
    k = 3
    
    sp0 = UnivariateSpline(x, y, k=k, s=n*std)
    sp = spline_neumann(x, y, k, s=n*std)
    
    plt.figure()
    X = np.linspace(x.min(), x.max(), len(x)*10)
    plt.plot(X, sp0(X), '-r', lw=1, label='guess')
    plt.plot(X, sp(X), '-r', lw=2, label='spline')
    plt.plot(X, sp.derivative()(X), '-g', label='slope')
    plt.plot(x, y, 'ok', label='data')
    plt.legend(loc='best')
    plt.show()
    

提交回复
热议问题