def calc_flatten_matrix(flatten: FlattenOrStr, stereo_nchan: int) -> np.ndarray: """Raises CorrError on invalid input. If flatten is Flatten.Stereo, returns shape=(nchan,nchan) identity matrix. - (N,nchan) @ (nchan,nchan) = (N,nchan). Otherwise, returns shape=(nchan) flattening matrix. - (N,nchan) @ (nchan) = (N) https://docs.scipy.org/doc/numpy/reference/generated/numpy.matmul.html#numpy.matmul ''' If the second argument is 1-D, it is promoted to a matrix by appending a 1 to its dimensions. After matrix multiplication the appended 1 is removed." ''' """ if flatten is Flatten.Stereo: # 2D identity (results in 2-dim data) flatten_matrix = np.eye(stereo_nchan, dtype=FLOAT) # 1D (results in 1-dim data) elif flatten is Flatten.SumAvg: flatten_matrix = np.ones(stereo_nchan, dtype=FLOAT) / stereo_nchan elif flatten is Flatten.DiffAvg: flatten_matrix = calc_flatten_matrix(str(flatten), stereo_nchan) flatten_matrix = rightpad(flatten_matrix, stereo_nchan, 0) else: words = flatten.replace(",", " ").split() try: flatten_matrix = np.array([FLOAT(word) for word in words]) except ValueError as e: raise CorrError("Invalid stereo flattening matrix") from e flatten_abs_sum = np.sum(np.abs(flatten_matrix)) if flatten_abs_sum == 0: raise CorrError( "Stereo flattening matrix must have nonzero elements") flatten_matrix /= flatten_abs_sum assert flatten_matrix.dtype == FLOAT, flatten_matrix.dtype return flatten_matrix
def _calc_lag_prevention(self) -> np.ndarray: """ Returns input-data window, which zeroes out all data older than 1-ish frame old. See https://github.com/jimbo1qaz/corrscope/wiki/Correlation-Trigger """ N = self._buffer_nsamp halfN = N // 2 # - Create a cosine taper of `width` <= 1 frame # - Right-pad(value=1, len=1 frame) # - Place in left half of N-sample buffer. # To avoid cutting off data, use a narrow transition zone (invariant to stride). lag_prevention = self.cfg.lag_prevention tsamp_frame = self._tsamp_frame transition_nsamp = round(tsamp_frame * lag_prevention.transition_frames) # Left half of a Hann cosine taper # Width (type=subsample) = min(frame * lag_prevention, 1 frame) assert transition_nsamp <= tsamp_frame width = transition_nsamp taper = windows.hann(width * 2)[:width] # Right-pad=1 taper to lag_prevention.max_frames long [t-#*f, t] taper = rightpad(taper, iround(tsamp_frame * lag_prevention.max_frames)) # Left-pad=0 taper to left `halfN` of data_taper [t-halfN, t] taper = leftpad(taper, halfN) # Generate left half-taper to prevent correlating with 1-frame-old data. # Right-pad=1 taper to [t-halfN, t-halfN+N] # TODO switch to rightpad()? Does it return FLOAT or not? data_taper = np.ones(N, dtype=FLOAT) data_taper[:halfN] = np.minimum(data_taper[:halfN], taper) return data_taper