From 60a5fa26f9380face88fb5c7ba86f7d63e74fd66 Mon Sep 17 00:00:00 2001 From: "E. Joshua Rigler" <erigler@usgs.gov> Date: Tue, 12 Feb 2019 13:08:55 -0700 Subject: [PATCH] Leave SqDistAlgorithm's state alone if no inputs Fixes issue #239, whereby the next_starttime state variable was incremented even if no input was passed to SqDistAlgorithm.process_one(), and therefore no processing was performed by SqDistAlgorithm.additive(). Also, modified SqDistAlgorithm.additive() so that the state variables returned were consistent with the last *input* sample, and NOT with the last output sample (they could differ if fc input parameter were ever used). --- geomagio/algorithm/SqDistAlgorithm.py | 45 +++++++++++++++++---------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/geomagio/algorithm/SqDistAlgorithm.py b/geomagio/algorithm/SqDistAlgorithm.py index 12d99564a..e850ab0ea 100644 --- a/geomagio/algorithm/SqDistAlgorithm.py +++ b/geomagio/algorithm/SqDistAlgorithm.py @@ -256,18 +256,23 @@ class SqDistAlgorithm(Algorithm): self.last_observatory = trace.stats.station self.last_channel = trace.stats.channel self.last_delta = trace.stats.delta - # TODO: double check next_starttime. Does this work as expected when - # projecting into the future, as long as the inputs are set correctly? - self.next_starttime = trace.stats.endtime + trace.stats.delta + self.next_starttime = trace.stats.starttime + \ + (trace.stats.delta * trace.stats.npts) self.save_state() # create updated traces channel = trace.stats.channel - raw = trace.data + # TODO: consider trimming yhat instead of adding NaNs to raw, even if + # dist will have fewer samples than the other traces in out stream + raw = np.concatenate((trace.data, np.full(self.fc, np.nan))) yhat = np.array(yhat) shat = np.array(shat) dist = np.subtract(raw, yhat) sq = shat sv = np.subtract(yhat, shat) + # TODO: create_trace will add to stats.endtime and adjust stats.npts + # if the data array is longer than expected, as when self.fc is non- + # zero; HOWEVER, if self.hstep is non-zero, both stats.starttime and + # stats.endtime must be adjusted to accomadate the time-shift. out += self.create_trace(channel + '_Dist', trace.stats, dist) out += self.create_trace(channel + '_SQ', trace.stats, sq) out += self.create_trace(channel + '_SV', trace.stats, sv) @@ -468,13 +473,14 @@ class SqDistAlgorithm(Algorithm): if i < len(yobs): et = yobs[i] - yhat[i] else: + # fc>0, so simulate beyond last input et = np.nan if (np.isnan(et) or np.abs(et) > zthresh * sigma[i]): # forecast (i.e., update l, b, and s assuming et==0) # no change in seasonal adjustments - r[i + 1] = 0 + r[i + 1] = 0 + r[i] s[i + m] = s[i] # update l before b @@ -498,10 +504,8 @@ class SqDistAlgorithm(Algorithm): else: # smooth (i.e., update l, b, and s by filtering et) - # renormalization could occur inside loop, but we choose to - # integrate r, and adjust a and s outside the loop to improve - # performance. - r[i + 1] = gamma * (1 - alpha) * et / m + # r will be used to enforce zero-mean seasonal correction + r[i + 1] = gamma * (1 - alpha) * et / m + r[i] # #update and append to s using equation-error formulation # s[i + m] = s[i] + gamma * (1 - alpha) * et @@ -525,22 +529,31 @@ class SqDistAlgorithm(Algorithm): sumc2 = sumc2_H phiJminus1 = phiHminus1 jstep = hstep + # endif (np.isnan(et) or np.abs(et) > zthresh * sigma[i]) - # endfor i in range(len(yobs) + fc - hstep) + # freeze state with last input for reinitialization + if i == (len(yobs)-1): + yhat0 = yhat[len(yobs):(len(yobs) + hstep)].copy() + s0 = s[len(yobs):(len(yobs) + m)].copy() - r[i + 1] + l0 = l + r[i + 1] + b0 = b + sigma0 = sigma[len(yobs):(len(yobs) + hstep + 1)].copy() + + # endfor i in range(len(yobs) + fc) - r = np.cumsum(r) + # adjustments to enforce zero-mean seasonal corrections l = l + r[-1] s = np.array(s) - np.hstack((r, np.tile(r[-1], m - 1))) return (yhat[:len(yobs) + fc], s[:len(yobs) + fc], sigma[1:len(yobs) + fc + 1], - yhat[len(yobs) + fc:], - s[len(yobs) + fc:], - l, - b, - sigma[len(yobs) + fc:]) + yhat0, + s0, + l0, + b0, + sigma0) @classmethod def estimate_parameters(cls, yobs, m, alpha=None, beta=None, gamma=None, -- GitLab