msi_processor.computing.radiometric package#
Radiometric correction stage (C-PU-RAD; DPM-M-RAD; ALG-RAD-*).
Dark/offset (DSNU) subtraction, NUC/flat-field (PRNU) equalisation,
bad-pixel detection & replacement, and saturation/no-data flagging. The
stage is a pure core plus a thin
RadiometricUnit wrapper.
Submodules#
msi_processor.computing.radiometric.core module#
Pure radiometric-correction core (C-PU-RAD; ALG-RAD-NUC/DARK/BPR/SAT).
CPM-free, I/O-free numpy functions implementing the radiometric algorithms of
ATBD <5.2>, ported faithfully from the heritage level_1.py NUC class
(compute_nuc / apply_nuc_and_bpr; RD-9). All arrays are processed in
float32 with a fixed operation order for reproducibility
(REQ-F-DEP-02, REQ-D-05).
Geometry convention: arrays are 2-D (line, detector) in focal-plane
geometry; per-detector gain/offset/dark are 1-D (detector,)
vectors broadcast across lines (ATBD <4.2>, SDD <5.5>).
Trace: REQ-F-RAD-01..05; DPM-M-RAD; ALG-RAD-*.
- class msi_processor.computing.radiometric.core.RadiometricParams(bit_depth=12, g_min=None, g_max=None, saturation=None, fill_value=None, remove_dark_fft=False)#
Bases:
objectTunable radiometric parameters (SDD <5.4.3>; DPM-PRM-RAD-01..04).
- Parameters:
- bit_depth:
Sensor radiometric depth; valid DN range
[0, 2**bit_depth - 1](DPM-PRM-GEN-01, default 12).- g_min, g_max:
Bad-pixel gain bounds (
DPM-PRM-RAD-02).Nonedisables that bound.- saturation:
Saturation threshold DN; defaults to
2**bit_depth - 1whenNone.- fill_value:
No-data sentinel DN; flagged
NO_DATAwhen present.- remove_dark_fft:
Enable the optional FFT dark-noise pre-removal (
DPM-PRM-RAD-03).
- Attributes:
- fill_value
- g_max
- g_min
max_dnUpper bound of the valid DN range,
2**bit_depth - 1.- saturation
-
bit_depth:
int= 12#
-
fill_value:
Optional[int] = None#
-
g_max:
Optional[float] = None#
-
g_min:
Optional[float] = None#
- property max_dn: int#
Upper bound of the valid DN range,
2**bit_depth - 1.
-
remove_dark_fft:
bool= False#
-
saturation:
Optional[int] = None#
- msi_processor.computing.radiometric.core.apply_nuc(dn, gain, offset, dark_offset)#
ALG-RAD-DARK — apply the per-detector affine plus dark-offset. :rtype:
ndarray[tuple[Any,...],dtype[float32]]\[X^{(b)}_{l,d} = \mathrm{DN}^{(b)}_{l,d}\,g^{(b)}_d + o^{(b)}_d - k^{(b)}\](heritage
apply_nuc_and_bpr).gain/offsetare 1-D(detector,)vectors broadcast across lines;dark_offsetis the per-band scalar \(k\) (or a per-detector vector). Returnsfloat32.
- msi_processor.computing.radiometric.core.detect_bad_pixels(gain, params, bpm)#
ALG-RAD-BPR (detection) — flag bad detectors.
A detector is bad when its gain falls outside the admissible bounds, when its gain is non-finite (NUC singularity), or when it is listed in the bad-pixel-map ADF: :rtype:
ndarray[tuple[Any,...],dtype[bool]]\[\text{bad}(d) \iff g_d \ge g_{\max} \;\vee\; g_d \le g_{\min} \;\vee\; \neg\,\mathrm{finite}(g_d) \;\vee\; \mathrm{bpm}(d).\]Returns a boolean array of shape
(detector,).
- msi_processor.computing.radiometric.core.estimate_nuc(dark, flat, cut_dark=0, cut_flat=0)#
ALG-RAD-NUC — estimate per-detector gain/offset (heritage
compute_nuc).From a dark frame \(D\) and a flat-field frame \(F\) (both
(line, detector)), reduce to per-detector column means and derive the normalising affine that maps every detector’s flat response to the array mean \(\mu_F\) and its dark to \(\mu_D\): :rtype:tuple[ndarray[tuple[Any,...],dtype[float32]],ndarray[tuple[Any,...],dtype[float32]]]\[g_d = \frac{\mu_F - \mu_D}{\bar F_d - \bar D_d}, \qquad o_d = \mu_F - g_d\,\bar F_d .\]- Parameters:
- dark, flat:
Dark / flat-field reference frames, dims
(line, detector).- cut_dark, cut_flat:
Number of leading along-track rows to discard before reduction (edge-cut alignment; default 0).
- Returns:
- tuple of ndarray
(gain[detector], offset[detector])asfloat32.
Notes
Detectors with \(\bar F_d = \bar D_d\) yield a non-finite gain (NUC singularity); these are not raised here but are caught downstream by
detect_bad_pixels()and repaired (SDD <5.4.3>).
- msi_processor.computing.radiometric.core.flag_saturation(corrected, params)#
ALG-RAD-SAT — clip to the valid range and flag saturation / no-data.
Values at or above the saturation level (
params.saturationor2**bit_depth - 1) are flaggedQAFlag.SATURATED; non-finite values and any equal toparams.fill_valueare flaggedQAFlag.NO_DATA. The data is then clipped to[0, 2**bit_depth - 1](REQ-F-RAD-04, REQ-D-05).- Return type:
tuple[ndarray[tuple[Any,...],dtype[float32]],ndarray[tuple[Any,...],dtype[uint16]]]- Returns:
- tuple of ndarray
(clipped[float32], qa[uint16])of the same shape ascorrected.
- msi_processor.computing.radiometric.core.remove_dark_fft(dn, dark)#
Optional FFT dark-noise removal (heritage
dark_noise_removal). :rtype:ndarray[tuple[Any,...],dtype[float32]]\[\hat I = \Re\big\{\mathcal F^{-1}(\mathcal F(I) - \mathcal F(D))\big\}\]By linearity of the Fourier transform this equals spatial dark subtraction \(I - D\); the FFT route is retained where a frequency-selective dark notch is desired (ATBD <5.4>, ALG-ENH-FFTDARK). The dark frame is cropped to the image extent and negative results are floored at 0 (upper clipping is deferred to
flag_saturation()). Returnsfloat32.
- msi_processor.computing.radiometric.core.replace_bad_pixels(corrected, bad)#
ALG-RAD-BPR (replacement) — across-track neighbour interpolation.
Repairs bad detectors column-wise (heritage
apply_nuc_and_bpr): :rtype:ndarray[tuple[Any,...],dtype[float32]]\[\begin{split}X_{:,d} \leftarrow \begin{cases} X_{:,d_{\text{next valid}}}, & d = 0,\\ X_{:,d-1}, & d \text{ and } d{+}1 \text{ both bad},\\ \tfrac12\big(X_{:,d-1}+X_{:,d+1}\big), & d \text{ bad}, d{+}1 \text{ valid},\\ X_{:,d-1}, & d = N_d - 1. \end{cases}\end{split}\]The pass is sequential left-to-right and operates on a copy. If every detector is bad (degenerate input) the array is returned unchanged. Returns
float32.
msi_processor.computing.radiometric.unit module#
Thin EOProcessingUnit wrapper for radiometric correction (C-PU-RAD).
Adapts the pure core to the EOPF
CPM runtime following the wrapper template of SDD <5.4.1>: read parameters,
extract input bands, load/validate ADFs, call the core per band, attach QA
flags, and build the output EOProduct. No algorithm lives here.
Mandatory inputs/ADFs are declared by the CPM computing-model JSON
(models/msi_radiometric_1.0.0.json), not by overriding the list methods.
ADF data convention (this increment). The unit reads ADF content from the
AuxiliaryDataFile.data_ptr mapping (the CPM data_ptr is documented as
holding the opened data):
dark->{"dark_offset": {band: float}, "frame": {band: ndarray2d}}(both keys optional;dark_offsetdefaults to 0.0,frameis only needed for FFT dark removal or calibration-mode NUC derivation)nuc->{"gain": {band: ndarray1d}, "offset": {band: ndarray1d}}(nominal mode)flatfield->{band: ndarray2d}(calibration mode)badpixel->{band: ndarray1d[bool]}(optional)
Trace: REQ-F-RAD-01..05; DPM-M-RAD; ALG-RAD-*; ICD <5.3.4>A.
- class msi_processor.computing.radiometric.unit.RadiometricUnit(identifier='')#
Bases:
EOProcessingUnitRadiometric correction processing unit (C-PU-RAD; SDD <5.4.3>).
- Attributes:
identifierIdentifier of the processing step
Methods
run:
Execute dark/NUC/BPR/saturation correction over the input bands.
- PROCESSOR_LEVEL = 'L1A'#
- PROCESSOR_MODEL = True#
- PROCESSOR_NAME = 'msi_radiometric'#
- PROCESSOR_VERSION = '1.0.0'#
- run(inputs, adfs=None, mode=None, **kwargs)#
Run the radiometric correction.
- Return type:
Mapping[str,Union[EOProduct,EOContainer,DataTree,Iterable[Union[EOProduct,EOContainer,DataTree]]]]- Parameters:
- inputs:
{"l1a": EOProduct}with bands undermeasurements/detector.- adfs:
dark(mandatory);nuc(nominal mode) orflatfield(calibration mode);badpixel(optional).- mode:
"nominal"(read NUC from ADF) or"calibration"(derive NUC from dark+flat and emit anucproduct, REQ-F-RAD-05).- **kwargs:
RadiometricParamsfields plus optionalnamefor the output product.
- Returns:
- Mapping[str, DataType]
{"rad": EOProduct}(corrected DN + QA); additionally{"nuc": EOProduct}in calibration mode.