Polarization Classifier (pynasonde.vipir.analysis.polarization)¶
O/X Wave-Mode Separation via PP Polarization Parameter
Labels each echo "O", "X", "ambiguous", or "unknown" by thresholding the PP chirality parameter from the Dynasonde seven-parameter signal model.
Theory¶
The PP parameter (polarization_deg) measures the chirality of the reflected
wavefront from differential phase between quasi-orthogonal antenna pairs. For
vertically incident HF signals the O and X modes have opposite chirality, mapping
to opposite signs of PP.
The sign convention is station-specific:
- Northern hemisphere: negative PP → O-mode (
o_mode_sign=-1, default) - Southern hemisphere: positive PP → O-mode (
o_mode_sign=+1)
Classes¶
pynasonde.vipir.analysis.polarization
¶
polarization.py — O/X wave-mode separation via the PP polarization parameter.
The PP parameter (polarization_deg in :class:~pynasonde.vipir.riq.echo.Echo)
measures the chirality of the reflected wavefront, estimated from the differential
phase between quasi-orthogonal antenna pairs.
For a vertically incident HF signal the ionosphere reflects two magneto-ionic modes: the ordinary (O) mode and the extraordinary (X) mode. Their reflected polarizations have opposite chirality, which maps to opposite signs of PP. The exact sign that corresponds to O vs X depends on:
- The orientation of the local geomagnetic field (sign of the vertical component Bz), which flips between the northern and southern magnetic hemispheres.
- The physical layout and wiring of the receiver antenna array.
This module provides:
:class:PolarizationClassifier
Processor — labels each echo "O", "X", "ambiguous", or "unknown" by
thresholding PP and applying a configurable sign convention.
:class:PolarizationResult
Output dataclass — holds the annotated DataFrame and summary statistics.
References¶
Zabotin, N. A., Wright, J. W., & Zhbankov, G. A. (2006). NeXtYZ: Three- dimensional electron density inversion for Dynasonde and ARTIST ionosondes. Radio Science, 41, RS6S32.
Wright, J. W. & Pitteway, M. L. V. (1994). A numerical study of the estimation of the wave polarization in the ionospheric HF reflection region. Journal of Atmospheric and Terrestrial Physics, 56, 577-585.
PolarizationClassifier
¶
Classify ionospheric echoes as O-mode, X-mode, or ambiguous using PP.
The sign convention (which PP sign maps to O-mode) is station-specific and
must be supplied by the user or inferred from the geomagnetic dip angle.
The default (o_mode_sign=-1) applies to northern-hemisphere VIPIR
installations where negative PP corresponds to left-hand (ordinary) wave
polarization.
Parameters¶
o_mode_sign
-1 — negative PP → O-mode (northern hemisphere default).
+1 — positive PP → O-mode (southern hemisphere, or reversed layout).
pp_ambiguous_threshold_deg
Echoes with |PP| < threshold are labelled "ambiguous"
(near-linear polarization; neither mode dominates). Default 20.0.
pp_col
Name of the PP column in the input DataFrame.
Default "polarization_deg".
Examples¶
clf = PolarizationClassifier(o_mode_sign=-1) result = clf.fit(extractor.to_dataframe()) o_df = result.o_mode_df()
Source code in pynasonde/vipir/analysis/polarization.py
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 | |
infer_o_mode_sign(station_lat)
staticmethod
¶
Heuristic sign convention from station latitude.
In the Dynasonde / VIPIR convention the O-mode PP sign follows the sign of the vertical geomagnetic field component Bz. Bz is positive (downward) in the northern hemisphere and negative (upward) in the southern hemisphere. A rigorous determination requires IGRF, but for most mid-latitude stations this approximation is sufficient.
Parameters¶
station_lat
Geodetic latitude in decimal degrees (positive north).
Returns¶
int
-1 for northern hemisphere, +1 for southern hemisphere.
Source code in pynasonde/vipir/analysis/polarization.py
fit(df)
¶
Classify every echo in df by wave mode.
Parameters¶
df
Echo DataFrame produced by
:class:~pynasonde.vipir.riq.echo.EchoExtractor or
:class:~pynasonde.vipir.riq.parsers.filter.IonogramFilter.
Must contain a column named self.pp_col.
Returns¶
PolarizationResult Annotated DataFrame and count summary.
Raises¶
KeyError
If self.pp_col is not found in df.
Source code in pynasonde/vipir/analysis/polarization.py
PolarizationResult
dataclass
¶
O/X classification results for one ionogram sounding.
Parameters¶
annotated_df
Copy of the input echo DataFrame with a new "mode" column added.
Values are one of "O", "X", "ambiguous", "unknown".
o_mode_count
Number of echoes labelled O-mode.
x_mode_count
Number of echoes labelled X-mode.
ambiguous_count
Number of echoes whose |PP| fell below pp_ambiguous_threshold_deg
(near-linear polarization; mode cannot be determined reliably).
unknown_count
Number of echoes with NaN PP (fewer than min_rx_for_direction
receivers used in the spatial fit).
o_mode_sign
Sign convention used: +1 means positive PP → O-mode,
-1 means negative PP → O-mode.
pp_ambiguous_threshold_deg
|PP| threshold below which echoes were labelled "ambiguous".
Source code in pynasonde/vipir/analysis/polarization.py
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | |
to_dataframe()
¶
o_mode_df()
¶
x_mode_df()
¶
summary()
¶
One-line text summary of the classification.
Source code in pynasonde/vipir/analysis/polarization.py
plot(ax=None)
¶
Plot a PP histogram with O/X classification regions highlighted.
Parameters¶
ax
Existing :class:matplotlib.axes.Axes to draw into. A new
figure is created when None (default).
Returns¶
matplotlib.axes.Axes
Source code in pynasonde/vipir/analysis/polarization.py
PolarizationClassifier¶
Constructor¶
PolarizationClassifier(
o_mode_sign: int = -1, # -1 (NH default) or +1 (SH)
pp_ambiguous_threshold_deg: float = 20.0, # |PP| below this → "ambiguous"
pp_col: str = "polarization_deg",
)
Methods¶
| Method | Signature | Description |
|---|---|---|
fit |
fit(df) → PolarizationResult |
Classify all echoes in df |
infer_o_mode_sign |
infer_o_mode_sign(station_lat) → int |
Static helper: −1 for lat≥0, +1 for lat<0 |
Labels assigned¶
| Label | Condition |
|---|---|
"O" |
|PP| ≥ threshold and PP has the O-mode sign |
"X" |
|PP| ≥ threshold and PP has the X-mode sign |
"ambiguous" |
|PP| < threshold (near-linear polarization) |
"unknown" |
PP is NaN (fewer than min_rx_for_direction antennas used) |
Quick start¶
from pynasonde.vipir.analysis import PolarizationClassifier
# Infer sign from station latitude
sign = PolarizationClassifier.infer_o_mode_sign(station_lat=37.9) # → -1 (NH)
clf = PolarizationClassifier(o_mode_sign=sign, pp_ambiguous_threshold_deg=20.0)
result = clf.fit(echo_df)
print(result.summary())
# PolarizationResult: total=1842 O=743 X=698 ambiguous=201 unknown=200
# o_mode_sign=negative PP
# Extract mode subsets
o_df = result.o_mode_df() # O-mode echoes only
x_df = result.x_mode_df() # X-mode echoes only
all_df = result.to_dataframe() # full DataFrame with "mode" column added
# Plot PP histogram with O/X regions shaded
result.plot()
PolarizationResult dataclass¶
| Field | Type | Description |
|---|---|---|
annotated_df |
DataFrame |
Input df + new "mode" column ("O" / "X" / "ambiguous" / "unknown") |
o_mode_count |
int |
O-mode echo count |
x_mode_count |
int |
X-mode echo count |
ambiguous_count |
int |
Ambiguous echo count |
unknown_count |
int |
NaN-PP echo count |
o_mode_sign |
int |
Sign convention used (±1) |
pp_ambiguous_threshold_deg |
float |
Threshold applied |
Methods¶
result.summary() # one-line summary string
result.to_dataframe() # annotated_df copy
result.o_mode_df() # O-mode subset
result.x_mode_df() # X-mode subset
result.plot() # PP histogram with coloured O/X/ambiguous bands
References¶
- Zabotin, N. A., Wright, J. W., & Zhbankov, G. A. (2006). NeXtYZ. Radio Science, 41, RS6S32.
- Wright, J. W. & Pitteway, M. L. V. (1994). J. Atmos. Terr. Phys., 56, 577–585.
See Also¶
- Analysis Overview
- Absorption — uses mode labels for differential O/X absorption
- True Height Inversion — uses O-mode trace from
o_mode_df() - Ionogram Scaler — uses mode-labelled echoes for foF2 scaling