Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions python/packages/nisar/antenna/rx_channel_imbalance_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,20 @@ def compute_rx_channel_imbalance(
txrx_pol,
caltone_freq=caltone_freq
)
# peak normalized
max_ratio = np.nanmax(abs(lna_caltone_ratio))
# compute complex caltone offset from the mean caltone
# over all active RX channels. This is used to remove
# phase/amplitude jumps due to WG reset over time, mode
# changes where pulsewidth varies, and finally due to
# change in caltone location onboard!
idx_rxs_active = raw.getListOfRxTRMs(freq_band, txrx_pol) - 1
caltone_ofs = np.nanmean(caltone_mean[idx_rxs_active])
# Use constant scalar, e.g., 1945, to scale the Caltone offset.
# This is to preserve the current abscal. (optional)
# This offset is obtained from the median over several
# observations/modes that have the same caltone frequency!
caltone_ofs /= 1945.0
# peak normalized and apply complex offset
max_ratio = caltone_ofs * np.nanmax(abs(lna_caltone_ratio))
if not np.isclose(max_ratio, 0):
lna_caltone_ratio /= max_ratio
return lna_caltone_ratio, n_tap_dominant, time_delays, max_ratio
Expand Down
57 changes: 46 additions & 11 deletions python/packages/nisar/workflows/focus.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
open_rrsd,
chirpcorrelator_caltype_from_raw,
is_raw_quad_pol,
first_tx_pol_for_quad
first_tx_pol_for_quad,
caltone_frequency_from_raw
)
from nisar.products.readers.rslc_cal import (RslcCalibration,
parse_rslc_calibration, get_scale_and_delay, check_cal_validity_dates)
Expand Down Expand Up @@ -1705,7 +1706,43 @@ def get_focused_sub_swaths(rawlist, out_chan, grid, orbit, doppler, dem, azres,
return swaths


def get_caltone_algorithm(cfg, fc, fs, n, is_dithered):
def get_caltone_frequency(cfg, raw, pol):
"""
Get Caltone frequency either from RSLC runconfig or from
parsing it from raw L0B low-rate telemerty (DRT).

Parameters
----------
cfg : Struct
RSLC runconfig data.
raw : nisar.products.readers.raw.Raw
NISAR L0B product pareser object
pol : str
Tx-Rx polarization such as "HH", "HV", etc

Returns
-------
float
Caltone frequency in Hz.

"""
caltone_freq = cfg.processing.caltone.frequency
caltone_freq_raw = caltone_frequency_from_raw(raw=raw, txrx_pol=pol)
if caltone_freq is None:
caltone_freq = caltone_freq_raw
name = os.path.basename(raw.filename)
log.info(f'Caltone frequency parsed from raw L0B "{name}" '
f'is {caltone_freq * 1e-6} (MHz)')
elif not np.isclose(caltone_freq, caltone_freq_raw, rtol=1e-6):
log.warning(
'Noticeable mismtach in Caltone frequency between user-provided '
f'one {caltone_freq} (Hz) and L0B-parsed one {caltone_freq_raw} '
'(Hz)!'
)
return caltone_freq


def get_caltone_algorithm(cfg, fc, fs, n, is_dithered, caltone_freq):
"""Helper for configuring caltone removal.

Parameters
Expand All @@ -1720,6 +1757,8 @@ def get_caltone_algorithm(cfg, fc, fs, n, is_dithered):
Number of samples in raw data.
is_dithered : bool
Whether we're analyzing a mode with dithered PRI.
caltone_freq : float
Caltone frequency in Hz.

Returns
-------
Expand All @@ -1742,7 +1781,7 @@ def get_caltone_algorithm(cfg, fc, fs, n, is_dithered):
elif algorithm == "wavelet":
log.info("Will remove wavelet caltone estimate from each pulse.")
wavelets = isce3.focus.ToneRemover(
(cfg.processing.caltone.frequency - fc) / fs,
(caltone_freq - fc) / fs,
n, cfg.processing.caltone.wavelet_size)
else:
algorithm = "disabled"
Expand Down Expand Up @@ -2059,9 +2098,11 @@ def temp(suffix):
log.info("Will fill gaps between sub-swaths with zeros.")

fs = raw.getChirpParameters(channel_in.freq_id, pol[0])[1]
caltone_freq = get_caltone_frequency(cfg=cfg, raw=raw, pol=pol)
log.info(f'Caltone frequency is {caltone_freq * 1e-6} (MHz)')
caltone_algorithm, wavelets = get_caltone_algorithm(cfg,
channel_in.band.center, fs, raw_grid.shape[1],
raw.isDithered(channel_in.freq_id))
raw.isDithered(channel_in.freq_id), caltone_freq)

for i in range(0, raw_grid.shape[0], na):
pulse = i + pulse_begin
Expand Down Expand Up @@ -2121,12 +2162,6 @@ def temp(suffix):

# Precompute antenna patterns at downsampled spacing
if cfg.processing.is_enabled.eap:
# XXX Due to a bug in respective DRT of some L0B products
# (CRID=05007), caltone.frequency is extrated from runconfig
# otherwise, it shall be set to None to be determined from DRT!
# The latter requires RSLC runconfig update to allow caltone
# frequency to be parsed directly from L0B product for more
# flexible configuration over wide range of L0B products.
# XXX the intrument-related delay offset used in DBF process
# shall be eventually obtained from instrument INT CAL HDF5
# once the respective product spec is updated (delay_ofs_dbf)!
Expand All @@ -2135,7 +2170,7 @@ def temp(suffix):
instparser, orbit, attitude,
el_lut=el_lut,
freq_band=channel_in.freq_id,
caltone_freq=cfg.processing.caltone.frequency,
caltone_freq=caltone_freq,
delay_ofs_dbf=-2.1474e-6)

log.info("Precomputing antenna patterns")
Expand Down
8 changes: 7 additions & 1 deletion share/nisar/defaults/focus.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,13 @@ runconfig:
# table v50 and v51, which went into operations on
# 2025-10-17T00:00:00Z. The v50 frequency is 1216.904297e6 Hz
# while the v51 frequency is 1214.882813e6 Hz.
frequency: 1214.882813e6
# For RCID=164 (77 MHz) over Antartica, it is set to
# 1209.492036e6 Hz since 2026-06-08T01:24:07Z.
# Default (Null or missing in user runconfig) implies that
# the Caltone frequency will be extracted from L0B DRT if
# available in L0B product otherwise it will be set to
# 1214.882813e6 Hz internally.
frequency: null

# Length of constant-overlap add (COLA) window.
wavelet_size: 64
Expand Down
Loading