Skip to content

Commit 0e477fe

Browse files
authored
Merge pull request #194 from florisvb/polydiff-multidim
Add axis parameter to polydiff (#76)
2 parents 214b3e2 + 0e0d09c commit 0e477fe

2 files changed

Lines changed: 19 additions & 11 deletions

File tree

pynumdiff/polynomial_fit.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def splinediff(x, dt_or_t, params=None, options=None, degree=3, s=None, num_iter
5050

5151

5252
def polydiff(x, dt_or_t, params=None, options=None, degree=None, window_size=None, step_size=1,
53-
kernel='friedrichs'):
53+
kernel='friedrichs', axis=0):
5454
"""Fit polynomials to the data, and differentiate the polynomials.
5555
5656
:param np.array[float] x: data to differentiate. May contain NaN values (missing data); NaNs are excluded from
@@ -64,6 +64,7 @@ def polydiff(x, dt_or_t, params=None, options=None, degree=None, window_size=Non
6464
:param int window_size: size of the sliding window, if not given no sliding
6565
:param int step_size: step size for sliding
6666
:param str kernel: name of kernel to use for weighting and smoothing windows ('gaussian' or 'friedrichs')
67+
:param int axis: data dimension along which differentiation is performed
6768
6869
:return: - **x_hat** (np.array) -- estimated (smoothed) x
6970
- **dxdt_hat** (np.array) -- estimated derivative of x
@@ -80,11 +81,13 @@ def polydiff(x, dt_or_t, params=None, options=None, degree=None, window_size=Non
8081
elif degree is None or window_size is None:
8182
raise ValueError("`degree` and `window_size` must be given.")
8283

83-
if window_size < degree*3:
84-
window_size = degree*3+1
85-
if window_size % 2 == 0:
86-
window_size += 1
87-
warn("Kernel window size should be odd. Added 1 to length.")
84+
if window_size:
85+
if window_size < degree*3:
86+
window_size = degree*3+1
87+
if window_size % 2 == 0:
88+
window_size += 1
89+
warn("Kernel window size should be odd. Added 1 to length.")
90+
kernel = {'gaussian':utility.gaussian_kernel, 'friedrichs':utility.friedrichs_kernel}[kernel](window_size)
8891

8992
def _polydiff(x, dt_or_t, degree, weights=None):
9093
t = dt_or_t if not np.isscalar(dt_or_t) else np.arange(len(x)) * dt_or_t # sample locations
@@ -99,10 +102,13 @@ def _polydiff(x, dt_or_t, degree, weights=None):
99102

100103
return x_hat, dxdt_hat
101104

102-
if not window_size: return _polydiff(x, dt_or_t, degree)
103-
104-
kernel = {'gaussian':utility.gaussian_kernel, 'friedrichs':utility.friedrichs_kernel}[kernel](window_size)
105-
return utility.slide_function(_polydiff, x, dt_or_t, kernel, degree, stride=step_size, pass_weights=True)
105+
x_hat = np.empty_like(x); dxdt_hat = np.empty_like(x)
106+
for vec_idx in np.ndindex(x.shape[:axis] + x.shape[axis+1:]):
107+
s = vec_idx[:axis] + (slice(None),) + vec_idx[axis:]
108+
x_hat[s], dxdt_hat[s] = _polydiff(x[s], dt_or_t, degree) if not window_size else \
109+
utility.slide_function(_polydiff, x[s], dt_or_t, kernel, degree, stride=step_size, pass_weights=True)
110+
111+
return x_hat, dxdt_hat
106112

107113

108114
def savgoldiff(x, dt, params=None, options=None, degree=None, window_size=None, smoothing_win=None, axis=0):

pynumdiff/tests/test_diff_methods.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,9 +325,10 @@ def test_diff_method(diff_method_and_params, test_func_and_deriv, request): # re
325325
(kerneldiff, {'kernel': 'gaussian', 'window_size': 5}),
326326
(butterdiff, {'filter_order': 3, 'cutoff_freq': 1 - 1e-6}),
327327
(finitediff, {}),
328+
(polydiff, {'degree': 2, 'window_size': 5}),
328329
(savgoldiff, {'degree': 3, 'window_size': 11, 'smoothing_win': 3}),
329330
(rtsdiff, {'order':2, 'log_qr_ratio':7, 'forwardbackward':True}),
330-
(robustdiff, {'order':2, 'log_q':7, 'log_r':2}),
331+
(robustdiff, {'order':2, 'log_q':7, 'log_r':2})
331332
]
332333

333334
# Similar to the error_bounds table, index by method first. But then we test against only one 2D function,
@@ -338,6 +339,7 @@ def test_diff_method(diff_method_and_params, test_func_and_deriv, request): # re
338339
kerneldiff: [(2, 1), (3, 2)],
339340
butterdiff: [(0, -1), (1, -1)],
340341
finitediff: [(0, -1), (1, -1)],
342+
polydiff: [(1, -1), (1, 0)],
341343
savgoldiff: [(0, -1), (1, 1)],
342344
rtsdiff: [(1, -1), (1, 0)],
343345
robustdiff: [(-2, -3), (0, -1)]

0 commit comments

Comments
 (0)