Opto-electronics#

The FlowCyPy.opto_electronics package defines the optical and electronic acquisition chain of the simulation.

It describes how particles are illuminated, how scattered light is collected by detectors, how the resulting photocurrent is amplified and filtered, and how analog signals are digitized before digital signal processing.

Together, these components determine the temporal shape, amplitude, bandwidth, and noise properties of the recorded detector traces.

The typical workflow is:

  1. define a light source

  2. configure one or more detectors

  3. specify the analog front-end, including amplification and optional filtering

  4. define the digitizer settings

  5. combine everything into an FlowCyPy.opto_electronics.OptoElectronics object

This configuration is then passed to the cytometer to simulate the acquisition chain from optical excitation to sampled digital signals.

Opto-electronic configuration#

The FlowCyPy.opto_electronics.OptoElectronics class groups the source, detectors, amplifier, digitizer, and optional analog processing stages into a single configuration object.

class OptoElectronics(detectors, source, amplifier, digitizer, analog_processing=())[source]#

Bases: object

Base class for optoelectronic components in flow cytometry simulations.

This class serves as a base for various optoelectronic components, such as detectors and signal generators, providing common functionality and attributes.

Parameters:
  • detectors (List[Detector], optional) – A list of Detector instances to be included in the optoelectronics setup.

  • source (source.BaseSource) – The light source instance used in the setup.

  • amplifier (Amplifier) – The amplifier instance used to amplify the detected signals.

  • digitizer (Digitizer) – The digitizer instance used to convert analog signals to digital form.

  • analog_processing (List[circuits.BaseCircuit]) – List of analog processing circuits applied to the signals.

add_coupling_to_dataframe(event_collection, compute_cross_section=False)[source]#

Computes the detected signal for each scatterer in the provided DataFrame and updates it in place. This method iterates over the list of detectors and computes the detected signal for each scatterer using the compute_detected_signal function.

Parameters:
  • event_collection (EventCollection) – Collection of dataframe containing scatterer properties. It must include a column named ‘type’ with values ‘Sphere’ or ‘CoreShell’, and additional columns required for each scatterer type.

  • compute_cross_section (bool, optional) – If True, the scattering cross section (Csca) is computed and added to the DataFrame under the column ‘Csca’. Default is False.

amplifier: Amplifier#
analog_processing: List[BaseCircuit] = ()#
apply_analog_processing(analog_dict)[source]#

Apply analog post processing circuits to an analog signal dictionary.

Parameters:
  • analog_dict (dict) – Analog voltage signals.

  • signal_processing (SignalProcessing) – Processing configuration.

Returns:

Processed analog signal dictionary.

Return type:

dict

apply_detector_current_noise(photocurrent_dict)[source]#

Apply detector current noise to photocurrent traces.

Parameters:
  • signal_dict (dict) – Photocurrent signal dictionary.

  • photocurrent_dict (dict)

Returns:

Updated photocurrent signal dictionary.

Return type:

dict

apply_source_noise_to_optical_signals(power_signal_dict)[source]#

Apply source level optical noise processes.

Parameters:

power_signal_dict (dict) – Optical power signals.

Returns:

Updated optical power signals.

Return type:

dict

convert_optical_power_to_photocurrent(power_signal_dict)[source]#

Convert detector optical power traces to photocurrent traces.

Parameters:

power_signal_dict (dict) – Optical power signal dictionary.

Returns:

Photocurrent signal dictionary.

Return type:

dict

convert_optical_power_to_voltage(power_signal_dict)[source]#

Convert optical power traces to analog voltage traces by applying the full optoelectronic chain.

Parameters:

power_signal_dict (dict) – Optical power signal dictionary.

Returns:

Analog voltage signal dictionary.

Return type:

dict

convert_photocurrent_to_voltage(photocurrent_dict)[source]#

Convert photocurrent traces to analog voltage traces.

Parameters:

photocurrent_dict (dict) – Photocurrent signal dictionary.

Returns:

Analog voltage signal dictionary.

Return type:

dict

copy_dict(dictionnary)[source]#

