def _update_buffer(self, data: np.ndarray, cache: PerFrameCache) -> None: """ Update self._buffer by adding `data` and a step function. Data is reshaped to taper away from the center. :param data: Wave data. WILL BE MODIFIED. """ assert cache.mean is not None assert cache.period is not None buffer_falloff = self.cfg.buffer_falloff responsiveness = self.cfg.responsiveness N = len(data) if N != self._buffer_nsamp: raise ValueError(f"invalid data length {len(data)} does not match " f"CorrelationTrigger {self._buffer_nsamp}") # New waveform data -= cache.mean normalize_buffer(data) window = windows.gaussian(N, std=(cache.period / self._stride) * buffer_falloff) data *= window # Old buffer normalize_buffer(self._buffer) self._buffer = lerp(self._buffer, data, responsiveness)
def gaussian_or_zero(M: int, std: float, sym: bool = True) -> np.ndarray: """ Sometimes `std` is computed based on period. If period is zero (cannot be estimated), return all zeros. """ if std == 0: return np.zeros(M, dtype=f32) else: return windows.gaussian(M, std, sym)
def calc_step(nsamp: int, peak: float, stdev: float) -> np.ndarray: """ Step function used for approximate edge triggering. TODO deduplicate CorrelationTrigger._calc_step() """ N = nsamp halfN = N // 2 step = np.empty(N, dtype=FLOAT) # type: np.ndarray[FLOAT] step[:halfN] = -peak / 2 step[halfN:] = peak / 2 step *= windows.gaussian(N, std=halfN * stdev) return step
def _calc_step(self) -> np.ndarray: """ Step function used for approximate edge triggering. """ # Increasing buffer_falloff (width of history buffer) # causes buffer to affect triggering, more than the step function. # So we multiply edge_strength (step function height) by buffer_falloff. edge_strength = self.cfg.edge_strength * self.cfg.buffer_falloff N = self._buffer_nsamp halfN = N // 2 step = np.empty(N, dtype=FLOAT) # type: np.ndarray[FLOAT] step[:halfN] = -edge_strength / 2 step[halfN:] = edge_strength / 2 step *= windows.gaussian(N, std=halfN / 3) return step
def _calc_slope_finder(self, period: float) -> np.ndarray: """Called whenever period changes substantially. Returns a kernel to be correlated with input data to find positive slopes, with length A+B.""" cfg = self.cfg kernel_size = self.A + self.B # noinspection PyTypeChecker slope_width: float = np.clip(cfg.slope_width * period, 1.0, self.A / 3) # This is a fudge factor. Adjust it until it feels right. slope_strength = cfg.edge_strength * 5 # slope_width is 1.0 or greater, so this doesn't divide by 0. slope_finder = np.empty(kernel_size, dtype=f32) # type: np.ndarray[f32] slope_finder[:self.A] = -slope_strength / 2 slope_finder[self.A:] = slope_strength / 2 slope_finder *= windows.gaussian(kernel_size, std=slope_width) return slope_finder