obstools.scrub_deveny_pickup module
Scrubber for DeVeny Pickup Noise Module
LDTObserverTools contains python ports of various LDT Observer Tools
Lowell Discovery Telescope (Lowell Observatory: Flagstaff, AZ) https://lowell.edu
This module cleans the RF pickup noise from DeVeny spectral 2D images by fitting a sinusoid to and then subtracting it from each row of the image.
The frequency of the sinusoid tends to vary from frame to frame but is roughly
CONSTANT within each frame. Between the non-integer wavelength and the slight
delay between row read-out (caused by the advancement of the parallel register)
the phase shifts from row to row, yielding an ever-changing pattern in the
output images. In order to identify the frequency in a given image, this
module fist taken the FFT of the flattened (i.e., time series) image to
identify the strongest frequency. (The function that performs the FFT also
modifies a copy of the data in various ways to remove spurious signals in the
FFT.) From there, it uses a tightly bounded curve fitting (from
scipy.optimize
) to identify the sinusoid in each line of the image.
Cosmic rays and other impulsive features in the 2D image can cause spurious matches for the sinusoid. So to guard against introducing artifacts into the cleaned image from the fitting, the row-by-row fit coefficients are each considered as a function and smoothed with an appropriate median window to ensure the final subtracted pattern is a smooth function, matching the underlying pickup noise.
The output of the module is a multi-extension FITS file containing [1] the cleaned image, [2] the original image, [3,4] the pattern subtracted from the original image, and [5] a FITS BinTable containing the sinusoid fit parameters for each row of the image.
- class obstools.scrub_deveny_pickup.ScrubDevenyPickup[source]
Bases:
ScriptBase
Script class for
scrub_deveny_pickup
toolScript structure borrowed from
pypeit.scripts.scriptbase.ScriptBase
.- classmethod get_parser(width=None)[source]
Construct the command-line argument parser.
- Parameters:
description (
str
, optional) – A short description of the purpose of the script.width (
int
, optional) – Restrict the width of the formatted help output to be no longer than this number of characters, if possible given the help formatter. If None, the width is the same as the terminal width.formatter (
HelpFormatter
) – Class used to format the help output.
- Returns:
ArgumentParser
– Command-line interpreter.
- obstools.scrub_deveny_pickup.clean_pickup(filename: Path, use_hann: bool = False, sine_plot: bool = True, fft_plot: bool = False)[source]
Clean the Pickup Noise
Warning
Deprecated – do not use. Only included for historical purposes. Use
iterative_pypeit_clean()
instead.This is the first version of the cleaning code, which operates directly on the raw DeVeny image. It suffers from confusion from bright night-sky lines and brighter objects. These deficiencies led to the development of the iterative scrubber. This code is kept here for historical purposes.
- Parameters:
filename (
Path
) – The name of the file to cleanuse_hann (
bool
) – Use a Hann window when cleaning the image for FFT (Default: False)sine_plot (
bool
) – Create a plot of the sinusoid pattern fits for this image? (Default: True)fft_plot (
bool
) – Create a plot of the FFT analysis for this image? (Default: False)
- obstools.scrub_deveny_pickup.create_and_apply_pattern(input_array: ndarray, fit_coeffs: Table) tuple[numpy.ndarray, numpy.ndarray] [source]
Construct the pattern from the fit coefficients
Note
The returned
pattern_array
has a mean = 0 (i.e., the pattern is constructed from the pure sinusoid w/o offset or other additive terms).- Parameters:
input_array (
ndarray
) – The input array to be cleanedfit_coeffs (
Table
) – The fit coefficient table produced byfit_lines()
- Returns:
- obstools.scrub_deveny_pickup.create_fft_plot(filename: Path, flat_array: ndarray, y_fft: ndarray, x_fft: ndarray, peak_freq: float, qa_dir: Path = None, extra_graphics: bool = False)[source]
Create the FFT analysis plot
This function creates a multipanel plot saved as
fft_analysis.pdf
in the current working directory. The panels are:The flattened time-like array, where pixels are in the order in which they were read out by the CCD electronics.
The real part of the FFT of the flattened array, where the abscissa is shown as the sinusoid period in pixels.
The imaginary part of the FFT of the flattened array, where the abscissa is shown as the sinusoid period in pixels.
The absolute value squared of the FFT of the flattened array, to show the power as a function of frequency.
- Parameters:
filename (
Path
) – The filename of the raw data frameflat_array (
ndarray
) – The flattened (1D) pixel arrayy_fft (
ndarray
) – The (complex) FFT valuesx_fft (
ndarray
) – The FFT frequencies for the values iny_fft
peak_freq (
float
) – The peak frequency measured from the FFTqa_dir (
Path
, optional) – The QA directory into which to place the optional plots. IfNone
, the plots will be placed in the current working directory. (Default: None)extra_graphics (
bool
, optional) – Produce extra graphics formats for documentation? (Default: False)
- obstools.scrub_deveny_pickup.fit_lines(data_array: ndarray, pixel_period: float, orig_fitc: Table = None, refit_thresh_sig: float = 3.0, trim_ends: bool = True, objmodel_check: bool = False, show_diagnostic: bool = False, fixed_sinusoid: bool = False) Table [source]
Fit a sinusoid to each line in the image
This is like a mini-driver function that fits a sinusoid to each line in the image.
It also can refit lines that have excessive RMS residual as compared to the bulk of the image. To enable the refitting, pass in the fit coefficient table from the first fitting.
- Parameters:
data_array (
ndarray
) – The image array to be processed. This should be HORIZONTAL and in the same orientation as images written out by lois directly from the instrument.pixel_period (
float
) – The predicted pixel period for this image array, as computed byflatten_clean_fft()
.orig_fitc (
Table
, optional) – If refitting, the first-pass fit coefficient table. If absent, then a full fitting of all lines will be performed. (Default: None)refit_thresh_sig (
float
, optional) – Threshold for RMS deviation (in sigma-clipped standard deviation units) from the mean for a line to be refit. (Default: 3.0)trim_ends (
bool
, optional) – Trim the 5 pixels off the ends of the line before fitting? (Default: True)objmodel_check (
bool
, optional) – Is this image the spec2d objmodel? (Default: False)show_diagnostic (
bool
, optional) – Display a diagnotic plot of several lines w/ fit? (Default: False)fixed_sinusoid (
bool
, optional) – Determine the (roughly) constant sinusoid amplitude and period and fit the lines for phase and secular drift only? (Default: False)
- Returns:
Table
– A table object containing the fit coefficients, one table row per row of the inputdata_array
.
- obstools.scrub_deveny_pickup.flatten_clean_fft(data_array: ndarray, use_hann: bool = False, fft_plot: bool = False, qa_dir: Path = None, filename: Path = None, extra_graphics: bool = False) float [source]
Find the peak frequency of sinusoidal noise
- The function name describes what it does:
Flatten the 2D array into a 1D timeseries
Clean the ends of the CCD for smoother transition
Take the FFT to find the proper frequency to return
In order to more effectively find the frequencies of persistent signal across the detector, start by flattening out the data array into a one- dimensional timeseries-like object representing the order in which the pixels are read out.
According to information in Chapter 5 of Scientific Charge-Coupled Devices by James R. Janesick (2001), the time to advance a row along the parallel register is small compared to the individual pixel digitization time because the latter requires a capacitive stabilization time to minimize readnoise, whereas parallel register moves simply move the charge without trying to measure it. Therefore, there is no spacing in between the rows of the flattened arrays to represent the time required for the parallel charge transfer.
Once the array is flattened, we deal with row-to-row edge effects by modifying the flattened array to replace the 10 pixels at the end of one row and the 10 pixels at the start of the next row with a linearly varying series of values. The first 10 and last 10 pixels of the flattened array are set to the next adjacent value. This removes some of the “ringing” power at integer frequencies of an entire row and places it into the fundamental row-length frequency. There are still sharp edges in the flattened array caused by night sky lines, but most of the power from these lines should be at the fundamental frequency (whole-row).
The detected pickup noise has a period in the range 100-300 pixels, so peaks in the power spectrum at lower frequencies than this (e.g., the fundamental row-length frequency) are masked when choosing the return value.
Additionally, the assumption of continuous readout is close but not entriely accurate. The slight pause in the readout caused by the parallel register readout causes the continuous readout amplifier pickup signal to manifest itself as a Gaussian packet of related frequencies in the FFT. By smoothing the power spectrum ( abs(FFT)^2 ) with a Gaussian kernel, narrow spikes in the FFT (caused by autocorrelation of night sky lines, cosmic rays, edge effects) are diluted compared to the sought signal. The returned period is that of the maximum of the Gaussian-smoothed absolute value squared.
- Parameters:
data_array (
ndarray
) – _description_use_hann (
bool
) – Use a Hann window on each row in addition to subtracting the row mean (Default: False)fft_plot (
bool
) – Create a debugging plot of the FFT analysis? (Default: False)qa_dir (
Path
, optional) – The QA directory into which to place the optional plots. IfNone
, the plots will be placed in the current working directory. (Default: None)filename (
Path
) – The filename of the raw data frame for the optional plot. (Default: None)extra_graphics (
bool
, optional) – Produce extra graphics formats for documentation? (Default: False)
- Returns:
float
– The pixel period of the sinusoidal oscillation to be removed
- obstools.scrub_deveny_pickup.iterative_pypeit_clean(filename: Path, proc_dir: Path = None, overwrite_raw: bool = False, diagnostics: bool = False, no_refit: bool = False, extra_graphics: bool = False, rerun_fft: bool = False)[source]
Iteratively use PypeIt to clean pickup noise
As part of the data-reduction process, PypeIt fits and extracts images as well as the sky background. We can use the reduced
spec2d
files to get the “source-free” noise background, which makes identifying the sinusoidal noise more straightforward.- Parameters:
filename (
Path
) – The name of the file to cleanproc_dir (
Path
, optional) – The location of the PypeIt-processed images, if not./ldt_deveny_?/
(Default: None)overwrite_raw (
bool
, optional) – Overwrite the raw file rather than create a new file with the ‘_scrub’ suffix (Default: False)diagnostics (
bool
, optional) – Output additional information and plots during the image analysis? (Default: False)no_refit (
bool
, optional) – Do not refit lines with “bad” RMS (Default: False)extra_graphics (
bool
, optional) – Produce extra graphics formats for documentation? (Default: False)rereun_fft (
bool
, optional) – Pass the fitted pattern through the FFT analysis? (Default: False)
- obstools.scrub_deveny_pickup.make_image_comparison_plots(filename: Path, spec2d: Spec2DObj, resid: ndarray, pattern: ndarray, qa_dir: Path = None, with_obj: bool = False, extra_graphics: bool = False)[source]
Make a set of Image Comparison plots
This function creates a multipanel plot. The panels are:
The PypeIt-reduced 2-dimensional spectrum (
spec2d.sciimg
)The PypeIt sky spectrum model (
spec2d.skymodel
).The PypeIt-reduced residual image (
spec2d.sciimg
-spec2d.skymodel
-spec2d.objmodel
) modified by the good pixel maskThe noise pattern image generated here from the sinusoidal fits to each row of the residual image
The cleaned residual image (
resid
-pattern
)The cleaned 2-dimensional spectrum (
spec2d.sciimg
-pattern
)
- Parameters:
filename (
Path
) – Filename of theraw image from which all this comesspec2d (
Spec2DObj
) – The 2D spectral image class from PypeItresid (
ndarray
) – The PypeIt-produced residual image (the starting point for the fitting)pattern (
ndarray
) – The constructed pattern from the sinusoidal fits (mean = 0)qa_dir (
Path
, optional) – The QA directory into which to place the optional plots. IfNone
, the plots will be placed in the current working directory. (Default: None)with_obj (
bool
, optional) – Doesresid
contain the object model? (Default: False)extra_graphics (
bool
, optional) – Produce extra graphics formats for documentation? (Default: False)
- obstools.scrub_deveny_pickup.make_sine_label(popt: ndarray, infodict: dict, mesg: str, ier: int) str [source]
Make a sensible label for the sinusoid example plots
- Parameters:
popt (
ndarray
) – The array of fit coefficients fromscipy.optimize.curve_fit()
infodict (
dict
) – Dictionary containing fit information fromscipy.optimize.curve_fit()
mesg (
str
) – Message about completion fromscipy.optimize.curve_fit()
ier (
int
) – Integer describing fir completion fromscipy.optimize.curve_fit()
- Returns:
str
– The legend label thusly constructed
- obstools.scrub_deveny_pickup.make_sinusoid_fit_plots(filename: Path, fit_coeffs: Table, pixel_period: float, qa_dir: Path = None, extra_graphics: bool = False, fixed_fitc: Table = None, smoothing: dict = None)[source]
Create a set of diagnostic plots from the set of sinusoid fits
This function creates a multipanel plot saved as
sinusoid_fits.pdf
in the current working directory. The panels are:The row-by-row sinusoid amplitude
The row-by-row sinusoid period
The row-by-row sinusoid phase shift
The row-by-row rms residual when the sinusoidal fit is subtracted from the original line
- Parameters:
filename (
Path
) – The filename of the original file, used in the plot titlefit_coeffs (
Table
) – The fit coefficients tablepixel_period (
float
) – The estimated pixel period of the sinusoidal noise from the FFTqa_dir (
Path
, optional) – The QA directory into which to place the optional plots. IfNone
, the plots will be placed in the current working directory. (Default: None)extra_graphics (
bool
, optional) – Produce extra graphics formats for documentation? (Default: False)fixed_fitc (
Table
, optional) – The fit coefficients table with fixed sinusoid (Default: None)smoothing (
dict
, optional) – Polynomial fit coefficients for amplitude and period (Default: None)
- obstools.scrub_deveny_pickup.package_into_fits(filename: Path, ccd: CCDData, cleaned_array: ndarray, pattern_array: ndarray, fit_coeffs: dict, pixel_period: float, overwrite_raw: bool = False)[source]
Package the cleaned data into a FITS file
Package everything into a multiextension FITS file:
Primary HDU – contains the raw file’s FITS header
Cleaned Image HDU – raw - pattern
Original Image HDU – raw
Pattern Image HDU – pattern
Pattern about Raw Mean Image HDU – pattern + mean(raw)
Fit Coefficients BinTable HDU – fit_coeffs
The output filename is the same (including path) as the input raw file, but with “_scrub” appended before “.fits”.
- Parameters:
filename (
Path
) – The filename of the raw data frameccd (
CCDData
) – The raw data objectcleaned_array (
ndarray
) – The cleaned raw data array (raw data - pattern) in ADUpattern_array (
ndarray
) – The computed pattern array in ADUfit_coeffs (
dict
) – The fit coefficients dictionary fromfit_lines()
pixel_period (
float
) – The FFT-computed pixel period fromflatten_clean_fft()
overwrite_raw (
bool
, optional) – Overwrite the raw file rather than create a new file with the ‘_scrub’ suffix (Default: False)
- obstools.scrub_deveny_pickup.pixper_tofrom_hz(val: ndarray) ndarray [source]
Convert to/from pixel period and Hertz
_extended_summary_
- obstools.scrub_deveny_pickup.smooth_array(array: ndarray, kernel_size: int = 21, ftype: str = 'median') ndarray [source]
Smooth out an array with a given filter
This may be used for smoothing a line or attempting to smooth fit coefficients from row to row in order to ameliorate the effects of cosmic rays and strong sources.
Note
scipy.signal.medfilt()
uses zero-padding for the ends of the signal, therefore subtract the mean and re-add it to eliminate edge weirdness.