Create a safe working copy of a signal dictionary.

Parameters:
  • signal_dict (dict) – Signal dictionary containing arrays or Pint quantities.

  • dictionnary (dict)

Returns:

Copied signal dictionary.

Return type:

dict

detectors: List[Detector]#
digitizer: Digitizer#
initialize_optical_signal_dict(run_time, background_power)[source]#

Initialize detector optical power traces.

Parameters:
  • run_time (Time) – Acquisition duration.

  • background_power (Power) – Constant optical background added to every detector channel.

Returns:

Optical power signal dictionary.

Return type:

dict

source: BaseSource#

Light sources#

Source classes define the spatial profile and optical properties of the illuminating beam.

They specify quantities such as wavelength, optical power, beam waist, and relative intensity noise, which together determine the incident optical field seen by particles traversing the interrogation region.

Gaussian source#

The Gaussian source models a focused beam with Gaussian transverse intensity profiles.

It is suitable for most tightly focused flow cytometry illumination geometries.

class Gaussian#

Bases: BaseSource

Gaussian beam source model.

This source uses a Gaussian transverse intensity profile with potentially different waists along the y and z directions. % It is appropriate for focused illumination geometries in which the field amplitude decays smoothly away from the beam center.

set_waist(self: FlowCyPy.opto_electronics.source.Gaussian, waist_y: object, waist_z: object) None#

Update the Gaussian beam waists.

Parameters:
  • waist_y (pint.Quantity) – New beam waist along the y direction.

  • waist_z (pint.Quantity) – New beam waist along the z direction.

property waist_y#

Gaussian beam waist along the y direction.

property waist_z#

Gaussian beam waist along the z direction.

Flat-top source#

The flat-top source models an illumination profile with a more uniform intensity over the beam cross-section.

It is useful when approximating excitation geometries that are intentionally homogenized across the interrogation region.

class FlatTop#

Bases: BaseSource

Flat top beam source model.

This source approximates an illumination profile with a more uniform intensity across the beam support than a Gaussian beam. % It is useful when modeling excitation geometries intended to produce a relatively homogeneous optical field over the interrogation region.

set_waist(self: FlowCyPy.opto_electronics.source.FlatTop, waist_y: object, waist_z: object) None#

Update the effective flat top beam extents.

Parameters:
  • waist_y (pint.Quantity) – New beam extent along the y direction.

  • waist_z (pint.Quantity) – New beam extent along the z direction.

property waist_y#

Effective flat top beam extent along the y direction.

property waist_z#

Effective flat top beam extent along the z direction.

Detectors#

Detector classes describe how scattered light is collected and converted into electrical current.

A detector typically defines its angular position, numerical aperture, and responsivity.

These parameters determine the optical collection efficiency and the conversion from collected optical power to photocurrent.

class Detector#

Bases: pybind11_object

Detector model for a flow cytometry acquisition channel.

A Detector represents the collection geometry and electrical response of a single detector channel.

It stores the angular placement of the detector, its numerical aperture, optional obscuration by a central cache, the current responsivity, the dark current level, an optional additive current noise density, and an optional bandwidth used for bandwidth dependent noise calculations.

In a typical FlowCyPy workflow, detector objects are assembled into an OptoElectronics configuration and are used to convert channel specific optical power into detector current prior to amplification and digitization.

Notes

This class represents the detector level response of the acquisition chain.

It does not model downstream analog amplification or digitization. Those stages are handled by the amplifier and digitizer components.

apply_dark_current_noise(self: FlowCyPy.opto_electronics.detector.Detector, signal: object, bandwidth: object = None) object#

Add dark current noise to a detector current signal.

Dark current noise depends on the effective bandwidth used for the calculation. The bandwidth is resolved in the following order:

  1. the method argument bandwidth, when provided

  2. the detector attribute bandwidth

  3. no finite bandwidth, in which case the input signal is returned unchanged

Parameters:
  • signal (pint.Quantity) – Input current trace expressed in amperes.

  • bandwidth (pint.Quantity or None, optional) – Bandwidth to use for the noise calculation. If omitted, the detector stored bandwidth is used.

