calibration

General description about the calibration pipeline scripts here.

Command line interface

Usage

To get calibrated detector polarization angle, 'gamma', pipeline below will be applied to an axismanger, which corresponds to the target wire grid operation. And the calibration script of the wire grid requires the HWP preprocess, that is, apply_hwp_angle_model and hwp.demod_tod.

'gamma' here is the same definition as in the coords module:

orientation of the detector, measured clockwise from North, i.e. 0 degrees is parall to the eta axis, and 90 degrees is parallel to the xi axis.

The main functions of the wire grid consists of 7 functions:
  • load_data

  • wrap_wg_hk

  • find_operation_range

  • calc_calibration_data_set

  • fit_with_circle

  • get_cal_gamma

One can get calibration results by calling these functions. tod in the scripts stands for an AxisManager. For example:

# Apply HWP angle model, IIR Filtering, and demodulation before this pipeline

# Load house-keeping data of the wire grid
wg_cfg = wg_config(**wiregrid_config)
raw_data_dict = load_data(wg_cfg, tod.timestamps[0],tod.timestamps[-1])
tod = wrap_wg_hk(tod, raw_data_dict, merge=True)

# Find the wire grid operation range in the tod and wrap the calibration data set
idxi, idxf = find_operation_range(
  tod, is_restrict=True, remove_trembling=True)

# Analyze the calibration data set and fit them with circles
calc_calibration_data_set(tod, idxi, idxf)
_ = fit_with_circle(tod)

# Get gamma and wrap it into the tod
get_cal_gamma(tod, merge=True, remove_cal_data=True)

Here, we load the wire grid data using the wiregrid_config. The example for SATp1 at NERSC is as follows:

hk_root: '/data/satp1/hk/'
db_file: '/hkdb-satp1.db'
site: False

aliases:
  enc_count: 'wg-encoder.wgencoder_full.reference_count'
  LSL1: 'wg-actuator.wgactuator.limitswitch_LSL1'
  LSL2: 'wg-actuator.wgactuator.limitswitch_LSL2'
  LSR1: 'wg-actuator.wgactuator.limitswitch_LSR1'
  LSR2: 'wg-actuator.wgactuator.limitswitch_LSR2'
  angleX: 'wg-tilt-sensor.wgtiltsensor.angleX'
  angleY: 'wg-tilt-sensor.wgtiltsensor.angleY'
  tempX: 'wg-tilt-sensor.wgtiltsensor.temperatureX'
  tempY: 'wg-tilt-sensor.wgtiltsensor.temperatureY'
  temp_rotator: 'wg-labjack.sensors_downsampled.AIN0C'
  temp_rotation_motor: 'wg-labjack.sensors_downsampled.AIN1C'
  temp_elec_plate: 'wg-labjack.sensors_downsampled.AIN2C'
# hardware specific constants
wg_count: 52000 # SATP1~SATP3, JSAT(SATP4?)
wg_offset: 12.13 # SAT1, MF1
telescope: 'satp1'

Finally, the AxisManager has the field of wg.gamma_cal that has:

  • 'gamma_raw': the calibrated angle at the j-th measurement step of the wire grid,

  • 'gamma_raw_err': the set of the standard deviation of the calibrated angle for each measurement step,

  • 'gamma': the calibrated angle by the wire grid,

  • 'gamma_err': the statistical error of the calibration,

  • 'wires_relative_power': radius of the circle used for the fitting (arbitrary unit),

  • 'background_pol_rad': direction of the background polarization in radian,

  • 'background_pol_relative_power': deviation to the origin of the background polarization,

  • 'theta_det_instr': polarization angle for the instrumental definition,

Background

Wire grid calibration is based on the model

\[\mathrm{d} = \mathrm{I}_{\mathrm{in}} + \left[A_{\mathrm{wire}}\ e^{2i\theta^{(j)}_\mathrm{wire}} + A_{\mathrm{background}}\ e^{2i\theta_\mathrm{bg}} +\mathcal{O}(\varepsilon) \left(\mathrm{CMB}\right)\right]\exp i\left[-4\theta_{\mathrm{HWP}} + 2\theta_{\mathrm{det}}\right] + c.c.\]

