Tutorial

This tutorial demonstrates the key functionality of lisa-gap, focusing on the new proportional tapering capabilities built on top of lisaglitch.

Quick Start Example

Basic gap mask generation:

import numpy as np
from lisaglitch import GapMaskGenerator
from lisagap import GapWindowGenerator
from lisaconstants import TROPICALYEAR_J2000DAY

# Set up simulation properties
A_YEAR = TROPICALYEAR_J2000DAY * 86400
dt = 0.25  # seconds
t_obs = 0.5 * A_YEAR  # 6 months
sim_t = np.arange(0, t_obs, dt)

# Define realistic gap configuration
gap_definitions = {
    "planned": {
        "antenna repointing": {"rate_per_year": 26, "duration_hr": 3.3},
        "TM stray potential": {"rate_per_year": 2, "duration_hr": 24},
    },
    "unplanned": {
        "platform safe mode": {"rate_per_year": 3, "duration_hr": 60},
        "HR GRS loss micrometeoroid": {"rate_per_year": 19, "duration_hr": 24},
    }
}

# Create gap mask generator
gap_gen = GapMaskGenerator(sim_t, gap_definitions)

# Generate binary mask
mask = gap_gen.generate_mask(include_unplanned=True, include_planned=True)

Proportional Tapering

Apply smart tapering based on gap duration:

# Convert to quality flags and create mask
quality_flags = gap_gen.build_quality_flags(mask)
gap_mask = GapMaskGenerator.quality_flags_to_mask(quality_flags)

# Apply proportional tapering
tapered_mask = GapWindowGenerator.apply_proportional_tapering(
    gap_mask,
    dt=dt,
    short_taper_fraction=0.25,   # 25% each side for short gaps
    medium_taper_fraction=0.05,  # 5% each side for medium gaps
    long_taper_fraction=0.02,    # 2% each side for long gaps
    short_gap_threshold_minutes=30,  # <30 min = short
    long_gap_threshold_hours=2       # >2 hours = long
)

Extended Lobe Tapering

Create ultra-smooth transitions with extended lobes:

# Extended tapering with 2.5x gap width
extended_tapered = GapWindowGenerator.apply_proportional_tapering(
    gap_mask,
    dt=dt,
    medium_taper_fraction=0.1,
    lobe_extension_factor=2.5    # Taper window 2.5x gap width
)

This creates much longer, more gradual transitions extending beyond gap boundaries.

Data Segmentation

Split data into continuous segments for independent analysis:

from lisagap import DataSegmentGenerator

# Create sample data with gaps
sample_data = np.sin(2 * np.pi * 0.01 * sim_t) + 0.1 * np.random.randn(len(sim_t))

# Create segmenter using tapered mask
segmenter = DataSegmentGenerator(
    mask=tapered_mask,
    data=sample_data,
    dt=dt,
    t0=0.0
)

# Get basic segmentation info
summary = segmenter.summary()
print(f"Found {summary['total_segments']} continuous segments")
print(f"Data fraction valid: {summary['data_fraction_valid']:.2%}")

Advanced Segmentation with Edge Tapering

Apply edge tapering to prevent spectral artifacts at segment boundaries:

# Basic segmentation (preserves original data)
segments = segmenter.get_time_segments(apply_window=False)

# Apply windowing with existing mask tapering
windowed_segments = segmenter.get_time_segments(apply_window=True)

# Add edge tapering for frequency domain analysis
edge_tapered_segments = segmenter.get_time_segments(
    apply_window=True,
    left_edge_taper=1000,   # Taper first 1000 samples of first segment
    right_edge_taper=1500   # Taper last 1500 samples of last segment
)

Edge tapering uses one-sided Tukey windows to create smooth ramps:

  • Left edge: Ramps from 0 to 1 over specified samples on first segment only

  • Right edge: Ramps from 1 to 0 over specified samples on last segment only

  • Middle segments: Unaffected by edge tapering

  • Prevents spectral leakage: Essential for clean frequency domain analysis

Frequency Domain Analysis

Analyze segments in frequency domain with proper windowing:

# Get frequency information for all segments
freq_info = segmenter.get_freq_info_from_segments()

# Plot power spectra
import matplotlib.pyplot as plt

plt.figure(figsize=(12, 6))
for seg_name, seg_freq in freq_info.items():
    psd = np.abs(seg_freq['fft'])**2
    plt.loglog(seg_freq['frequencies'][1:], psd[1:],
               label=seg_name, alpha=0.8)

plt.xlabel('Frequency (Hz)')
plt.ylabel('Power Spectral Density')
plt.legend()
plt.show()

Integration Workflows

Create segmenters directly from gap generators:

# Integrated workflow
segmenter, reusable_mask = DataSegmentGenerator.from_gap_generator(
    gap_window_generator=window_gen,
    data=sample_data,
    dt=dt,
    apply_tapering=True  # Apply windowing during mask generation
)

This creates much longer, more gradual transitions extending beyond gap boundaries.

# Create gap mask generator gap_gen = GapMaskGenerator(

sim_t, dt, gap_definitions, treat_as_nan=False, # Treat as gating function (zeros for gap segment) use_gpu=False # Set to True for GPU acceleration

)

Traditional Windowing

For specific gap types, use traditional lobe-length tapering:

# Wrap with windowing capabilities
window_gen = GapWindowGenerator(gap_gen)

# Define custom tapering per gap type
taper_definitions = {
    "planned": {
        "antenna repointing": {"lobe_lengths_hr": 5.0},
        "TM stray potential": {"lobe_lengths_hr": 0.5},
    },
    "unplanned": {
        "platform safe mode": {"lobe_lengths_hr": 1.0},
        "HR GRS loss micrometeoroid": {"lobe_lengths_hr": 7.0},
    }
}

# Apply smooth tapering
smoothed_mask = window_gen.generate_window(
    include_planned=True,
    include_unplanned=True,
    apply_tapering=True,
    taper_definitions=taper_definitions
)

Save and Load

Save configurations for reproducible results:

# Save to HDF5
gap_gen.save_to_hdf5(mask, filename="gap_mask_data.h5")

# Load from HDF5
loaded_gen = GapMaskGenerator.from_hdf5("gap_mask_data.h5")
mask_copy = loaded_gen.generate_mask()

Complete Tutorial Notebook

See the complete notebook for detailed examples:

Key Advantages

Proportional Tapering Benefits:

  • Automatic categorization - Short, medium, long gaps handled differently

  • Proportional to gap duration - Larger gaps get more tapering

  • Configurable thresholds - Customize gap categories for your use case

  • Extended lobes - Ultra-smooth transitions for frequency analysis

Data Segmentation Benefits:

  • Independent analysis - Analyze each continuous segment separately

  • Preserves data integrity - No modification of original data

  • Edge tapering - Prevents spectral artifacts at boundaries

  • Frequency domain ready - Built-in FFT support with proper windowing

Edge Tapering Benefits:

  • Spectral cleanliness - Prevents leakage in frequency analysis

  • Boundary-specific - Only affects first and last segments

  • Tukey windowing - Optimal spectral properties with smooth transitions

  • Configurable length - User-defined taper samples for fine control

Compared to traditional windowing:

  • Smarter - Adapts to gap characteristics automatically

  • More flexible - Works with external .npy gap masks

  • Better for FFTs - Longer, smoother transitions reduce artifacts

  • Segmentation support - Clean separation for independent analysis

The notebook provides detailed examples showing these features in action.