Returns:

Output current trace with dark current noise added.

Return type:

pint.Quantity

Notes

This method operates directly on detector current, before any downstream amplifier or digitizer stage.

The total RMS current noise is computed from the quadrature sum of dark-current shot noise and additive current-noise density.

property bandwidth#

Optional detector bandwidth.

When defined, this bandwidth is used as the default bandwidth for bandwidth dependent detector operations. Setting this attribute to None removes the stored bandwidth.

property cache_numerical_aperture#

Numerical aperture of the central obscuration.

This value can be used to represent a masked or blocked central region in the detector collection geometry, such as the obscuration often present in forward scatter configurations.

clear_bandwidth(self: FlowCyPy.opto_electronics.detector.Detector) None#

Remove the stored detector bandwidth.

After calling this method, bandwidth dependent operations require an explicit method level bandwidth argument in order to use a finite bandwidth.

property current_noise_density#

Detector current-noise density.

This value represents an additive current-noise spectral density expressed in ampere / sqrt(hertz).

property dark_current#

Mean detector dark current.

This value is used to model detector dark-current shot noise and the mean dark-current offset when a valid bandwidth is available.

property gamma_angle#

Longitudinal detector angle.

This angle complements phi_angle and defines the detector orientation relative to the optical axis.

has_bandwidth(self: FlowCyPy.opto_electronics.detector.Detector) bool#

Return whether the detector has a stored bandwidth.

Returns:

True if bandwidth is defined, otherwise False.

Return type:

bool

property name#

Detector identifier.

This name is typically used to label detector channels in the acquisition pipeline and in exported results.

property numerical_aperture#

Numerical aperture of the detector collection cone.

Larger values correspond to a wider collection angle and therefore a larger accepted range of scattered directions.

property phi_angle#

Azimuthal detector angle.

This angle defines the detector position around the optical axis in the transverse plane.

property responsivity#

Detector responsivity.

Responsivity defines the conversion factor between collected optical power and detector current.

property sampling#

Internal sampling density used to represent the detector support.

Increasing this value may improve geometric resolution at the cost of additional computation.

Amplification#

Amplifier classes model the analog front-end that converts detector photocurrent into voltage.

In FlowCyPy, this stage is typically represented by a transimpedance amplifier, which applies a current-to-voltage gain, a finite bandwidth, and optional electronic noise contributions.

This stage strongly influences pulse amplitude, temporal smoothing, and baseline noise before digitization.

class Amplifier#

Bases: pybind11_object

Represents a transimpedance amplifier applied to a one dimensional current signal.

This model converts an input current signal into an output voltage signal using the configured transimpedance gain. It can optionally include a finite analog bandwidth and additive Gaussian noise derived from voltage and current noise densities.

If a sampling rate is provided during amplification and the amplifier bandwidth is defined, a realistic low-pass filter is applied. If no sampling rate is provided, waveform filtering is skipped, but the bandwidth is still used for integrated noise estimation.

Parameters:
  • gain (Quantity) – Transimpedance gain in volt / ampere.

  • bandwidth (Quantity | None, optional) – Amplifier bandwidth in hertz. If None, no bandwidth-limited filtering or bandwidth-based noise integration is applied.

  • voltage_noise_density (Quantity | None, optional) – Output referred voltage noise spectral density in volt / hertz ** 0.5.

  • current_noise_density (Quantity | None, optional) – Input referred current noise spectral density in ampere / hertz ** 0.5.

  • filter_order (int, optional) – Order of the low-pass filter used when bandwidth filtering is enabled.

amplify(self: FlowCyPy.opto_electronics.amplifier.Amplifier, signal: object, sampling_rate: object) object#

Amplify a one dimensional current signal and return the output voltage signal.

Parameters:
  • signal (pint.Quantity) – One dimensional signal with units of ampere.

  • sampling_rate (pint.Quantity | None, optional) – Sampling rate in hertz. If provided and the amplifier bandwidth is defined, bandwidth-limited filtering is applied. If omitted, waveform filtering is skipped.

