def calc_avg_amps(refs_all, data_shape, nchans=4, altcol=True): """Calculate amplifier averages Save the average reference value for each amplifier in each frame. Assume by default that alternating columns are offset from each other, so we save two arrays: self.refs_amps_avg1 and self.refs_amps_avg2. Each array has a size of (namp, ngroup). Parameters ---------- refs_all : ndarray The top and/or bottom references pixels order in a shape (nz, nref_rows, nx) data_shape : tuple Shape of the data array: (nz, ny, nx). nchans : int Number of amplifier output channels. altcol : bool Calculate separate reference values for even/odd columns? Default=True. """ nz, ny, nx = data_shape chsize = int(nx / nchans) if altcol: refs_amps_avg1 = [] refs_amps_avg2 = [] for ch in range(nchans): # Channel indices ich1 = ch * chsize ich2 = ich1 + chsize # Slice out alternating columns refs_ch1 = refs_all[:, :, ich1:ich2 - 1:2].reshape((nz, -1)) refs_ch2 = refs_all[:, :, ich1 + 1:ich2:2].reshape((nz, -1)) # Take the resistant mean chavg1 = robust.mean(refs_ch1, axis=1) chavg2 = robust.mean(refs_ch2, axis=1) refs_amps_avg1.append(chavg1) refs_amps_avg2.append(chavg2) return (np.array(refs_amps_avg1), np.array(refs_amps_avg2)) else: refs_amps_avg = [] for ch in range(nchans): # Channel indices ich1 = ch * chsize ich2 = ich1 + chsize # Slice out alternating columns refs_ch = refs_all[:, :, ich1:ich2].reshape((nz, -1)) # Take the resistant mean and reshape for broadcasting chavg = robust.mean(refs_ch, axis=1).reshape(-1, 1, 1) refs_amps_avg.append(chavg) return np.array(refs_amps_avg)
def calc_avg_amps(refs_all, data_shape, nchans=4, altcol=True): """ Save the average reference value for each amplifier in each frame. This assumes that alternating columns are offset from each other, so we save two arrays: self.refs_amps_avg1 and self.refs_amps_avg2. Each array has a size of (namp, ngroup). top_ref (bool) : Include top reference rows when correcting channel offsets. bot_ref (bool) : Include bottom reference rows when correcting channel offsets. """ nz, ny, nx = data_shape chsize = int(nx / nchans) if altcol: refs_amps_avg1 = [] refs_amps_avg2 = [] for ch in range(nchans): # Channel indices ich1 = ch * chsize ich2 = ich1 + chsize # Slice out alternating columns refs_ch1 = refs_all[:, :, ich1:ich2 - 1:2].reshape((nz, -1)) refs_ch2 = refs_all[:, :, ich1 + 1:ich2:2].reshape((nz, -1)) # Take the resistant mean chavg1 = robust.mean(refs_ch1, axis=1) chavg2 = robust.mean(refs_ch2, axis=1) refs_amps_avg1.append(chavg1) refs_amps_avg2.append(chavg2) return (np.array(refs_amps_avg1), np.array(refs_amps_avg2)) else: refs_amps_avg = [] for ch in range(nchans): # Channel indices ich1 = ch * chsize ich2 = ich1 + chsize # Slice out alternating columns refs_ch = refs_all[:, :, ich1:ich2].reshape((nz, -1)) # Take the resistant mean and reshape for broadcasting chavg = robust.mean(refs_ch, axis=1).reshape(-1, 1, 1) refs_amps_avg.append(chavg) return np.array(refs_amps_avg)
def correct_amp_refs(self, supermean=False): """Correct amplifier offsets Use values in ``self.refs_amps_avg`` to correct amplifier offsets. Parameters ---------- supermean : bool Add back the overall mean of the reference pixels. """ # Check to make sure refs_amps_avg is valid if (self.refs_amps_avg is None): _log.warning( 'self.refs_amps_avg is set to None. No offsets applied.') return #raise ValueError('self.refs_amps_avg is set to None') # Supermean # the average of the average is the DC level of the output channel smean = robust.mean(refs_all) if supermean else 0.0 nchans = self.detector.nout chsize = self.detector.chsize nz, ny, nx = self.data.shape for ch in range(nchans): # Channel indices ich1 = int(ch * chsize) ich2 = int(ich1 + chsize) # In-place subtraction of channel averages if self.altcol: for i in range(nz): self.data[i, :, ich1:ich2 - 1:2] -= self.refs_amps_avg[0][ch, i] self.data[i, :, ich1 + 1:ich2:2] -= self.refs_amps_avg[1][ch, i] else: for i in range(nz): self.data[i, :, ich1:ich2] -= self.refs_amps_avg[ch, i] # Add back supermean if supermean: self.data += smean
def correct_amp_refs(self, supermean=False): """ Use values from calc_avg_amps to correct amplifier offsets. supermean (bool) : Add back the overall mean of the reference pixels. """ # Check to make sure refs_amps_avg is valid if (self.refs_amps_avg is None): raise ValueError('self.refs_amps_avg is set to None') # Supermean # the average of the average is the DC level of the output channel smean = robust.mean(refs_all) if supermean else 0.0 nchans = self.detector.nout chsize = self.detector.chsize nz, ny, nx = self.data.shape for ch in range(nchans): # Channel indices ich1 = ch * chsize ich2 = ich1 + chsize # In-place subtraction of channel averages if self.altcol: for i in range(nz): self.data[i, :, ich1:ich2 - 1:2] -= self.refs_amps_avg[0][ch, i] self.data[i, :, ich1 + 1:ich2:2] -= self.refs_amps_avg[1][ch, i] else: for i in range(nz): self.data[i, :, ich1:ich2] -= self.refs_amps_avg[ch, i] # Add back supermean if supermean: self.data += smean
def reffix_amps(cube, nchans=4, in_place=True, altcol=True, supermean=False, top_ref=True, bot_ref=True, ntop=4, nbot=4, **kwargs): """Correct amplifier offsets Matches all amplifier outputs of the detector to a common level. This routine subtracts the average of the top and bottom reference rows for each amplifier and frame individually. By default, reference pixel corrections are performed in place since it's faster and consumes less memory. Parameters ---------- cube : ndarray Input datacube. Can be two or three dimensions (nz,ny,nx). nchans : int Number of output amplifier channels in the detector. Default=4. altcol : bool Calculate separate reference values for even/odd columns. supermean : bool Add back the overall mean of the reference pixels. in_place : bool Perform calculations in place. Input array is overwritten. top_ref : bool Include top reference rows when correcting channel offsets. bot_ref : bool Include bottom reference rows when correcting channel offsets. ntop : int Specify the number of top reference rows. nbot : int Specify the number of bottom reference rows. """ if not in_place: cube = np.copy(cube) # Check the number of dimensions are valid. ndim = len(cube.shape) if ndim == 2: ny, nx = cube.shape nz = 1 cube = cube.reshape((nz, ny, nx)) elif ndim == 3: nz, ny, nx = cube.shape else: raise ValueError('Input data can only have 2 or 3 dimensions. \ Found {} dimensions.'.format(ndim)) chsize = int(nx / nchans) # Number of reference rows to use # Set nt or nb equal to 0 if we don't want to use either nt = ntop if top_ref else 0 nb = nbot if bot_ref else 0 if (nt + nb) == 0: print("No reference pixels available for use. Returning...") return # Slice out reference pixels refs_bot = cube[:, :nb, :] refs_top = cube[:, -nt:, :] if nt == 0: refs_all = refs_bot elif nb == 0: refs_all = refs_top else: refs_all = np.hstack((refs_bot, refs_top)) assert refs_all.shape[1] == (nb + nt) # Supermean # the average of the average is the DC level of the output channel smean = robust.mean(refs_all) if supermean else 0.0 # Calculate avg reference values for each frame and channel refs_amps_avg = calc_avg_amps(refs_all, cube.shape, nchans=nchans, altcol=altcol) for ch in range(nchans): # Channel indices ich1 = ch * chsize ich2 = ich1 + chsize # In-place subtraction of channel medians if altcol: for i in range(nz): cube[i, :, ich1:ich2 - 1:2] -= refs_amps_avg[0][ch, i] cube[i, :, ich1 + 1:ich2:2] -= refs_amps_avg[1][ch, i] else: for i in range(nz): cube[i, :, ich1:ich2] -= refs_amps_avg[ch, i] # Add back supermean if supermean: cube += smean cube = cube.squeeze() return cube