def weighted_average_slopes(data, old_start, old_dt, new_start, new_dt, new_npts, *args, **kwargs): """ Implements the weighted average slopes interpolation scheme proposed in [Wiggins1976]_ for evenly sampled data. The scheme guarantees that there will be no additional extrema after the interpolation in contrast to spline interpolation. The slope :math:`s_i` at each knot is given by a weighted average of the adjacent linear slopes :math:`m_i` and :math:`m_{i+j}`: .. math:: s_i = (w_i m_i + w_{i+1} m_{i+1}) / (w_i + w_{i+1}) where .. math:: w = 1 / max \left\{ \left\| m_i \\right\|, \epsilon \\right\} The value at each data point and the slope are then plugged into a piecewise continuous cubic polynomial used to evaluate the interpolated sample points. :type data: array_like :param data: Array to interpolate. :type old_start: float :param old_start: The start of the array as a number. :type old_start: float :param old_dt: The time delta of the current array. :type new_start: float :param new_start: The start of the interpolated array. Must be greater or equal to the current start of the array. :type new_dt: float :param new_dt: The desired new time delta. :type new_npts: int :param new_npts: The new number of samples. """ old_end, new_end = _validate_parameters(data, old_start, old_dt, new_start, new_dt, new_npts) # In almost all cases the unit will be in time. new_time_array = np.linspace(new_start, new_end, new_npts) m = np.diff(data) / old_dt w = np.abs(m) w = 1.0 / np.clip(w, np.spacing(1), w.max()) slope = np.empty(len(data), dtype=np.float64) slope[0] = m[0] slope[1:-1] = (w[:-1] * m[:-1] + w[1:] * m[1:]) / (w[:-1] + w[1:]) slope[-1] = m[-1] # If m_i and m_{i+1} have opposite signs then set the slope to zero. # This forces the curve to have extrema at the sample points and not # in-between. sign_change = np.diff(np.sign(m)).astype(np.bool) slope[1:-1][sign_change] = 0.0 derivatives = np.empty((len(data), 2), dtype=np.float64) derivatives[:, 0] = data derivatives[:, 1] = slope # Create interpolated value using hermite interpolation. In this case # it is directly applicable as the first derivatives are known. # Using scipy.interpolate.piecewise_polynomial_interpolate() is too # memory intensive return_data = np.empty(len(new_time_array), dtype=np.float64) clibsignal.hermite_interpolation(data, slope, new_time_array, return_data, len(data), len(return_data), old_dt, old_start) return return_data
def weighted_average_slopes(data, old_start, old_dt, new_start, new_dt, new_npts, *args, **kwargs): r""" Implements the weighted average slopes interpolation scheme proposed in [Wiggins1976]_ for evenly sampled data. The scheme guarantees that there will be no additional extrema after the interpolation in contrast to spline interpolation. The slope :math:`s_i` at each knot is given by a weighted average of the adjacent linear slopes :math:`m_i` and :math:`m_{i+j}`: .. math:: s_i = (w_i m_i + w_{i+1} m_{i+1}) / (w_i + w_{i+1}) where .. math:: w = 1 / max \left\{ \left\| m_i \\right\|, \epsilon \\right\} The value at each data point and the slope are then plugged into a piecewise continuous cubic polynomial used to evaluate the interpolated sample points. :type data: array_like :param data: Array to interpolate. :type old_start: float :param old_start: The start of the array as a number. :type old_start: float :param old_dt: The time delta of the current array. :type new_start: float :param new_start: The start of the interpolated array. Must be greater or equal to the current start of the array. :type new_dt: float :param new_dt: The desired new time delta. :type new_npts: int :param new_npts: The new number of samples. """ old_end, new_end = _validate_parameters(data, old_start, old_dt, new_start, new_dt, new_npts) # In almost all cases the unit will be in time. new_time_array = np.linspace(new_start, new_end, new_npts) m = np.diff(data) / old_dt w = np.abs(m) w = 1.0 / np.clip(w, np.spacing(1), w.max()) slope = np.empty(len(data), dtype=np.float64) slope[0] = m[0] slope[1:-1] = (w[:-1] * m[:-1] + w[1:] * m[1:]) / (w[:-1] + w[1:]) slope[-1] = m[-1] # If m_i and m_{i+1} have opposite signs then set the slope to zero. # This forces the curve to have extrema at the sample points and not # in-between. sign_change = np.diff(np.sign(m)).astype(np.bool) slope[1:-1][sign_change] = 0.0 derivatives = np.empty((len(data), 2), dtype=np.float64) derivatives[:, 0] = data derivatives[:, 1] = slope # Create interpolated value using hermite interpolation. In this case # it is directly applicable as the first derivatives are known. # Using scipy.interpolate.piecewise_polynomial_interpolate() is too # memory intensive return_data = np.empty(len(new_time_array), dtype=np.float64) clibsignal.hermite_interpolation(data, slope, new_time_array, return_data, len(data), len(return_data), old_dt, old_start) return return_data