Returns:

Amplified output signal with units of volt.

Return type:

pint.Quantity

property bandwidth#

Bandwidth returned as a pint.Quantity in hertz, or None if unlimited.

property current_noise_density#

Current noise spectral density returned as a pint.Quantity in ampere / hertz ** 0.5.

property filter_order#

Order of the low-pass filter used when bandwidth filtering is enabled.

property gain#

Transimpedance gain returned as a pint.Quantity in volt / ampere.

get_rms_noise(self: FlowCyPy.opto_electronics.amplifier.Amplifier) object#

Calculate the RMS output noise of the amplifier.

Returns:

RMS noise expressed in volts.

Return type:

pint.Quantity

property voltage_noise_density#

Voltage noise spectral density returned as a pint.Quantity in volt / hertz ** 0.5.

Digitization#

The digitizer converts analog voltage signals into sampled digital traces.

Its configuration controls the sampling rate, quantization depth, and channel range strategy.

These settings determine the temporal resolution, integer encoding, clipping behavior, and effective dynamic range of the recorded waveforms.

class Digitizer#

Bases: pybind11_object

Digitize and clip voltage signals.

The Digitizer class models a digitization stage for detector voltage signals. It supports optional clipping, optional automatic range inference, and quantization to either unsigned or signed integer like ADC codes.

Two settings control range selection:

use_auto_range

Select whether ranges are inferred from the data or taken from the fixed instance level min_voltage and max_voltage.

channel_range_mode

When use_auto_range is enabled, controls whether automatic range inference is shared across channels or done independently for each channel.

Explicit channel ranges set with set_channel_voltage_range() always take precedence over the automatic or fixed instance level policy.

Parameters:
  • sampling_rate (pint.Quantity) – Sampling rate in hertz.

  • bandwidth (pint.Quantity or None, default=None) – Digitizer bandwidth in hertz. If None, bandwidth remains unset.

  • bit_depth (int, default=0) – Number of quantization bits. A value of 0 disables digitization.

  • min_voltage (pint.Quantity or None, default=None) – Minimum clipping voltage used when a fixed range is required.

  • max_voltage (pint.Quantity or None, default=None) – Maximum clipping voltage used when a fixed range is required.

  • use_auto_range (bool, default=False) – If True, infer voltage ranges automatically from the signal data.

  • output_signed_codes (bool, default=False) – If True, digitized outputs use signed integer like code values.

  • debug_mode (bool, default=False) – If True, print debug information during processing.

  • channel_range_mode ({"shared", "per_channel"}, default="shared") – Automatic range scope used when use_auto_range is enabled.

property bandwidth#

Bandwidth of the digitizer.

Returns:

Bandwidth in hertz, or None if unset.

Return type:

pint.Quantity or None

property bit_depth#

Number of quantization bits.

A value of 0 disables digitization.

capture_signal(*args, **kwargs)#

Overloaded function.

  1. capture_signal(self: FlowCyPy.opto_electronics.digitizer.Digitizer, signal: object) -> None

    Update internal range information using the persistent use_auto_range setting.

    signalpint.Quantity

    One dimensional voltage signal.

  2. capture_signal(self: FlowCyPy.opto_electronics.digitizer.Digitizer, signal: object, use_auto_range: bool) -> None

    Update internal range information with an explicit auto range override.

    signalpint.Quantity

    One dimensional voltage signal.

    use_auto_rangebool

    If True, infer and store the signal min and max as the instance level voltage range.

property channel_range_mode#

Automatic range scope for dictionary based channel processing.

Allowed values are:

"shared"

Infer one shared range across all detector channels without explicit channel overrides.

"per_channel"

Infer one independent range for each detector channel without explicit channel overrides.

Notes

This property only affects processing when use_auto_range is True. When use_auto_range is False, the instance level min_voltage and max_voltage are used instead.

clear_all_channel_voltage_ranges(self: FlowCyPy.opto_electronics.digitizer.Digitizer) None#