In this representation, \(\mathrm{d}\) is a raw time-ordered data which consists of the intensity term and the polrization term. The intensity of the input signal is represented as \(\mathrm{I}_\mathrm{in}\). The polarization terms includes wires power \(A_\mathrm{wire}\), static background \(A_\mathrm{background}\), and tiny amount of the CMB. \(\theta^{(j)}_\mathrm{wire}\) is the j-th direction of wires. \(\theta_\mathrm{bg}\) is the direction of the static background polarization. \(\theta_\mathrm{HWP}\) and \(\theta_\mathrm{det}\) are the fast axis direction of the HWP and the detector polarization angle, gamma. In this case, \(\theta_\mathrm{det} = \gamma\).

Demodulation of the HWP provides two independent polarization term:

\[\begin{split}\mathcal{F}_{\mathrm{LP}}\left[\mathcal{F}_{\mathrm{BP}}\left[\mathrm{d}\right] \times \exp(4i\theta_{\mathrm{HWP}})\right] & \simeq A_{\mathrm{background}}\ e^{2i\theta_{\mathrm{bg}}+2i\theta_\mathrm{det}} + A_{\mathrm{wire}}\ e^{2i\theta^{(j)}_{\mathrm{wire}}+2i\theta_\mathrm{det}} \\ & = (Q_\mathrm{offset} + iU_\mathrm{offset}) + (Q^{(j)}_\mathrm{wire} + iU^{(j)}_\mathrm{wire})\end{split}\]

We call the static background polarization the offset term. The calibrated polarization response directions, 'gamma' or \(\theta_\mathrm{det}\), can be obtained by removing the direction of wires from the input polarization

\[\begin{split}\Phi(j) & \equiv \arctan\frac{U^{(j)}_{\mathrm{wire}} - U_\mathrm{offset}}{Q^{(j)}_{\mathrm{wire}} - Q_\mathrm{offset}} = 2\theta_{\mathrm{det}}+2\theta^{(j)}_{\mathrm{wire}} \\ \theta^{(j)}_{\mathrm{det}} & = \frac{1}{2}\left[\Phi(j)-2\theta^{(j)}_{\mathrm{wire}}\right]\end{split}\]

This module provides the averaged \(\theta_{det}\) as the best estimation of gamma. Other return fields are listed as follows:

  • 'gamma_raw': \(\theta^{(j)}_\mathrm{det}\)

  • 'gamma_raw_err': \(\sigma (\theta^{(j)}_\mathrm{det})\)

  • 'gamma': \(\theta_\mathrm{det}\)

  • 'gamma_err': \(\sigma (\theta_\mathrm{det})\)

  • 'wires_relative_power': \(\arctan([(U^{(j)}_{\mathrm{wire}} - U_\mathrm{offset})/(Q^{(j)}_{\mathrm{wire}} - Q_\mathrm{offset})])\)

  • 'background_pol_rad': \(\arctan(U_\mathrm{offset} / Q_\mathrm{offset})\)

  • 'background_pol_relative_power': \(\sqrt{Q_\mathrm{offset}^2 + U_\mathrm{offset}^2}\)

  • 'theta_det_instr': \(0.5\pi - \theta_\mathrm{det}\)

class sotodlib.site_pipeline.calibration.wiregrid.wg_config(hk_root: str, db_file: str, site: bool, aliases: dict, wg_count: int, wg_offset: float, telescope: str, timestamp_margin: float = 1.0)[source]
hk_root: str
db_file: str
site: bool
aliases: dict
wg_count: int
wg_offset: float
telescope: str
timestamp_margin: float = 1.0
sotodlib.site_pipeline.calibration.wiregrid.load_data(config: wg_config, start_time: float, stop_time: float) dict[source]

Load wire grid house-keeping data based on the provided configuration in site-pipeline-configs. start_time and stop_time are used to load the data within the specified range.

Parameters:
  • config (wg_config) – configuration for loading the wire grid house-keeping data

  • start_time (float) – start time in unixtime

  • stop_time (float) – stop time in unixtime

Returns:

wg_data_dict – dictionary including the raw house-keeping data and corrected encoder angle about the wire grid operation.

Return type:

dict

Notes

We assume wg_cfg is a yaml file, which has the following structure.

  • hk_root. path to house-keeping data directory, e.g. '../data/satp1/hk/'

  • db_file. path to sqlite database file, e.g. './hkdb-satp1.db'

  • site: bool. If True, load housekeeping data from L2 hk data at site, if False load it from L3 hkdb.

  • aliases:
    • enc_count : 'wg-encoder.wgencoder_full.reference_count'

    • LSL1 : 'wg-actuator.wgactuator.limitswitch_LSL1'

    • LSL2 : 'wg-actuator.wgactuator.limitswitch_LSL2'

    • LSR1 : 'wg-actuator.wgactuator.limitswitch_LSR1'

    • LSR2 : 'wg-actuator.wgactuator.limitswitch_LSR2'

    • angleX : 'wg-tilt-sensor.wgtiltsensor.angleX'

    • angleY : 'wg-tilt-sensor.wgtiltsensor.angleY'

    • tempX : 'wg-tilt-sensor.wgtiltsensor.temperatureX'

    • tempY : 'wg-tilt-sensor.wgtiltsensor.temperatureY'

    • temp_rotator: 'wg-labjack.sensors_downsampled.AIN0C'

    • temp_rotation_motor: 'wg-labjack.sensors_downsampled.AIN1C'

    • temp_elec_plate: 'wg-labjack.sensors_downsampled.AIN2C'

  • wg_count: magnetic scale counts per one lap (52,000 for SATp1~SATp3)

  • wg_offset: correction for the encoder offset, in degrees

    (12.13 deg for SATp1, 9.473 deg for SATp2, 11.21 deg for SATp3)

  • telescope: telescope name in lowercase letters, e.g. ‘satp1’

  • timestamp_margin: Time buffer added before and after the time range of observation, in seconds. Defaults to 1. This margin compensates for imperfect timestamp synchronization between detectors’ data and housekeeping data.

sotodlib.site_pipeline.calibration.wiregrid.wrap_wg_hk(tod, raw_data_dict, merge=True)[source]

Wrap the house-keeping data about the wire grid operation.

Parameters:
  • tod (AxisManager)

  • raw_data_dict (dict) – dictionary including the raw house-keeping data about the wire grid operation.

  • merge (bool (default, True)) – whether merge the house-keeping data into tod or not

Returns:

tod

This includes fields, which are related with the wire grid hardware.

  • enc_count : wires’ direction read in raw encoder count (raw data from the encoder)

  • enc_rad : wires’ direction read by encoder in radian (corrected with encoder count and hardware offset)

  • LSL1 : ON/OFF status of the limit switch LEFT 1 (outside) of the actuator

  • LSL2 : ON/OFF status of the limit switch LEFT 2 (inside) of the actuator

  • LSR1 : ON/OFF status of the limit switch RIGHT 1 (outside) of the actuator

  • LSR2 : ON/OFF status of the limit switch RIGHT 2 (inside) of the actuator

  • angleX : tilt angle X of the tilt sensor in degree

  • angleY : tilt angle Y of the tilt sensor in degree

  • tempX : temperature sensor X of the tilt sensor in Celsius

  • tempY : temperature sensor Y of the tilt sensor in Celsius

  • temp_rotator: temperature sensor of the rotator in Celsius

  • temp_rotation_motor: temperature sensor of the rotation motor in Celsius

  • temp_elec_plate: temperature sensor of the electric plate in Celsius

Return type:

AxisManager

sotodlib.site_pipeline.calibration.wiregrid.find_operation_range(tod, steps_thresholds=(10, 300), ls_margin=2000, is_restrict=True, remove_trembling=True, tremble_threshold=1.0)[source]

Define the range of the wire grid operation by the limit switches

Parameters:
  • tod (AxisManager)

  • ls_margin (int (default, 2000 samples)) – the offsets to define the operation range of the wire grid calibration.

  • is_restrict (bool (default, True)) – whether restrict TODs by the opration range or not

  • remove_trembling (bool (default, True)) – whether remove the steps in the encoder data under the motor-motion threshold, tremble_threshold

  • tremble_threshold (float (default, 1 deg)) – the threshold to remove the slight vibration in the steps of the wire grid rotation

Returns:

