@@ -296,39 +296,33 @@ def robustdiff(x, dt_or_t, order, log_q, log_r, proc_huberM=6, meas_huberM=0):
296296 - **dxdt_hat** (np.array) -- estimated derivative of x
297297 """
298298 equispaced = np .isscalar (dt_or_t )
299+ if not equispaced and len (x ) != len (dt_or_t ):
300+ raise ValueError ("If `dt_or_t` is given as array-like, must have same length as `x`." )
299301
300302 A_c = np .diag (np .ones (order ), 1 ) # continuous-time A just has 1s on the first diagonal (where 0th is main diagonal)
301303 Q_c = np .zeros (A_c .shape ); Q_c [- 1 ,- 1 ] = 10 ** log_q # continuous-time uncertainty around the last derivative
302304 C = np .zeros ((1 , order + 1 )); C [0 ,0 ] = 1 # we measure only y = noisy x
303305 R = np .array ([[10 ** log_r ]]) # 1 observed state, so this is 1x1
304-
305306 M = np .block ([[A_c , Q_c ], [np .zeros (A_c .shape ), - A_c .T ]]) # exponentiate per step
306307
307308 if equispaced :
308309 # convert to discrete time using matrix exponential
309310 eM = expm (M * dt_or_t ) # Note this could handle variable dt, similar to rtsdiff
310311 A_d = eM [:order + 1 , :order + 1 ]
311- Q_d = eM [:order + 1 , order + 1 :] @ A_d .T #
312- if np .linalg .cond (Q_d ) > 1e12 :
313- Q_d += np .eye (order + 1 )* 1e-12 # for numerical stability with convex solver. Doesn't change answers appreciably (or at all).
312+ Q_d = eM [:order + 1 , order + 1 :] @ A_d .T
313+ if np .linalg .cond (Q_d ) > 1e12 : Q_d += np .eye (order + 1 )* 1e-12 # for numerical stability with convex solver. Doesn't change answers appreciably (or at all).
314+ else : # support variable step size for this function
315+ A_d = np .empty ((len (x )- 1 , order + 1 , order + 1 )) # stack all the evolution matrices
316+ Q_d = np .empty ((len (x )- 1 , order + 1 , order + 1 ))
314317
315- x_states = convex_smooth (x , A_d , Q_d , C , R , proc_huberM = proc_huberM , meas_huberM = meas_huberM ) # outsource solution of the convex optimization problem
316- else : # support variable step size for this function
317- N = len (x )
318- if N != len (dt_or_t ): raise ValueError ("If `dt_or_t` is given as array-like, must have same length as `x`." )
319-
320- A_ds = np .empty ((N - 1 , order + 1 , order + 1 ))
321- Q_ds = np .empty ((N - 1 , order + 1 , order + 1 ))
322318 for i , dt in enumerate (np .diff (dt_or_t )): # for each variable time step
323319 eM = expm (M * dt )
324- A_ds [i ] = eM [:order + 1 , :order + 1 ] # extract discrete time A matrix
325- Q_ds [i ] = eM [:order + 1 , order + 1 :] @ A_ds [i ].T # extract discrete time Q matrix
326- if dt < 0 : Q_ds [i ] = np .abs (Q_ds [i ]) # eigenvalues go negative if reverse time, but noise shouldn't shrink
327- if np .linalg .cond (Q_ds [i ]) > 1e12 :
328- Q_ds [i ] += np .eye (order + 1 )* 1e-12
329-
330- x_states = convex_smooth (x , A_ds , Q_ds , C , R , proc_huberM = proc_huberM , meas_huberM = meas_huberM ) # outsource solution of the convex optimization problem
320+ A_d [i ] = eM [:order + 1 , :order + 1 ] # extract discrete time A matrix
321+ Q_d [i ] = eM [:order + 1 , order + 1 :] @ A_d [i ].T # extract discrete time Q matrix
322+ if dt < 0 : Q_d [i ] = np .abs (Q_d [i ]) # eigenvalues go negative if reverse time, but noise shouldn't shrink
323+ if np .linalg .cond (Q_d [i ]) > 1e12 : Q_d [i ] += np .eye (order + 1 )* 1e-12
331324
325+ x_states = convex_smooth (x , A_d , Q_d , C , R , proc_huberM = proc_huberM , meas_huberM = meas_huberM ) # outsource solution of the convex optimization problem
332326 return x_states [:,0 ], x_states [:,1 ]
333327
334328
0 commit comments