Clear all explicit per channel voltage ranges.

clear_bandwidth(self: FlowCyPy.opto_electronics.digitizer.Digitizer) None#

Clear the configured bandwidth.

After this call, bandwidth becomes undefined.

clear_channel_voltage_range(self: FlowCyPy.opto_electronics.digitizer.Digitizer, channel_name: str) None#

Clear the explicit voltage range for one detector channel.

Parameters:

channel_name (str) – Name of the detector channel.

clear_voltage_range(self: FlowCyPy.opto_electronics.digitizer.Digitizer) None#

Clear the instance level fixed voltage range.

After this call, both min_voltage and max_voltage become undefined. Explicit per channel ranges are not modified.

clip_signal(self: FlowCyPy.opto_electronics.digitizer.Digitizer, signal: object) object#

Clip a signal to the instance level fixed voltage range.

Parameters:

signal (pint.Quantity) – One dimensional voltage signal.

Returns:

Clipped voltage signal.

Return type:

pint.Quantity

Notes

This method uses only the instance level min_voltage and max_voltage.

digitize_data_dict(self: FlowCyPy.opto_electronics.digitizer.Digitizer, data_dict: dict) object#

Process acquisition data stored in a dictionary.

Supported input formats#

Flat acquisition dictionary:
{

“Time”: time_quantity, “DetectorA”: voltage_quantity, …

}

Flat acquisition dictionaries may also contain metadata fields such as "segment_id". Metadata fields are copied through unchanged and are never used for voltage range inference.

Range resolution order#

For each detector channel, the applied range is chosen in this order:

  1. explicit channel range set with set_channel_voltage_range()

  2. if use_auto_range is True: a. shared inferred range when channel_range_mode == "shared" b. per channel inferred range when channel_range_mode == "per_channel"

  3. if use_auto_range is False: instance level min_voltage and max_voltage

param data_dict:

Acquisition data dictionary using Pint quantities.

type data_dict:

dict

returns:

Dictionary with processed detector channels. Metadata fields such as Time and segment_id are copied unchanged. If digitization is disabled, detector channels are returned as voltage quantities. If digitization is enabled, detector channels are returned as integer ADC code arrays.

rtype:

dict

digitize_signal(self: FlowCyPy.opto_electronics.digitizer.Digitizer, signal: object) object#

Digitize one voltage signal using the instance level fixed voltage range.

Parameters:

signal (pint.Quantity) – One dimensional voltage signal.

Returns:

Integer ADC code array if digitization is enabled. If digitization is disabled, the returned array contains the unchanged floating point samples.

Return type:

numpy.ndarray

Notes

This method does not perform automatic range inference.

get_channel_voltage_range(self: FlowCyPy.opto_electronics.digitizer.Digitizer, channel_name: str) tuple[object, object]#

Return the explicit voltage range of a channel.

Parameters:

channel_name (str) – Name of the detector channel.

Returns:

Minimum and maximum voltage bounds in volts.

Return type:

tuple[pint.Quantity, pint.Quantity]

Raises:

RuntimeError – If the channel has no explicit range override.

get_maximum_code(self: FlowCyPy.opto_electronics.digitizer.Digitizer) int#

Return the maximum ADC code value.

Returns:

Maximum representable code value for the current digitizer settings.

Return type:

int

Raises:

RuntimeError – If digitization is disabled.

get_min_max(self: FlowCyPy.opto_electronics.digitizer.Digitizer, signal: object) tuple[object, object]#

Return the minimum and maximum finite values of a signal.

Parameters:

signal (pint.Quantity) – One dimensional voltage signal.

Returns:

Minimum and maximum finite values in volts.

Return type:

tuple[pint.Quantity, pint.Quantity]

get_minimum_code(self: FlowCyPy.opto_electronics.digitizer.Digitizer) int#

Return the minimum ADC code value.

Returns:

Minimum representable code value for the current digitizer settings.

Return type:

int

Raises:

RuntimeError – If digitization is disabled.

get_time_series(self: FlowCyPy.opto_electronics.digitizer.Digitizer, run_time: object) object#

Return the sampling time axis for a given acquisition duration.

Parameters:

run_time (pint.Quantity) – Acquisition duration in seconds.

Returns:

Sampling time axis in seconds.

Return type:

pint.Quantity

has_bandwidth(self: FlowCyPy.opto_electronics.digitizer.Digitizer) bool#

Return whether a bandwidth is defined.

Returns:

True if bandwidth is set, otherwise False.

Return type:

bool

has_channel_voltage_range(self: FlowCyPy.opto_electronics.digitizer.Digitizer, channel_name: str) bool#

Return whether a channel has an explicit voltage range.

Parameters:

channel_name (str) – Name of the detector channel.

Returns:

True if the channel has an explicit range override.

Return type:

bool

has_signed_output_codes(self: FlowCyPy.opto_electronics.digitizer.Digitizer) bool#

Return whether signed output codes are enabled.

Returns:

True if signed integer ADC codes are requested.

Return type:

bool

has_voltage_range(self: FlowCyPy.opto_electronics.digitizer.Digitizer) bool#

Return whether the instance level fixed voltage range is defined.

Returns:

True if both min_voltage and max_voltage are set.

Return type:

bool

property max_voltage#

Instance level fixed maximum clipping voltage.

Returns:

Maximum clipping voltage in volts, or None if unset.

Return type:

pint.Quantity or None

Notes

This value is used only when use_auto_range is False, unless an explicit per channel range overrides it.

property min_voltage#

Instance level fixed minimum clipping voltage.

Returns:

Minimum clipping voltage in volts, or None if unset.

Return type:

pint.Quantity or None

Notes

This value is used only when use_auto_range is False, unless an explicit per channel range overrides it.

property output_signed_codes#

Whether digitized outputs use signed integer like code values.

process_signal(self: FlowCyPy.opto_electronics.digitizer.Digitizer, signal: object) object#

Process one signal.

Processing order:

  1. choose a fixed or automatically inferred range

  2. clip using that range

  3. digitize

Parameters:

signal (pint.Quantity) – One dimensional voltage signal.

Returns:

If digitization is disabled, returns a voltage quantity. Otherwise returns an integer code array.

Return type:

pint.Quantity or numpy.ndarray

property sampling_rate#

Sampling rate of the digitizer.

Returns:

Sampling rate in hertz.

Return type:

pint.Quantity

set_auto_range(self: FlowCyPy.opto_electronics.digitizer.Digitizer, signal: object) None#

Infer and store the instance level voltage range from one signal.

The minimum and maximum finite values of the input signal are used to update min_voltage and max_voltage.

Parameters:

signal (pint.Quantity) – One dimensional voltage signal.

set_channel_voltage_range(self: FlowCyPy.opto_electronics.digitizer.Digitizer, channel_name: str, minimum_voltage: object, maximum_voltage: object) None#

Set an explicit voltage range for one detector channel.

Parameters:
  • channel_name (str) – Name of the detector channel.

  • minimum_voltage (pint.Quantity) – Minimum voltage bound. Must be compatible with volts.

  • maximum_voltage (pint.Quantity) – Maximum voltage bound. Must be compatible with volts.

Notes

Explicit channel ranges always take precedence over the global processing policy.

Examples

digitizer.set_channel_voltage_range("forward", -0.2 * ureg.volt, 1.5 * ureg.volt)

should_digitize(self: FlowCyPy.opto_electronics.digitizer.Digitizer) bool#

Return whether digitization is enabled.

Returns:

True if bit_depth is greater than zero.

Return type:

bool

property use_auto_range#

Whether voltage ranges are inferred automatically from the data.

When False, processing uses the fixed instance level min_voltage and max_voltage, unless an explicit channel override is present.

When True, processing infers ranges from the signal data. The scope of that inference is controlled by channel_range_mode.

Analog processing circuits#

Analog processing circuits represent signal conditioning stages applied before digitization.

Typical examples include baseline restoration, low-pass filtering, and other bandwidth-limiting or shaping operations that affect the continuous detector signal.

