Skip to main content

A package for cross-checking radargram layers using dot product similarity.

Project description

XCheck — Consistency-Based Validation of Englacial Layer Annotations

A Python implementation of the radargram layer-matching framework from:

Hassan, Muhammad Behroze; Tama, Bayu Adhi; Purushotham, Sanjay; Janeja, Vandana P. XCheck: A Consistency-Based Validation Framework for Englacial Layers Annotations. https://par.nsf.gov/biblio/10673248 · DOI: 10.1109/ICDMW69685.2025.00015

XCheck validates whether annotated englacial layers are consistent between two radargrams that observe the same ice — either two consecutive flight segments (overlap found automatically via GPS time) or two intersecting flight paths (crossing point supplied via a CSV).


Features

  • GPS Overlap Detection: Automatically finds temporally overlapping segments between two radargrams using log-transformed GPS timestamps.
  • Data Loading & Masking: Loads .mat radargram and ground truth layer files and converts annotated layers into binary depth masks.
  • Geometric Alignment: Adjusts radargram columns by surface elevation before comparison to correct for topographic variation.
  • Layer Continuity Matching: Dot-product similarity algorithm that identifies corresponding layers between two radargrams at their crossing or overlap point.
  • Flexible Input: Accepts a single radargram pair via CLI flags, a batch CSV of pairs, or a pre-computed intersections CSV.
  • Visualization: Map plots of GPS overlap regions and side-by-side mask views with matched layer annotations.

Installation

pip install xcheck

NDH_PythonTools (required)

XCheck uses NDH_PythonTools for .mat file loading and radar data processing. Because that repository is not a standard pip package, it must be installed manually:

git clone https://github.com/nholschuh/NDH_PythonTools.git

Then add its parent directory to PYTHONPATH before running xcheck:

# Linux / macOS
export PYTHONPATH="/path/to/parent/of/NDH_PythonTools"

# Windows PowerShell
$env:PYTHONPATH = "C:\path\to\parent\of\NDH_PythonTools"

Quick Start

Layer matching only (no NDH_PythonTools needed)

import numpy as np
from xcheck import match_layers_with_dot_product

m1 = np.zeros((6, 5)); m1[[1, 3, 5], :] = 1
m2 = np.zeros((6, 5)); m2[[1, 3, 5], :] = 1

matches = match_layers_with_dot_product(m1, m2, max_distance=1,
                                        window_size=3, dp_threshold=1)
print(matches)  # [(1, 1), (3, 3), (5, 5)]

Python API (requires NDH_PythonTools + data)

from xcheck import (
    load_and_process_radargram,
    load_log_gps_time,
    find_overlapping_intervals,
    extract_and_adjust_mask_columns_for_location,
    match_layers_with_dot_product,
)

# Load two consecutive radargrams
r1, m1, d1 = load_and_process_radargram("Data_20120429_01_026.mat",
                                         layer_dir="./Nick-layer-data-mat/",
                                         radar_dir="./Nick-raw-radargram-mat/")
r2, m2, d2 = load_and_process_radargram("Data_20120429_01_027.mat",
                                         layer_dir="./Nick-layer-data-mat/",
                                         radar_dir="./Nick-raw-radargram-mat/")

# Find GPS overlap and derive crossing point from midpoint
import numpy as np
log_t1 = load_log_gps_time("./Nick-raw-radargram-mat/Data_20120429_01_026.mat")
log_t2 = load_log_gps_time("./Nick-raw-radargram-mat/Data_20120429_01_027.mat")
overlaps1, overlaps2 = find_overlapping_intervals(log_t1, log_t2)

for iv1, iv2 in zip(overlaps1, overlaps2):
    mid1 = (iv1[0] + iv1[1]) // 2
    mid2 = (iv2[0] + iv2[1]) // 2
    mc1 = extract_and_adjust_mask_columns_for_location(
        r1['Longitude'][mid1], r1['Latitude'][mid1], r1, m1, d1, 20)
    mc2 = extract_and_adjust_mask_columns_for_location(
        r2['Longitude'][mid2], r2['Latitude'][mid2], r2, m2, d2, 20)
    matches = match_layers_with_dot_product(mc1, mc2)
    print(f"Matched layers: {matches}")

CLI

Single pair — consecutive (no crossing CSV needed)

