Detectors, channels, and instruments#

The core of the LiteBIRD instruments is the set of detectors that perform the measurement of the electromagnetic power entering through the telescope. Several simulation modules revolve around the concept of «detector», «frequency channel», and «instrument», and the LiteBIRD Simulation Framework implements a few classes and functions to handle the information associated with them.

Consider this example:

import litebird_sim as lbs

detectors = [
    lbs.DetectorInfo(
        name="Dummy detector #1",
        net_ukrts=100.0,
        bandcenter_ghz=123.4,
        bandwidth_ghz=5.6,
    ),
    lbs.DetectorInfo(
        name="Dummy detector #2",
        net_ukrts=110.0,
        fwhm_arcmin=65.8,
    ),
]

# Now simulate the behavior of the two detectors
# …

Here you see that the DetectorInfo class can be used to store information related to single detectors, and that you can choose which information provide for each detector: the example specifies bandshape information only for the first detector (Dummy detector #1), but not for the other. Missing information is usually initialized with zero or a sensible default. The simulation modules provided by the framework typically expect one or more DetectorInfo objects to be passed as input.

Detectors are grouped according to their nominal central frequency in frequency channels; there are several frequency channels in the three LiteBIRD instruments (LFT, MFT, HFT), and sometimes one does not need to simulate each detector within a frequency channel, but only the channel as a whole. In this case there is the FreqChannelInfo class, which can produce a mock DetectorInfo object by taking out the «average» information of the frequency channel:

import litebird_sim as lbs

chinfo = lbs.FreqChannelInfo(
    bandcenter_ghz=40.0,
    net_channel_ukrts=40.0, # Taken from Sugai et al. 2020 (JLTP)
    number_of_detectors=64, # 32 pairs
)

# Return a "mock" detector that is representative of the
# frequency channel
mock_det = chinfo.get_boresight_detector(name="mydet")

# Look, ma, a detector!
assert isinstance(mock_det, lbs.DetectorInfo)
assert mock_det.name == "mydet"

print("The NET of one detector at 40 GHz is {0:.1f} µK·√s"
      .format(mock_det.net_ukrts))
The NET of one detector at 40 GHz is 320.0 µK·√s

Finally, the Instrument class holds information about one of the three instruments onboard the LiteBIRD spacecraft (LFT, MFT, and HFT).

Reading from the IMO#

The way information about detectors and frequency channels is stored in the IMO (see The IMo) closely match the DetectorInfo and FreqChannelInfo classes. In fact, they can be retrieved easily from the IMO using the static methods DetectorInfo.from_imo() and FreqChannelInfo.from_imo().

The following example uses the PTEP IMO to show how to use the API:

import litebird_sim as lbs

# The location of the PTEP IMO is stored in the constant
# PTEP_IMO_LOCATION
imo = lbs.Imo(flatfile_location=lbs.PTEP_IMO_LOCATION)

det = lbs.DetectorInfo.from_imo(
    imo=imo,
    url="/releases/vPTEP/satellite/LFT/L1-040/"
        "000_000_003_QA_040_T/detector_info",
)

print(f"The bandcenter for {det.name} is {det.bandcenter_ghz} GHz")

freqch = lbs.FreqChannelInfo.from_imo(
    imo=imo,
    url="/releases/vPTEP/satellite/LFT/L1-040/channel_info",
)

print(
    f"The average bandcenter for {freqch.channel} "
    f"is {freqch.bandcenter_ghz} GHz"
)
The bandcenter for 000_000_003_QA_040_T is 40.0 GHz
The average bandcenter for L1-040 is 40.0 GHz

Detectors in parameter files#

It is often the case that the list of detectors to simulate must be read from a parameter file. There are several situations that typically need to be accomodated:

  1. In some simulations, you just need to simulate one detector (whose parameters can be taken either from the IMO or from the parameter file itself);

  2. In other cases, you want to simulate all the detectors in one or more frequency channels: in this case, you would like to avoid specifying them one by one!

  3. In other cases, you might want to specify just a subset

  4. Finally, you might base your simulation on the IMO definition of a detector/channel but twiddle a bit with some parameters.

The LiteBIRD simulation framework provides a way to read a set of detectors/channels from a dictionary, which can be used to build a list of DetectorInfo/FreqChannelInfo objects.

In the following examples, we will refer to a «mock» IMO, which contains information about a few fake detectors. It’s included in the source distribution of the framework, under the directory litebird_sim/test/mock_imo, and it defines one frequency channel with four detectors. Here is a summary of its contents:

from pathlib import Path
import litebird_sim as lbs

# This ensures that the mock IMO can be found when generating this
# HTML page
imo = lbs.Imo(flatfile_location=lbs.PTEP_IMO_LOCATION)

# This UUID refers to a 140 GHz "channel_info" object.
ch = imo.query("/data_files/463e9ea9-c1f0-484d-9bfd-05092851d8f4")
metadata = ch.metadata

print("Here are the contents of the mock IMO:")
print(f'Channel: {metadata["channel"]}')

detector_names = metadata["detector_names"]
print(f'There are {len(detector_names)} detectors')
print("Here are the first 5 of them:")
for name, obj in list(zip(metadata["detector_names"],
                          metadata["detector_objs"]))[0:5]:
    det_obj = imo.query(obj)
    det_metadata = det_obj.metadata
    bandcenter_ghz = det_metadata["bandcenter_ghz"]
    print(f'  {name}: band center at {bandcenter_ghz:.1f} GHz')
Here are the contents of the mock IMO:
Channel: M1-140
There are 366 detectors
Here are the first 5 of them:
  001_002_030_00A_140_T: band center at 140.0 GHz
  001_002_030_00A_140_B: band center at 140.0 GHz
  001_002_031_15B_140_T: band center at 140.0 GHz
  001_002_031_00B_140_B: band center at 140.0 GHz
  001_002_022_15A_140_T: band center at 140.0 GHz

Now, let’s turn back to the problem of specifying a set of detectors in a parameter file. The following TOML file shows some of the possibilities granted by the framework. The parameter random_seed is mandatory for the Simulation constructor.

# This is file "det_list1.toml"

# Mandatory parameter
[simulation]
random_seed = 12345

# In this example we list the detectors to use in the simulation
# using one of TOML's features: lists of elements. They are
# indicated using double square brackets, and each occurrence
# appends a new item to the end of the list.

# First element
[[detectors]]
# Take the parameters for the detector from the IMO;
# here we specify the UUID of the object
detector_info_obj = "/data_files/34b46c91-e196-49b9-9d44-d69b4827f751"

# Append two more elements
[[detectors]]
# Take the parameters for the set of detectors from the channel
# information in the IMO. As above, we use an UUID
channel_info_obj = "/data_files/463e9ea9-c1f0-484d-9bfd-05092851d8f4"
# Just generate two detectors (default is to generate all the
# detectors in this frequency channel, which contains *four*
# detectors). This is useful when debugging, because it can
# drastically reduce the amount of data to simulate
num_of_detectors_from_channel = 2

# Append one more element
[[detectors]]
# Unlike in the previous example, here we just want to generate *one*
# mock detector associated with a specified frequency channel. This
# detector will be aligned with the boresight of the focal plane, and
# it will use the «average» detector parameters for this channel
channel_info_obj = "/data_files/463e9ea9-c1f0-484d-9bfd-05092851d8f4"
# This implies num_of_detectors_from_channel == 1
use_only_one_boresight_detector = true
detector_name = "foo_boresight"

# Append one more element
[[detectors]]
# Set up every parameter manually
name = "planck30GHz"
channel = "30 GHz"
fwhm_arcmin = 33.10
fknee_mhz = 113.9
bandwidth_ghz = 9.89
bandcenter_ghz = 28.4
sampling_rate_hz = 32.5

# Add one last element
[[detectors]]
# Take the parameters from the IMO but fix one parameter by hand
detector_info_obj = "/data_files/34b46c91-e196-49b9-9d44-d69b4827f751"
sampling_rate_hz = 1.0   # Fix this parameter

If the TOML file you are using in your simulation follows this structure, you can use the function detector_list_from_parameters(), which parses the parameters and uses an Imo object to build a list of DetectorInfo objects.

The following code will read the TOML file above and produce a list of 6 detectors:

from pathlib import Path
import litebird_sim as lbs

imo = lbs.Imo(flatfile_location=lbs.PTEP_IMO_LOCATION)

# Tell Simulation to use the PTEP IMO and to
# load the TOML file shown above
sim = lbs.Simulation(imo=imo, parameter_file="det_list1.toml")

det_list = lbs.detector_list_from_parameters(
    imo=sim.imo,
    definition_list=sim.parameters["detectors"],
)

for idx, det in enumerate(det_list):
    print(f"{idx + 1}. {det.name}: band center at {det.bandcenter_ghz} GHz")
1. 000_000_003_QA_040_T: band center at 40.0 GHz
2. 001_002_030_00A_140_T: band center at 140.0 GHz
3. 001_002_030_00A_140_B: band center at 140.0 GHz
4. foo_boresight: band center at 140.0 GHz
5. planck30GHz: band center at 28.4 GHz
6. 000_000_003_QA_040_T: band center at 40.0 GHz

You are not forced to use detectors as the name of the parameter in the TOML file, as detector_list_from_parameters() accepts a generic list. As an example, consider the following TOML file. Note again the mandatory parameter random_seed.

# This is file "det_list2.toml"

# Mandatory parameter
[simulation]
random_seed = 12345

[simulation1]

# Detectors to be used for the first simulation
[[simulation1.detectors]]
detector_info_obj = "/data_files/899ba8cc-789c-47bf-9bb1-40f61b25b3a9"

[simulation2]

# Detectors to be used for the second simulation
[[simulation2.detectors]]
detector_info_obj = "/data_files/e4401060-9233-4b14-a642-c00293c99c70"

Its purpose is to provide the parameters for a two-staged simulation, and each of them requires its own list of detectors. For this purpose, it uses the TOML syntax [[simulation1.detectors]] to specify that the detectors list belongs to the section simulation1, and similarly for [[simulation2.detectors]]. Here is a Python script that interprets the TOML file and prints the detectors to be used at each stage of the simulation:

from pathlib import Path
import litebird_sim as lbs

imo = lbs.Imo(flatfile_location=lbs.PTEP_IMO_LOCATION)

# Tell the Simulation object that we want to use the PTEP IMO
sim = lbs.Simulation(imo=imo, parameter_file="det_list2.toml")

det_list1 = lbs.detector_list_from_parameters(
    imo=sim.imo,
    definition_list=sim.parameters["simulation1"]["detectors"],
)

det_list2 = lbs.detector_list_from_parameters(
    imo=sim.imo,
    definition_list=sim.parameters["simulation2"]["detectors"],
)

print("Detectors to be used in the first simulation:")
for det in det_list1:
    print(f"- {det.name}")

print("Detectors to be used in the second simulation:")
for det in det_list2:
    print(f"- {det.name}")
Detectors to be used in the first simulation:
- 000_000_004_QB_040_B
Detectors to be used in the second simulation:
- 000_000_004_QB_040_T

Bandpasses#

Any electromagnetic detector is sensitive only to some frequencies of the spectrum, and it is vital to know what they are. We refer to these as the «bandpass», i.e., the list of frequencies that can «pass through the detector» and be detected. A bandpass is a function \(B(\nu)\) that associates the frequency \(\nu\) with a pure number in the range 0…1, representing the fraction of power that is actually measured by the instrument. The functional form of \(B(\nu)\) is usually called the bandshape, and it is usually nonzero in a limited subset of the real space.

A widely used analytical model of the bandshape is the top-hat bandpass:

(1)#\[\begin{split}B(\nu) = \begin{cases} 1\,\text{ if } \nu_0 - \Delta\nu/2 < \nu < \nu_0 + \Delta\nu/2,\\ 0\,\text{ otherwise.} \end{cases}\end{split}\]

Given a bandshape \(B(\nu)\), two quantities are usually employed to synthetically represent it:

  • The central frequency \(\left<\nu\right>\), which is just the average value of \(\nu\) when weighted with \(B(\nu)\):

    \[\left<\nu\right> = \frac{\int_0^\infty \nu B(\nu)\,\mathrm{d}\nu}{\int_0^\infty B(\nu)\,\mathrm{d}\nu}\]

    which is of course the formula of the weighted average. For the top-hat band, the central frequency is \(\nu_0\).

  • The bandwidth \(\Delta\nu\), which is the width of the band, i.e., a measurement of how wide is the subrange of the electromagnetic spectrum sampled by the detector:

    \[\Delta\nu^2 = \frac{\left(\int_0^\infty B(\nu)\,\mathrm{d}\nu\right)^2}{\int_0^\infty B^2(\nu)\,\mathrm{d}\nu},\]

    which is again inspired by the formula of the standard square deviation. For the top-hat bandshape, the value of \(\Delta\nu\) in (1) is exactly the bandwidth.

Modeling bandshapes#

In the LiteBIRD Simulation Framework, bandpasses are encoded in the class BandPassInfo, which can be used either to load bandpasses from the IMO or to generate them on scratch. In the latter case, you must specify the central frequency and the bandwidth, alongside with other parameter that introduce a random component meant to make the band more realistic. Here is a simple example, which shows how to create a bandpass and then how to add «noise» to make it more realistic:

import litebird_sim as lbs
import matplotlib.pylab as plt

# Generate the «model» (i.e., ideal band, with no wiggles)
band = lbs.BandPassInfo(
    bandcenter_ghz=43.0,
    bandwidth_ghz=10.0,
    bandtype="top-hat-cosine",
    normalize=True,
    nsamples_inband=100,
)
plt.plot(band.freqs_ghz, band.weights, label="Ideal band")

# Now generate a more realistic band with random wiggles
new_weights = band.bandpass_resampling()
plt.plot(
    band.freqs_ghz,
    new_weights,
    label="Random realization",
)

plt.xlabel("Frequency [GHz]")
plt.ylabel("Weight")
plt.legend()

(Source code, png, hires.png, pdf)

_images/bandpass_demo.png

API reference#

class litebird_sim.detectors.DetectorInfo(name: str = '', wafer: str | None = None, pixel: int | None = None, pixtype: str | None = None, channel: str | None = None, squid: int | None = None, sampling_rate_hz: float = 0.0, fwhm_arcmin: float = 0.0, ellipticity: float = 1.0, psi_rad: float = 0.0, bandcenter_ghz: float = 0.0, bandwidth_ghz: float = 0.0, band_freqs_ghz: None | ndarray = None, band_weights: None | ndarray = None, net_ukrts: float = 0.0, pol_sensitivity_ukarcmin: float = 0.0, fknee_mhz: float = 0.0, fmin_hz: float = 0.0, alpha: float = 0.0, pol: str | None = None, orient: str | None = None, quat: Any = None, pol_angle_rad: float = 0.0, pol_efficiency: float = 1.0, mueller_hwp: None | ndarray | dict[str, ndarray] = None, jones_hwp: None | ndarray | dict[str, ndarray] = None, pointing_theta_phi_psi_deg: None | ndarray = None, pointing_u_v: None | ndarray = None, g_one_over_k: float = 0.0, amplitude_2f_k: float = 0.0, band: BandPassInfo | None = None)#

Bases: object

A class encapsulating the basic information about a LiteBIRD detector.

This data class stores the key properties of a detector, including its geometry, spectral and noise characteristics, polarization, pointing, and optional systematic effects.

Initialization Methods:

The class can be instantiated in one of the following ways:

  1. Using the default constructor (recommended to specify at least name and sampling_rate_hz):

    det = DetectorInfo(name="dummy", sampling_rate_hz=10.0)
    
  2. Using the class method from_dict(), which builds a detector from a dictionary of fields.

  3. Using the class method from_imo(), which extracts detector metadata from the LiteBIRD Instrument Model (see Imo).

Post-initialization Behavior:
  • If the quaternion (quat) is not provided, it defaults to the identity quaternion (no rotation).

  • The quaternion is automatically normalized using normalize_time_dependent_quaternion.

  • If band_freqs_ghz is provided as a NumPy array, band_weights must have the same length.

  • If band_freqs_ghz is not provided, a simple rectangular bandpass is constructed from bandcenter_ghz and bandwidth_ghz using BandPassInfo.

Dictionary Format:

When using from_dict(), the input dictionary may contain the following keys:

name, wafer, pixel, pixtype, channel, squid, bandcenter_ghz, bandwidth_ghz, band_freqs_ghz, band_weights, sampling_rate_hz, fwhm_arcmin, ellipticity, psi_rad, net_ukrts, pol_sensitivity_ukarcmin, fknee_mhz, fmin_hz, alpha, pol, orient, quat, pol_angle_rad, pol_efficiency, mueller_hwp, mueller_hwp_solver, pointing_theta_phi_psi_deg, pointing_u_v, g_one_over_k, amplitude_2f_k

Quaternions can be specified as: - A list of 4 numbers (static rotation), or - A dictionary with keys like start_time, quats, sampling_rate_hz, etc., for time-varying rotation.

Parameters:
  • name (str) – The name of the detector. Default is an empty string.

  • wafer (str | None) – The name of the wafer hosting the detector (e.g., "H00", "L07", etc.). Default is None.

  • pixel (int | None) – The index of the pixel within the wafer. Default is None.

  • pixtype (str | None) – The type of the pixel (e.g., "HP1", "LP3"). Default is None.

  • channel (str | None) – The channel name. Default is None.

  • squid (int | None) – The SQUID number associated with the detector. Default is None.

  • sampling_rate_hz (float) – Sampling rate of the ADC associated with this detector, in Hz. Default is 0.0.

  • fwhm_arcmin (float) – Full Width at Half Maximum of the beam in arcminutes. Defined as fwhm = sqrt(fwhm_max*fwhm_min). Default is 0.0.

  • ellipticity (float) – Ellipticity of the beam (major/minor axis ratio). Defined as fwhm_max/fwhm_min Default is 1 (circular beam). Default is 1.0.

  • psi_rad (float) – Orientation angle of the beam’s major axis with respect to the x-axis, in radians. Default is 0.0.

  • net_ukrts (float) – Noise Equivalent Temperature (NET) in μK√s, representing per-sample noise. Used when adding noise to timelines. Default is 0.0.

  • pol_sensitivity_ukarcmin (float) – Detector polarization sensitivity in μK·arcmin. Includes effects such as cosmic ray hits and repointing losses. Should not be used for timeline noise simulation. Default is 0.0.

  • bandcenter_ghz (float) – Center frequency of the detector band, in GHz. Default is 0.0.

  • bandwidth_ghz (float) – Bandwidth of the detector, in GHz. Default is 0.0.

  • band_freqs_ghz (np.ndarray | None) – Array of sampled frequencies in the band (GHz). Default is None.

  • band_weights (np.ndarray | None) – Corresponding normalized band weights. Default is None.

  • fknee_mhz (float) – 1/f noise knee frequency in mHz. Default is 0.0.

  • fmin_hz (float) – Minimum noise frequency used in synthetic noise generation, in Hz. Default is 0.0.

  • alpha (float) – Slope of the 1/f noise power spectrum. Default is 0.0.

  • pol (str | None) – Polarization type ("T", "B", etc.). Default is None.

  • orient (str | None) – Polarization orientation ("Q", "U", etc.). Default is None.

  • quat (TimeDependentQuaternion) – Quaternion representing the rotation from the detector frame to the boresight frame. Default is identity (no rotation).

  • pol_angle_rad (float) – Polarization angle relative to the detector frame x-axis, in radians. Default is 0.0.

  • pol_efficiency (float) – Polarization efficiency (γ), as defined in Eq. 15 of astro-ph/0606606. Default is 1.0.

  • mueller_hwp (None | np.ndarray | dict) – Mueller matrix of the HWP: None if no hwp, np.ndarray if a single matrix, dict if multiple matrices, in the case of rotation harmonics expansion. Default is None (no HWP).

  • jones_hwp (None | np.ndarray | dict) – Jones matrix of the HWP: None if no hwp, np.ndarray if a single matrix, dict if multiple matrices, in the case of rotation harmonics expansion. Default is None (no HWP).

  • pointing_theta_phi_psi_deg (None | np.ndarray) – Array of pointing angles (θ, φ, ψ) in degrees: colatitude, longitude, and orientation. Default is None.

  • pointing_u_v (None | np.ndarray) – Detector pointing in focal plane coordinates (u, v), with (0, 0) representing the central axis of the focal plane. Default is None.

  • g_one_over_k (float) – Gain conversion factor (1/K), used in calibration models. Default is 0.0.

  • amplitude_2f_k (float) – Amplitude of the 2f systematic signal component in Kelvin. Default is 0.0.

alpha: float = 0.0#
amplitude_2f_k: float = 0.0#
band: BandPassInfo | None = None#
band_freqs_ghz: None | ndarray = None#
band_weights: None | ndarray = None#
bandcenter_ghz: float = 0.0#
bandwidth_ghz: float = 0.0#
channel: str | None = None#
ellipticity: float = 1.0#
fknee_mhz: float = 0.0#
fmin_hz: float = 0.0#
static from_dict(dictionary: dict[str, Any])#

Create a detector from the contents of a dictionary

The parameter dictionary must contain one key for each of the fields in this dataclass:

  • name

  • wafer

  • pixel

  • pixtype

  • channel

  • squid

  • bandcenter_ghz

  • bandwidth_ghz

  • band_freqs_ghz

  • band_weights

  • sampling_rate_hz

  • fwhm_arcmin

  • ellipticity

  • psi_rad

  • net_ukrts

  • pol_sensitivity_ukarcmin

  • fknee_mhz

  • fmin_hz

  • alpha

  • pol

  • orient

  • quat

  • pol_angle_rad

  • pol_efficiency

  • mueller_hwp

  • mueller_hwp_solver

  • pointing_theta_phi_psi_deg

  • pointing_u_v

  • g_one_over_k

  • amplitude_2f_k

static from_imo(imo: Imo, url: UUID | str)#

Create a DetectorInfo object from a definition in the IMO

The url must either specify a UUID or a full URL to the object.

Example:

import litebird_sim as lbs
imo = Imo()
det = DetectorInfo.from_imo(
    imo=imo,
    url="/releases/v1.0/satellite/LFT/L1-040/L00_008_QA_040T/detector_info",
)
fwhm_arcmin: float = 0.0#
g_one_over_k: float = 0.0#
jones_hwp: None | ndarray | dict[str, ndarray] = None#
mueller_hwp: None | ndarray | dict[str, ndarray] = None#
name: str = ''#
net_ukrts: float = 0.0#
orient: str | None = None#
pixel: int | None = None#
pixtype: str | None = None#
pointing_theta_phi_psi_deg: None | ndarray = None#
pointing_u_v: None | ndarray = None#
pol: str | None = None#
pol_angle_rad: float = 0.0#
pol_efficiency: float = 1.0#
pol_sensitivity_ukarcmin: float = 0.0#
psi_rad: float = 0.0#
quat: Any = None#
sampling_rate_hz: float = 0.0#
squid: int | None = None#
wafer: str | None = None#
class litebird_sim.detectors.FreqChannelInfo(bandcenter_ghz: float, channel: str | None = None, bandwidth_ghz: float = 0.0, band_freqs_ghz: None | numpy.ndarray = None, band_weights: None | numpy.ndarray = None, net_detector_ukrts: float = 0.0, net_channel_ukrts: float = 0.0, pol_sensitivity_channel_ukarcmin: float = 0.0, sampling_rate_hz: float = 0.0, fwhm_arcmin: float = 0.0, ellipticity: float = 1.0, psi_rad: float = 0.0, fknee_mhz: float = 0.0, fmin_hz: float = 1e-05, alpha: float = 1.0, number_of_detectors: int = 0, detector_names: list[str] = <factory>, detector_objs: list[uuid.UUID] = <factory>, band: litebird_sim.bandpasses.BandPassInfo | None = None)#

Bases: object

alpha: float = 1.0#
band: BandPassInfo | None = None#

A data class representing the configuration of a frequency channel in LiteBIRD.

This class encapsulates the spectral, noise, and beam properties of a frequency channel, along with metadata about the associated detectors.

Initialization Methods:
  • Direct instantiation (requires at least bandcenter_ghz)

  • from_dict(): load from a dictionary

  • from_imo(): load from a LiteBIRD Instrument Model (IMO)

Post-initialization Behavior:
  • If channel is not specified, it defaults to “<bandcenter_ghz> GHz”.

  • If number_of_detectors is provided:
    • Validates or generates detector_names and detector_objs.

  • If number_of_detectors is not provided:
    • It is inferred from detector_names or detector_objs, defaulting to 1 detector named “det0”.

  • If either net_channel_ukrts or net_detector_ukrts is zero, it is computed from the other.

  • All entries in detector_objs are converted to UUIDs.

  • If band_freqs_ghz is not provided, a default rectangular bandpass is generated from bandcenter_ghz and bandwidth_ghz.

- from_dict(dict)

Create an instance from a plain dictionary.

- from_imo(imo, url)

Load metadata from an IMO object using a UUID or URL.

- get_boresight_detector(name)

Return a simplified DetectorInfo object with boresight-aligned geometry and inherited channel parameters.

Parameters:
  • bandcenter_ghz (float) – Center frequency of the channel in GHz.

  • channel (str or None) – Channel name. Defaults to “<bandcenter_ghz> GHz”.

  • bandwidth_ghz (float) – Bandwidth of the channel in GHz. Default is 0.0.

  • band_freqs_ghz (np.ndarray or None) – Sampled frequencies across the band in GHz. If not provided, a rectangular bandpass is constructed. Default is None.

  • band_weights (np.ndarray or None) – Normalized bandpass weights. Default is None.

  • net_detector_ukrts (float) – Noise Equivalent Temperature (NET) per detector in μK√s. Default is 0.0.

  • net_channel_ukrts (float) – Total NET for the channel in μK√s, accounting for all detectors. Default is 0.0.

  • pol_sensitivity_channel_ukarcmin (float) – Polarization sensitivity of the channel in μK·arcmin. Default is 0.0.

  • sampling_rate_hz (float) – ADC sampling rate in Hz. Default is 0.0.

  • fwhm_arcmin (float) – Averaged beam Full Width at Half Maximum in arcminutes. Default is 0.0.

  • ellipticity (float) – Averaged beam ellipticity (major/minor axis ratio). Default is 1.0.

  • psi_rad (float) – Averaged beam orientation angle (major axis vs x-axis) in radians. Default is 0.0.

  • fknee_mhz (float) – Knee frequency of 1/f noise in mHz. Default is 0.0.

  • fmin_hz (float) – Minimum frequency for synthetic noise generation in Hz. Default is 1e-5.

  • alpha (float) – Slope of the 1/f noise component. Default is 1.0.

  • number_of_detectors (int) – Number of detectors in the channel. If 0, inferred from detector_names or detector_objs. Default is 0.

  • detector_names (list[str]) – List of detector names. If not provided, generated automatically. Default is an empty list.

  • detector_objs (list[UUID]) – List of UUIDs (or strings convertible to UUIDs) identifying detector entries in the IMO. Default is an empty list.

band_freqs_ghz: None | ndarray = None#
band_weights: None | ndarray = None#
bandcenter_ghz: float#
bandwidth_ghz: float = 0.0#
channel: str | None = None#
detector_names: list[str]#
detector_objs: list[UUID]#
ellipticity: float = 1.0#
fknee_mhz: float = 0.0#
fmin_hz: float = 1e-05#
static from_dict(dictionary: dict[str, Any])#
static from_imo(imo: Imo, url: UUID | str)#
fwhm_arcmin: float = 0.0#
get_boresight_detector(name='mock') DetectorInfo#
net_channel_ukrts: float = 0.0#
net_detector_ukrts: float = 0.0#
number_of_detectors: int = 0#
pol_sensitivity_channel_ukarcmin: float = 0.0#
psi_rad: float = 0.0#
sampling_rate_hz: float = 0.0#
class litebird_sim.detectors.InstrumentInfo(name: str = '', boresight_rotangle_rad: float = 0.0, spin_boresight_angle_rad: float = 0.0, spin_rotangle_rad: float = 0.0, hwp_rpm: float = 0.0, number_of_channels: int = 0, channel_names: list[str] = <factory>, channel_objs: list[uuid.UUID] = <factory>, wafer_names: list[str] = <factory>, wafer_space_cm: float = 0.0)#

Bases: object

bore2spin_quat = array([0., 0., 0., 1.])#
boresight_rotangle_rad: float = 0.0#
channel_names: list[str]#
channel_objs: list[UUID]#
static from_dict(dictionary: dict[str, Any])#
static from_imo(imo: Imo, url: UUID | str)#
hwp_rpm: float = 0.0#
name: str = ''#
number_of_channels: int = 0#
spin_boresight_angle_rad: float = 0.0#
spin_rotangle_rad: float = 0.0#
wafer_names: list[str]#
wafer_space_cm: float = 0.0#

A data class representing a LiteBIRD instrument configuration.

This class stores metadata about the overall instrument, including boresight orientation, spin geometry, channel and wafer associations, and HWP rotation parameters.

Initialization Methods:
  • Direct instantiation (with keyword arguments)

  • from_dict(): construct from a dictionary (e.g., loaded from YAML/JSON)

  • from_imo(): construct from an IMO object and URL/UUID

Post-initialization Behavior:
  • The quaternion from boresight to spin frame (bore2spin_quat) is computed from three rotation angles using __compute_bore2spin_quat__, and then normalized with normalize_time_dependent_quaternion.

  • Any entries in channel_objs that are strings or URLs are converted to UUIDs.

Quaternion Construction:

The rotation from boresight to spin frame is computed as: 1. A rotation around the Z-axis by boresight_rotangle_rad 2. A rotation around the Y-axis by spin_boresight_angle_rad 3. A rotation around the Z-axis by spin_rotangle_rad

Parameters:
  • name (str) – Name of the instrument. Default is an empty string.

  • boresight_rotangle_rad (float) – Initial rotation around the boresight Z-axis, in radians. Default is 0.0.

  • spin_boresight_angle_rad (float) – Angle between the boresight and spin axis, in radians. Default is 0.0.

  • spin_rotangle_rad (float) – Initial spin phase angle around the spin axis, in radians. Default is 0.0.

  • bore2spin_quat (np.ndarray) – Quaternion representing the full rotation from the boresight frame to the spin frame. Automatically computed and normalized in __post_init__.

  • hwp_rpm (float) – Rotation speed of the Half-Wave Plate, in revolutions per minute. Default is 0.0.

  • number_of_channels (int) – Number of frequency channels in the instrument. Default is 0.

  • channel_names (list[str]) – List of frequency channel names. Default is an empty list.

  • channel_objs (list[UUID]) – List of references to channel definitions (UUIDs or convertible strings). Automatically converted to UUIDs. Default is an empty list.

  • wafer_names (list[str]) – List of wafer names used in the instrument. Default is an empty list.

  • wafer_space_cm (float) – Spacing between wafers, in centimeters. Default is 0.0.

from_dict(dictionary)#

Construct an InstrumentInfo object from a configuration dictionary.

from_imo(imo, url)#

Query the IMO using a UUID or URL and construct an InstrumentInfo from the result.

litebird_sim.detectors.detector_list_from_parameters(imo: Imo, definition_list: list[Any]) list[DetectorInfo]#
litebird_sim.detectors.normalize_time_dependent_quaternion(quat: ndarray | RotQuaternion) RotQuaternion#

Make sure that a quaternion is represented as a TimeDependentQuaternion object

litebird_sim.detectors.url_to_uuid(url: str) UUID#
class litebird_sim.bandpasses.BandPassInfo(bandcenter_ghz: float = 0.0, bandwidth_ghz: float = 0.0, bandlow_ghz: float | None = None, bandhigh_ghz: float | None = None, nsamples_inband: int = 128, name: str = '', bandtype: str = 'top-hat', normalize: bool = False, model: str | None = None, alpha_exp: float = 1, beta_exp: float = 1, cosine_apo_length: float = 5, cheby_poly_order: int = 3, cheby_ripple_dB: int | float = 3)#

Bases: object

A class wrapping the basic information about a detector bandpass.

This class encodes the basic properties of a frequency band.

It can be initialized in three ways:

  • The default constructor will generate top-hat bandpasses, assuming that band centroid and width are provided.

  • Through the class method from_imo(), which reads the detector bandpass from the LiteBIRD Instrument Model (see the Imo class).

Parameters:
  • bandcenter_ghz (-) – center frequency in GHz

  • bandwidth_ghz (-) – width of the band (default=0.)

  • bandlow_ghz (-) – lowest frequency to sample the band, i.e. the first element of the frequency array considered (default: bandcenter_ghz - bandwidth_ghz)

  • bandhigh_ghz (-) – highest frequency to sample the band, i.e. the last element of frequency array considered (default: bandcenter_ghz + bandwidth_ghz)

  • nsamples_inband (-) – number of elements to sample the band (default=128)

  • name (-) – ID of the band

  • normalize (-) – If set to true bandpass weights will be normalized to 1

  • bandtype (-) –

    a string describing the band profile. It can be one of the following:

    • top-hat (default)

    • top-hat-exp: the edges of the band are apodized with an exponential profile

    • top-hat-cosine: the edges of the band are apodized with a cosine profile

    • cheby: the bandpass encodes a Chebyshev profile

  • alpha_exp (-) – out-of-band exponential decay index for low freq edge.

  • beta_exp (-) – out-of-band exponential decay index for high freq edge

  • cosine_apo_length (-) – the numerical factor related to the cosine apodization length

  • cheby_poly_order (-) – chebyshev filter order.

  • cheby_ripple_dB (-) – maximum ripple amplitude in decibels.

alpha_exp: float = 1#
bandcenter_ghz: float = 0.0#
bandhigh_ghz: float | None = None#
bandlow_ghz: float | None = None#
bandpass_resampling(bstrap_size=1000, nresample=54, model=None)#

Resample a bandpass with bootstrap resampling.

Note that the user can provide any sampler built with the interpolate_band method; otherwise, an error will be raised!

This function should be used when the user wants to generate many realizations of bandpasses, e.g. per detector bands. There is no need to initialize many instances of the class BandPassInfo, just rerun this functions multiple times issuing the same bandpass model instance.

Args :

  • bstrap_size (int): encodes the size of the random dataset

    to be generated from the Sampler

  • nresample (int): define how fine is the grid for the

    resampled bandpass

  • model (BandPassInfo.model): We can resample from a model previously

    constructed with this function. The default value is set to None: in this case, it initializes the bandpass sampler with the model set in the class instance (recommended use).

bandtype: str = 'top-hat'#
bandwidth_ghz: float = 0.0#
beta_exp: float = 1#
cheby_poly_order: int = 3#
cheby_ripple_dB: int | float = 3#
cosine_apo_length: float = 5#
find_central_frequency()#

Find the effective central frequency of a bandpass profile as defined in https://arxiv.org/abs/1303.5070

classmethod from_dict(d: dict) BandPassInfo#

Create a BandPassInfo object from a dictionary.

static from_imo(imo: Imo, url: UUID | str)#

Create a BandPassInfo object from a definition in the IMO The url must either specify a UUID or a full URL to the object.

get_edges()#

get the edges of the tophat band

get_normalization()#

Estimate the integral over the frequency band

model: str | None = None#
name: str = ''#
normalize: bool = False#
normalize_band()#

Normalize the band transmission coefficients

nsamples_inband: int = 128#