Analog signal conditioning circuits for FlowCyPy.

This module exposes analog processing circuits used in the opto electronic acquisition chain of a flow cytometry simulation. % Each circuit operates on a one dimensional signal and returns a processed signal with the same physical units as the input. % Typical use cases include baseline correction, baseline restoration, and analog low pass filtering prior to digitization or downstream digital processing.

All public process methods expect:

  • signal to be a Pint quantity backed by a one dimensional NumPy array

  • sampling_rate to be a Pint quantity compatible with hertz when required

class BaseCircuit#

Bases: pybind11_object

Abstract base class for analog signal conditioning circuits.

A BaseCircuit represents a transformation applied to a one dimensional signal in the analog acquisition chain. % Concrete subclasses implement specific operations such as baseline subtraction or low pass filtering. % The processed output always retains the same physical units as the input signal.

process(self: FlowCyPy.opto_electronics.circuits.BaseCircuit, signal: object, sampling_rate: object = None) object#

Process a signal with the circuit.

Parameters:
  • signal (pint.Quantity) – One dimensional input signal.

  • sampling_rate (pint.Quantity or None, optional) – Sampling rate in hertz. % Circuits that depend on time scale or frequency response may require this value, while others may ignore it.

Returns:

Processed signal with the same units as the input.

Return type:

pint.Quantity

Notes

This method preserves the physical units of the input signal. % Only the numerical values are transformed by the circuit.

class BaselineRestorationServo#

Bases: BaseCircuit

Baseline restoration servo circuit.

This circuit models a baseline restoration stage that continuously estimates the slowly varying baseline of a signal and subtracts it so that the output is driven toward a target reference level. % It is useful for suppressing baseline drift and restoring a stable operating point before digitization or event extraction. % The response speed of the servo is controlled by its time constant.

property initialize_with_first_sample#

Whether the internal baseline state is initialized from the first sample.

When enabled, the circuit starts from the first input value, which often reduces initial transients.

process(self: FlowCyPy.opto_electronics.circuits.BaselineRestorationServo, signal: object, sampling_rate: object) object#

Apply baseline restoration servo processing.

Parameters:
  • signal (pint.Quantity) – One dimensional input signal.

  • sampling_rate (pint.Quantity) – Sampling rate in hertz.

Returns:

Baseline restored signal with the same units as the input.

Return type:

pint.Quantity

Notes

A valid sampling rate is required because the circuit dynamics are defined through the servo time constant.

property reference_level#

Target output baseline level.

After restoration, the signal baseline is driven toward this numerical reference value.

property time_constant#

Servo time constant.

Returns:

Time constant in second.

Return type:

pint.Quantity

class BesselLowPass#

Bases: BaseCircuit

Bessel low pass filter.

This circuit applies a Bessel low pass response to the input signal. % Bessel filters are often preferred when preserving waveform shape and approximate phase linearity is more important than maximizing roll off steepness. % The output can optionally be scaled by a multiplicative gain factor.

property cutoff_frequency#

Filter cutoff frequency.

Returns:

Cutoff frequency in hertz.

Return type:

pint.Quantity

property gain#

Multiplicative output gain applied after filtering.

property order#

Filter order.

Higher orders increase the sharpness of the low pass transition.

process(self: FlowCyPy.opto_electronics.circuits.BesselLowPass, signal: object, sampling_rate: object) object#

Apply Bessel low pass filtering.

Parameters:
  • signal (pint.Quantity) – One dimensional input signal.

  • sampling_rate (pint.Quantity) – Sampling rate in hertz.

Returns:

Filtered signal with the same units as the input.

Return type:

pint.Quantity

Notes

This filter is typically used when preserving pulse shape is more important than maximizing stopband steepness.

class ButterworthLowPass#

Bases: BaseCircuit

Butterworth low pass filter.

This circuit applies a Butterworth low pass response to the input signal. % Butterworth filters provide a maximally flat magnitude response in the passband and are useful when smooth low pass attenuation is desired without passband ripple. % The output can optionally be scaled by a multiplicative gain factor.

