コード例 #1
0
    def update_discretisation_scheme(self, signal, period):
        """
        Given an existing set of interior knots, re-optimize the knots
        to the new optimal value, for the given signal.

            signal : 2-by-n float array
                Signal to discretise. signal[0] is the independent
                (time-like) variable. signal[1] is the dependent
                (voltage / position / etc.)-like variable.

            period : float > 0
                Time taken for the signal to complete a single
                oscillation.

        Stores the result of an optimization procedure over the knot
        sets, to minimize fitting error, starting from the current
        knots.
        """
        def loss(interior_knots):
            # Training error under current knots
            spline = splines.PeriodicSpline(np.sort(interior_knots))
            coeffs = spline.fit(signal[0], signal[1], period)
            residuals = signal[1] - spline(signal[0], coeffs, period)
            return np.linalg.norm(residuals)**2

        bounds = scipy.optimize.Bounds(0, 1)
        opti = scipy.optimize.minimize(loss, self.mesh, bounds=bounds)
        self.mesh = np.sort(opti.x)
        self._spline = splines.PeriodicSpline(self.mesh)
        print("Proposed knots: \n", self.mesh)
        print(opti, "\n")
        return self.mesh
コード例 #2
0
    def _initialise_discretisation_scheme(self, signal, period, n_tries=10):
        """
        Given some periodic data, find the set of interior knots that
        provide a best-possible periodic splines model to the data (in
        the least-squares sense). This is done by starting with a
        randomly distributed set of knots, then attempting a numerical
        optimization on the knot set, to maximise goodness-of-fit. To
        avoid local minima, this procedure is repeated numerous times,
        with the best knots being recorded.

            signal : 2-by-n float array
                Signal to discretise. signal[0] is the independent
                (time-like) variable. signal[1] is the dependent
                (voltage / position / etc.)-like variable.

            period : float > 0
                Time taken for the signal to complete a single
                oscillation.

            n_tries : int > 0
                Number of times to restart the optimisation, to avoid
                local minima. More is better, but slower.

        Returns an interior knot vector that produces the
        lowest-residual splines fit to the provided data.
        """
        def loss(interior_knots):
            # Training error under current knots
            spline = splines.PeriodicSpline(np.sort(interior_knots))
            coeffs = spline.fit(signal[0], signal[1], period)
            residuals = signal[1] - spline(signal[0], coeffs, period)
            return np.linalg.norm(residuals)**2

        # Uniform distribution for initial knots
        initial_knots = scipy.stats.uniform().rvs((n_tries, self.dsize))

        # Keep re-optimizing; store best result
        best_loss = np.inf
        best_knots = None
        bounds = scipy.optimize.Bounds(0, 1)
        for k in initial_knots:
            opti = scipy.optimize.minimize(loss, k, bounds=bounds)
            print("Proposed knots: \n", np.sort(opti.x))
            print(opti, "\n")
            if opti.fun < best_loss:
                best_loss = opti.fun
                best_knots = opti.x
        self.mesh = np.sort(best_knots)
        self._spline = splines.PeriodicSpline(self.mesh)
        return self.mesh
コード例 #3
0
ファイル: collocation.py プロジェクト: MarkBlyth/cbclib
 def __init__(self, mesh_size, order=3):
     """
     BSpline collocation doesn't divide the data into subintervals.
     Instead, it maintains a single subinterval over the entire BVP
     domain [0,1]. The subinterval mesh is taken as a knot list for
     the spline functions. mesh_size therefore specifies the number
     of BSpline basis functions, and order specifies the order of
     the splines, similarly to with polynomial collocation. Note
     that BSpline collocation is only implemented for third-order
     (cubic) BSplines, so choosing an order!=3 will raise a
     NotImplementedError. Also, for third-order periodic splines,
     we require at least 4 BSpline functions, so choosing
     mesh_size<4 will raise a ValueError.
     """
     if mesh_size < 4:
         raise ValueError("Must have at least 4 cubic BSpline functions")
     if order != 3:
         raise NotImplementedError(
             "BSpline collocation is only implemented for third-order BSplines"
         )
     super().__init__(1, mesh_size)
     self.splines = splines.PeriodicSpline(self.full_mesh[1:-1])
コード例 #4
0
 def loss(interior_knots):
     # Training error under current knots
     spline = splines.PeriodicSpline(np.sort(interior_knots))
     coeffs = spline.fit(signal[0], signal[1], period)
     residuals = signal[1] - spline(signal[0], coeffs, period)
     return np.linalg.norm(residuals)**2
コード例 #5
0
 def __init__(self, dsize):
     self.dsize = dsize
     interior_knots = np.linspace(0, 1, dsize + 2)[1:-1]
     self._spline = splines.PeriodicSpline(interior_knots)