xcheck --r1 Data_20120429_01_026.mat --r2 Data_20120429_01_027.mat \
       --layer_dir ./Nick-layer-data-mat/ \
       --radar_dir ./Nick-raw-radargram-mat/

Single pair — intersecting (crossing looked up from CSV)

xcheck --r1 Data_20120330_01_004.mat --r2 Data_20120511_01_054.mat \
       --intersections_csv ./Intersections_2012.csv \
       --layer_dir ./Nick-layer-data-mat/ \
       --radar_dir ./Nick-raw-radargram-mat/

Single pair — intersecting with explicit crossing coordinates

xcheck --r1 Data_20120330_01_004.mat --r2 Data_20120511_01_054.mat \
       --lat 78.909416 --lon -61.804612 \
       --layer_dir ./Nick-layer-data-mat/ \
       --radar_dir ./Nick-raw-radargram-mat/

Batch mode (all pairs in a CSV)

xcheck --intersections_csv ./Intersections_2012.csv \
       --layer_dir ./Nick-layer-data-mat/ \
       --radar_dir ./Nick-raw-radargram-mat/

All CLI arguments

Argument Default Description
--r1, --r2 Single-pair mode: filenames of the two radargrams
--lat, --lon Crossing coordinates for single-pair mode
--csv_path Batch CSV with columns Radargram 1, Radargram 2, Latitude, Longitude
--intersections_csv Pre-computed intersections CSV (used alone or to look up coordinates)
--layer_dir required Directory of layer .mat files
--radar_dir required Directory of raw radargram .mat files
--layer_prefix Layer_ Filename prefix for layer files
--cols_side 20 / 3 Columns extracted each side of crossing (consecutive / non-consecutive)
--max_distance 4 / 3 Max depth-pixel gap between candidate layer rows
--window_size 7 / 3 Dot product window width (must be odd)
--dp_threshold 4 / 1 Minimum dot product score to confirm a match
--plot_overlaps off Plot GPS overlap regions on a map

Default pairs shown as consecutive / non-consecutive.


Default thresholds by radargram type

Parameter Consecutive Non-consecutive
cols_side 20 (41 columns) 3 (7 columns)
max_distance 4 px 3 px
window_size 7 3
dp_threshold 4 1

These are selected automatically. Override any of them via CLI flags.


Methodological note

The GPS overlap detection compares log(GPS_time) between two radargrams with an absolute tolerance of 1e-8. Because d(log t) ≈ dt/t and GPS times are ~1×10⁹ seconds, this tolerance corresponds to matching raw timestamps within roughly 10 seconds. Consecutive flight segments (e.g. _026.mat_027.mat) share a small tail/head of overlapping traces, which is where the crossing point is derived. Non-consecutive intersecting radargrams do not share GPS timestamps; their crossing point must be supplied via --intersections_csv or --lat/--lon.


Project structure

src/xcheck/
  xcheck.py      Core algorithms: loading, masking, GPS overlap,
                 column extraction, layer matching, plotting, CLI
  __init__.py    Public API exports
pyproject.toml   Build metadata and dependencies
README.md

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xcheck-0.1.0.tar.gz (11.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xcheck-0.1.0-py3-none-any.whl (9.4 kB view details)

Uploaded Python 3

File details

Details for the file xcheck-0.1.0.tar.gz.

File metadata

  • Download URL: xcheck-0.1.0.tar.gz
  • Upload date:
  • Size: 11.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.9

File hashes

Hashes for xcheck-0.1.0.tar.gz
Algorithm Hash digest
SHA256 565422afeb4baf43ac2e0b8ff426152d1493b72c126f5993974839890f8208ab
MD5 acf0f87068869062683a986205ec700a
BLAKE2b-256 2a9b19c482b9f0c655e7f3bff67846bdc02971851b136d30389118d5d0ec486b

See more details on using hashes here.

File details

Details for the file xcheck-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: xcheck-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 9.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.9

File hashes

Hashes for xcheck-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6b7f9d946bc8056692f4f197b8326c38f779474e0441c0f4470fa0d9495d76aa
MD5 a79ebbda8d5cee78ca909816a775660e
BLAKE2b-256 a07ab7d4aa02f3f13c6a99e63256f4c102890ee78b5ede31d6ae0946dba42c53

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page