property cutoff_frequency#

Filter cutoff frequency.

Returns:

Cutoff frequency in hertz.

Return type:

pint.Quantity

property gain#

Multiplicative output gain applied after filtering.

property order#

Filter order.

Higher orders correspond to a sharper transition between passband and stopband.

process(self: FlowCyPy.opto_electronics.circuits.ButterworthLowPass, signal: object, sampling_rate: object) object#

Apply Butterworth low pass filtering.

Parameters:
  • signal (pint.Quantity) – One dimensional input signal.

  • sampling_rate (pint.Quantity) – Sampling rate in hertz.

Returns:

Filtered signal with the same units as the input.

Return type:

pint.Quantity

Notes

The sampling rate is required to map the analog cutoff frequency to the discrete time signal.

class SlidingMinimumBaselineCorrection#

Bases: BaseCircuit

Sliding minimum baseline correction circuit.

This circuit estimates the local baseline by tracking the minimum signal value within a sliding window and subtracting that baseline estimate from the input. % It is useful for suppressing slowly varying offsets or drifting baselines while preserving positive excursions associated with particle events. % A window size of -1 * second is interpreted as an infinite window, meaning that the baseline is estimated from the global minimum over the full signal.

process(self: FlowCyPy.opto_electronics.circuits.SlidingMinimumBaselineCorrection, signal: object, sampling_rate: object = None) object#

Apply sliding minimum baseline correction.

Parameters:
  • signal (pint.Quantity) – One dimensional input signal.

  • sampling_rate (pint.Quantity or None, optional) – Sampling rate in hertz. % This is required when window_size is finite, because the time window must be converted into a number of samples. % It may be omitted when the window is infinite.

Returns:

Baseline corrected signal with the same units as the input.

Return type:

pint.Quantity

property window_size#

Sliding window size used for baseline estimation.

Returns:

Window size in second. % A value of -1 * second indicates an infinite window.

Return type:

pint.Quantity

Example#

The example below shows a typical opto-electronic configuration composed of a Gaussian source, two detectors, a transimpedance amplifier, optional analog filtering, and a digitizer.

from FlowCyPy.units import ureg
from FlowCyPy.opto_electronics import (
    Detector,
    Digitizer,
    OptoElectronics,
    Amplifier,
    source,
    circuits,
)

analog_processing = [
    circuits.BaselineRestorationServo(time_constant=100 * ureg.microsecond),
    circuits.BesselLowPass(cutoff_frequency=2 * ureg.megahertz, order=4, gain=2),
]

excitation_source = source.Gaussian(
    waist_z=10e-6 * ureg.meter,
    waist_y=60e-6 * ureg.meter,
    wavelength=405 * ureg.nanometer,
    optical_power=200 * ureg.milliwatt,
    rin=-140 * ureg.dB_per_Hz,
    bandwidth=10 * ureg.megahertz,
)

detectors = [
    Detector(
        name="side",
        phi_angle=90 * ureg.degree,
        numerical_aperture=1.1,
        responsivity=1 * ureg.ampere / ureg.watt,
    ),
    Detector(
        name="forward",
        phi_angle=0 * ureg.degree,
        numerical_aperture=0.3,
        cache_numerical_aperture=0.1,
        responsivity=1 * ureg.ampere / ureg.watt,
    ),
]

amplifier = Amplifier(
    gain=10 * ureg.volt / ureg.ampere,
    bandwidth=10 * ureg.megahertz,
    voltage_noise_density=0.0 * ureg.nanovolt / ureg.sqrt_hertz,
    current_noise_density=0.0 * ureg.femtoampere / ureg.sqrt_hertz,
)

digitizer = Digitizer(
    sampling_rate=60 * ureg.megahertz,
    bit_depth=14,
    use_auto_range=True,
    channel_range_mode="shared",
)

opto_electronics = OptoElectronics(
    digitizer=digitizer,
    detectors=detectors,
    source=excitation_source,
    amplifier=amplifier,
    analog_processing=analog_processing,
)