idx_steps_start, idx_steps_stop

Return type:

sample index of the start/stop for each step

sotodlib.site_pipeline.calibration.wiregrid.calc_calibration_data_set(tod, idx_steps_start, idx_steps_stop)[source]

Interpret the Q_cal, U_cal data from the wrapped calibration data. This method is based on both of demodQ and demodU, which are calculated by the HWP demodulation process. Users have to apply some HWP process before calling this.

Parameters:
  • tod (AxisManager,) – the others are same as the _get_operation_range

  • idx_steps_start (np.ndarray) – sample index of the start of each step

  • idx_steps_stop (np.ndarray) – sample index of the stop of each step

Returns:

  • axes (AxisManger)

  • return includes fields as follows

    • wg.cal_data.theta_wire_rad is the average direction of wires in each step

    • wg.cal_data.theta_wire_std is the standard deviation of the direction of wires in each step

    • wg.cal_data.ts_step_mid is the time stamps in the middle of each step

    • wg.cal_data.Q, wg.cal_data.U : Q (and U) signal by wires

    • wg.cal_data.Qerr, wg.cal_data.Uerr : the standard deviations of Q (and U) signal

sotodlib.site_pipeline.calibration.wiregrid.fit_with_circle(tod)[source]

Get the results by the circle fitting about the responce against the wires in Q+iU plane

Parameters:

tod (AxisManager)

Returns:

fit_results – the result of the circle fitting of the wires’ signal in the Q/U plane.

Return type:

list

Notes

With this process, tod will include the several parameters of the fittings as tod.wg.cfit_result:

  • cx0(_err) : the estimated x-offset value(, and its fit err).

  • cy0(_err) : the estimated y-offset value(, and its fit err).

  • cr(_err) : Estimated radius vaule(, and its fit err).

  • covariance : covariance matrix of the estimated parameters.

  • residual_var : Residual variance.

  • is_success : the status of how fits end.

sotodlib.site_pipeline.calibration.wiregrid.fit_with_ellipse(tod)[source]

Get the results by the ellipse fitting about the responce against the wires in Q+iU plane

Parameters:

tod (AxisManager)

Returns:

efit_results – the result of the ellipse fitting of the wires’ signal in the Q/U plane.

Return type:

list

Notes

With this process, tod will include the several parameters of the fittings as tod.wg.cfit_result:

  • ex0(_err) : the estimated x-offset value(, and its fit err).

  • ey0(_err) : the estimated y-offset value(, and its fit err).

  • ea(_err) : Estimated major axis vaule(, and its fit err).

  • eb(_err) : Estimated minor axis vaule(, and its fit err).

  • etheta(_err) : Estimated rotation angle vaule(, and its fit err).

  • covariance : covariance matrix of the estimated parameters.

  • residual_var : Residual variance.

  • is_success : the status of how fits end.

sotodlib.site_pipeline.calibration.wiregrid.get_cal_gamma(tod, merge=True, remove_cal_data=False)[source]

Calibrate detector polarization angle with a circle model

Parameters:
  • tod (AxisManager)

  • merge (bool (default, True)) – whether merge the calibration results into tod or not

  • remove_cal_data (bool (default, False)) – whether remove the intermediate product for the wire grid calibration in tod or not

Returns:

ax – which includes the calibrated angle of gamma in the sky coordinate, etc.

Return type:

AxisManager

Notes

  • gamma_raw(_err) is the raw output of the calibration for each wire grid step.

  • wires_relative_power is the signal intensity of the wires, which will relatively change depending on the ambient temperature.

  • gamma(_err) is the main result of the calibration using Sparse Wire Grid.

  • background_pol_rad or background_pol_relative_power is the Q/U-plane offsets of the detectors signal respect to the wires’ reflection.

  • theta_det_instr is gamma translated to the instrumental angle printed on the silicon wafer.

sotodlib.site_pipeline.calibration.wiregrid.get_ecal_gamma(tod)[source]

Calibrate dtector polarization angle with an ellipse model. See also get_cal_gamma.

Parameters:

tod (AxisManager)

Returns:

ax – which includes the calibrated angle of gamma by ellipse model in the sky coordinate, etc.

Return type:

AxisManager