Skip to content

Remove the PhiDP system phase offset before Bringi KDP processing - #136

Merged
rcjackson merged 1 commit into
ARM-Development:mainfrom
rcjackson:rcjackson/phase_fix
Sep 10, 2026
Merged

Remove the PhiDP system phase offset before Bringi KDP processing#136
rcjackson merged 1 commit into
ARM-Development:mainfrom
rcjackson:rcjackson/phase_fix

Conversation

@rcjackson

Copy link
Copy Markdown
Collaborator

The phase calculations using Bringi's technique were not being adjusted by the system phase and unfolded first, which was causing some radial artifacts in the outputs. This PR mitigates these artifacts.

Written with Claude Opus 5's help.

The BNF C-SAPR2 raw differential phase sits on a system phase offset of
roughly 220 degrees. The bringi branch passed it to csu_kdp unchanged,
so corrected_differential_phase kept the offset, and Py-ART's
_prepare_phidp smeared it along each ray with np.maximum.accumulate.
Z-PHI then read that plateau as propagation phase: the self consistency
number came out at 10.34 instead of order 0.05 to 0.2, and the
reflectivity fed to the integral was inflated by about 16 dB. The
result was specific differential attenuation up to 2.2 dB/km, roughly
20 times the physical C-band value, with radial streaking where the
plateau differed between adjacent rays.

Estimate the offset and subtract it, undoing the 0-360 fold in the same
step, before calling calc_kdp_bringi. get_sys_phase takes the median
over the first meteorological gates of each ray then the median across
rays; Py-ART's estimators take a per-ray minimum, which sits well below
the true offset when PhiDP noise is order 30 degrees, and both raise
IndexError on the BNF RHI files whose sweep_end_ray_index disagrees
with the ray count. They are kept as fallbacks. The value used is
recorded as a system_phase_offset attribute and can be pinned with the
new phidp_sys_phase configuration key.

On bnfcsapr2cfrS3.a1.20250520.000009 at 3.5 degrees this takes
corrected_differential_phase from 196..257 to -26..36 degrees, ADP max
from 2.206 to 0.100 dB/km, and PIDA max from 4.639 to 0.543 dB.

Two related corrections:

Py-ART's field metadata carries valid_min/valid_max on
specific_attenuation but none on specific_differential_attenuation, so
AH above the cap was silently masked on read while the ADP derived from
that same AH survived, leaving the pair disagreeing by over a thousand
gates. Set both, deriving the ADP bound from the AH bound through the
same ADP = c * AH ** d relation.

calculate_attenuation_zphi defaults to temp_ref='temperature', so the
iso0_field argument was silently ignored and the melting layer came
from a sounding_temperature copy whose masked gates had been filled
with +9999 degC, marking the entire ice region as liquid. Pass
temp_ref explicitly and drop the fill. This changes the melting layer
mask on 26 percent of gates volume wide but no output gates, since
those gates are already excluded by phase_proc_gates.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@rcjackson
rcjackson merged commit a40060e into ARM-Development:main Sep 10, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants