def estimate_good_plot_length(xx, chrono=None, mult=100): """ Estimate good length for plotting stuff from the time scale of the system. Provide sensible fall-backs (better if chrono is supplied). """ if xx.ndim == 2: # If mult-dim, then average over dims (by ravel).... # But for inhomogeneous variables, it is important # to subtract the mean first! xx = xx - np.mean(xx, axis=0) xx = xx.ravel(order='F') try: K = mult * series.estimate_corr_length(xx) except ValueError: K = 0 if chrono is not None: t = chrono K = int(min(max(K, t.dkObs), t.K)) T = round2(t.tt[K], 2) # Could return T; T>tt[-1] K = utils.find_1st_ind(t.tt >= T) if K: return K else: return t.K else: K = int(min(max(K, 1), len(xx))) T = round2(K, 2) return K
def assimilate(self, HMM, xx, yy): Dyn, Obs, chrono, stats = HMM.Dyn, HMM.Obs, HMM.t, self.stats # Compute "climatological" Kalman gain muC = np.mean(xx, 0) AC = xx - muC PC = (AC.T @ AC) / (xx.shape[0] - 1) # Setup scalar "time-series" covariance dynamics. # ONLY USED FOR DIAGNOSTICS, not to affect the Kalman gain. L = series.estimate_corr_length(AC.ravel(order='F')) SM = fit_sigmoid(1/2, L, 0) # Init mu = muC stats.assess(0, mu=mu, Cov=PC) for k, kObs, t, dt in progbar(chrono.ticker): # Forecast mu = Dyn(mu, t-dt, dt) if kObs is not None: stats.assess(k, kObs, 'f', mu=muC, Cov=PC) # Analysis H = Obs.linear(muC, t) KG = mtools.mrdiv([email protected], H@[email protected] + Obs.noise.C.full) mu = muC + KG@(yy[kObs] - Obs(muC, t)) P = (np.eye(Dyn.M) - KG@H) @ PC SM = fit_sigmoid(P.trace()/PC.trace(), L, k) stats.assess(k, kObs, mu=mu, Cov=2*PC*SM(k))
def estimate_good_plot_length(xx, chrono=None, mult=100): """Estimate the range of the xx slices for plotting. The length is based on the estimated time scale (wavelength) of the system. Provide sensible fall-backs (better if chrono is supplied). Parameters ---------- xx: ndarray Plotted array chrono: `dapper.tools.chronos.Chronology`, optional object with property dkObS. Defaults: None mult: int, optional Number of waves for plotting. Defaults: 100 Returns ------- K: int length for plotting Example ------- >>> K_lag = estimate_good_plot_length(stats.xx, chrono, mult=80) # doctest: +SKIP """ if xx.ndim == 2: # If mult-dim, then average over dims (by ravel).... # But for inhomogeneous variables, it is important # to subtract the mean first! xx = xx - np.mean(xx, axis=0) xx = xx.ravel(order='F') try: K = mult * series.estimate_corr_length(xx) except ValueError: K = 0 if chrono is not None: t = chrono K = int(min(max(K, t.dkObs), t.K)) T = round2sigfig(t.tt[K], 2) # Could return T; T>tt[-1] K = find_1st_ind(t.tt >= T) if K: return K else: return t.K else: K = int(min(max(K, 1), len(xx))) T = round2sigfig(K, 2) return K
def assimilate(self, HMM, xx, yy): Dyn, Obs, chrono, X0, stats = HMM.Dyn, HMM.Obs, HMM.t, HMM.X0, self.stats if isinstance(self.B, np.ndarray): # compare ndarray 1st to avoid == error for ndarray B = self.B.astype(float) elif self.B in (None, 'clim'): # Use climatological cov, estimated from truth B = np.cov(xx.T) elif self.B == 'eye': B = np.eye(HMM.Nx) else: raise ValueError("Bad input B.") B *= self.xB # ONLY USED FOR DIAGNOSTICS, not to change the Kalman gain. CC = 2 * np.cov(xx.T) L = series.estimate_corr_length(center(xx)[0].ravel(order='F')) P = X0.C.full SM = fit_sigmoid(P.trace() / CC.trace(), L, 0) # Init mu = X0.mu stats.assess(0, mu=mu, Cov=P) for k, kObs, t, dt in progbar(chrono.ticker): # Forecast mu = Dyn(mu, t - dt, dt) P = CC * SM(k) if kObs is not None: stats.assess(k, kObs, 'f', mu=mu, Cov=P) # Analysis H = Obs.linear(mu, t) KG = mrdiv(B @ H.T, H @ B @ H.T + Obs.noise.C.full) mu = mu + KG @ (yy[kObs] - Obs(mu, t)) # Re-calibrate fit_sigmoid with new W0 = Pa/B P = (np.eye(Dyn.M) - KG @ H) @ B SM = fit_sigmoid(P.trace() / CC.trace(), L, k) stats.assess(k, kObs, mu=mu, Cov=P)