A Python library for performance analysis and testing of Distributed Acoustic Sensing (DAS) interrogators, developed by SEAFOM's Measuring Sensor Performance group. This package provides standardized tools for testing, benchmarking, and performance evaluation of DAS systems following SEAFOM recommended procedures.
To promote transparency, consistency, and collaboration in the evaluation of DAS interrogator performance by providing open-source tools and standardized workflows.
https://seafom-fiber-optic-monitoring-group.github.io/pySEAFOM/
pip install pySEAFOM
from pySEAFOM import calculate_self_noise, plot_combined_self_noise_db
import numpy as np
# Load your DAS data (channels × time samples)
data = np.load('your_das_data.npy') # Shape: (n_channels, n_samples)
# Define test sections (channel ranges to analyze)
sections = [data[0:50, :], data[100:150, :]] # Two cable sections
section_names = ['Section A', 'Section B']
# Calculate self-noise for each section (using direct import)
results = calculate_self_noise(
sections,
interrogation_rate=10000, # Hz
gauge_length=10.0, # meters
window_function='blackman-harris',
data_type='pε' # picostrain
)
# OR using module import:
# results = pySEAFOM.self_noise.calculate_self_noise(
sections,
interrogation_rate=10000, # Hz
gauge_length=10.0, # meters
window_function='blackman-harris',
data_type='pε' # picostrain
)
# Visualize results
plot_combined_self_noise_db(
results=results,
test_sections=section_names,
gauge_length=10.0,
org_data_unit='pε',
title='DAS Self-Noise Test Results'
)
Self-noise analysis
Dynamic range analysis
Fidelity (THD) analysis
Crosstalk analysis
Frequency response analysis
Spatial resolution analysis
- Noise Floor: System noise characterization
Computes RMS amplitude spectral density across channels.
Parameters:
sections(list): List of 2D arrays (channels × samples) for each test sectioninterrogation_rate(float): Sampling frequency in Hzgauge_length(float): Gauge length in meterswindow_function(str): FFT window type ('blackman-harris', 'hann', 'none', etc.)data_type(str): Data unit ('pε', 'nε', 'rad', or custom)
Returns:
- List of tuples:
[(frequencies, asd), ...]for each section
Creates publication-quality self-noise plots.
Parameters:
results: Output fromcalculate_self_noise()test_sections(list): Section namesgauge_length(float): Gauge length in metersdata_unit(str): Display unittitle(str): Plot titlesampling_freq(float): Sampling rate (for metadata box)n_channels(int): Total channels (for metadata box)duration(float): Recording duration (for metadata box)
Prints formatted text report.
Loads one (or many) .npy files, builds a 2D matrix, and extracts a 1D trace at a chosen spatial position.
Parameters:
folder_or_file(str): Folder with.npyfiles or a single.npyfilefs(float): Sampling / interrogator rate in Hzdelta_x_m(float): Spatial step between channels [m]x1_m(float): Spatial window start [m]x2_m(float): Spatial window end [m]test_sections_channels(float): Position inside the spatial window [m]time_start_s(float): Analysis window start time [s]duration(float | None): Analysis window duration [s]average_over_cols(int): Number of adjacent channels to averagematrix_layout(str):'time_space','space_time', or'auto'
Returns:
(time_s, trace)where:time_sis a 1D time vector [s]traceis a 1D extracted signal
Optional unit conversion (phase to strain) and optional high-pass filtering for the extracted 1D trace.
Parameters:
trace(1D array): Input trace (phase [rad] or strain)data_is_strain(bool): If False, converts phase [rad] to microstrain [µε]gauge_length(float): Gauge length [m] (used for converting)highpass_hz(float | None): High-pass cutoff [Hz] (set None to disable)fs(float): Sampling rate [Hz] (required when high-pass is enabled)
Returns:
- 1D array: processed signal (microstrain [µε] if conversion is enabled)
` Hilbert envelope dynamic range test. Compares measured envelope vs theoretical envelope and triggers when the relative error exceeds a threshold.
Parameters:
-
time_s(1D array): Time vector [s] -
signal_microstrain(1D array): Trace in microstrain [µε] -
max_strain_microstrain(float): Final theoretical envelope amplitude [µε] -
ref_freq_hz(float): Expected sine frequency [Hz] -
smooth_window_s(float): Envelope smoothing window [s] -
error_threshold_frac(float): Relative error threshold (e.g., 0.3 = 30%) -
safezone_s(float): Initial safe zone where triggering is ignored [s] -
save_results(bool): Save figure + append CSV row -
radian_basis(float | None): If provided withgauge_length, reportspeak_over_basisas dB re rad/√Hz (computed from the peak of the last cycle converted from µε → rad). Otherwise the CSV field is empty and the metadata box omits it -
results_dir(str): Output directory
Outputs:
- Prints a formatted summary (trigger time, limit strain, etc.)
- Optional figure:
dynamic_range_hilbert.png - Optional CSV:
dynamic_range_hilbert.csv
Sliding THD dynamic range test. Computes THD in a moving window and triggers when THD exceeds a threshold for a minimum duration.
Parameters:
-
time_s(1D array): Time vector [s] -
signal_microstrain(1D array): Trace in microstrain [µε] -
ref_freq_hz(float): Expected fundamental frequency [Hz] -
window_s(float): Sliding window length [s] -
overlap(float): Window overlap fraction (e.g., 0.75 = 75%) -
thd_threshold_frac(float): THD threshold (e.g., 0.15 = 15%) -
median_window_s(float): Median smoothing window applied to the THD curve -
min_trigger_duration(float): Minimum continuous violation time to trigger [s] -
safezone_s(float): Initial safe zone where triggering is ignored [s] -
save_results(bool): Save figure + append CSV row -
radian_basis(float | None): If provided withgauge_length, reportspeak_over_basisas dB re rad/√Hz (computed from the peak of the last cycle converted from µε → rad). Otherwise the CSV field is empty and the metadata box omits it -
results_dir(str): Output directory
Outputs:
- Prints a formatted summary (trigger time, limit strain, etc.)
- Optional figure:
dynamic_range_thd.png - Optional CSV:
dynamic_range_thd.csv
Computes fidelity as THD (%) at a known stimulus frequency for a single pre-sliced spatial section, across one or more time “levels”.
Inputs (typical):
time_series_data(2D array): section matrix (channels_in_section × samples)fs(float): Sampling frequency [Hz]levels_time_steps(list[[start,end]] | [start,end]): Sample index range(s) per stimulus levelstimulus_freq(float): Fundamental frequency [Hz]snr_threshold_db(float): SNR gate used to accept FFT blockssection_name(str, optional): Label used in the report output
Returns:
- A structured dict with one section containing per-level THD and harmonic levels.
Prints a compact text summary of calculate_fidelity_thd() results.
Computes a crosstalk profile and maximum crosstalk for a single spatial section centered on the stimulation point.
Returns:
- A result dict containing:
crosstalk_db(1D array): dB relative to reference regionmax_xt_db(float): max crosstalk in the outer regionmagnitudes(1D array): linear magnitudes at stimulus frequencyreference_level(float): linear reference magnitude
Plots a crosstalk profile (dB vs distance).
Prints a compact text summary of calculate_crosstalk() results.
Loads one (or many) .npy files, builds a 2D matrix, and extracts a 1D trace at a chosen spatial position.
Parameters:
folder_or_file(str): Folder with.npyfiles or a single.npyfilefs(float): Sampling / interrogator rate in Hzdelta_x_m(float): Spatial step between channels [m]stretcher_start_m(float): Spatial window start [m]stretcher_end_m(float): Spatial window end [m]span_m(int): Number of adjacent channels to average [m]matrix_layout(str):'time_space','space_time', or'auto'
Returns:
(time_s, trace_raw, distance_m, local_pos_m)where:time_sis a 1D time vector [s]trace_rawis a 1D extracted signaldistance_mis the size of the stretcher in [m]local_pos_mis the central position of the stretcher in [m]
Optional unit conversion (phase to strain) and optional high-pass filtering for the extracted 1D trace.
Parameters:
trace(1D array): Input trace (phase [rad] or strain)data_is_strain(bool): If False, converts phase [rad] to microstrain [µε]gauge_length(float): Gauge length [m] (used for converting)highpass_hz(float | None): High-pass cutoff [Hz] (set None to disable)fs(float): Sampling rate [Hz] (required when high-pass is enabled)
Returns:
- 1D array: processed signal (microstrain [µε] if conversion is enabled)
` Frequency response test. Computes the DAS frequency response (FFT magnitude in dB re 1 µε) and the normalized frequency response over the step frequencies.
Parameters:
time_s(1D array): Time vector [s]signal_microstrain(1D array): Local trace in microstrain [µε]interrogation_rate_hz(float): Repetition / sampling rate [Hz]n_steps(int): Number of frequency stepsfreq_min_frac_nyq(float): Minimum frequency as a fraction of Nyquist (e.g., 0.02)freq_max_frac_nyq(float): Maximum frequency as a fraction of Nyquist (e.g., 0.80)window_spectrogram_s(float): Spectrogram window length [s] (local diagnostics)overlap_spectrogram_frac(float): Spectrogram overlap fraction (0.5 = 50%) (local diagnostics)save_results(bool): If True, saves figures + CSVresults_dir(str): Output directory
Outputs:
- Returns a dictionary with frequency arrays and dB curves
- Optional figure:
frequency_response_local_time_spectrogram_fft.png,frequency_response.pngandfrequency_response_normalized.png - Optional CSV:
frequency_response_normalized.csv
Loads one (or many) .npy files, builds a 2D matrix (concatenated along time), and extracts a spatial-temporal section for analysis.
Parameters:
folder_or_file(str): Folder with.npyfiles or a single.npyfilefs(float): Sampling / interrogator rate in Hzdelta_x_m(float): Spatial step between channels [m]x1_m(float): Spatial window start [m]x2_m(float): Spatial window end [m]time_start_s(float): Analysis window start time [s]duration(float | None): Analysis window duration [s]matrix_layout(str):'time_space','space_time', or'auto'
Returns:
(time_s, section_data)where:time_sis a 1D time vector [s]section_datais a 2D matrix(n_time, n_space)representing the extracted section
Optional unit conversion (phase to strain) and optional high-pass filtering for the extracted data.
Parameters:
data(2D array): Input data (phase [rad] or strain)data_is_strain(bool): If False, converts phase [rad] to microstrain [µε]gauge_length(float): Gauge length [m] (used for conversion)highpass_hz(float | None): High-pass cutoff [Hz] (set None to disable)fs(float): Sampling rate [Hz] (required when high-pass is enabled)
Returns:
- 2D array: processed data (microstrain [µε] if conversion is enabled)
Estimates the spatial resolution from the spatial amplitude profile at a reference frequency.
Parameters:
section_data(2D array): Input matrix(n_ssl, n_samples)(space × time)fs(float): Sampling rate [Hz]delta_x_m(float): Spatial step [m]ref_freq_hz(float): Reference stimulus frequency [Hz]fft_size(int): FFT block sizesnr_threshold_db(float): Recommended minimum SNRtarget_pos_m(float): Expected stretcher position [m]save_results(bool): Save figures + CSV summaryresults_dir(str): Output directory
Outputs:
- Returns a summary that includes:
- detected peak position
- SNR
LL(left slope width)LR(right slope width)- spatial resolution (mean of
LLandLR)
- Optional figures:
spatiotemporal_map.pngspatial_resolution_profile.png
- Optional CSV:
spatial_resolution_summary.csv
We welcome contributions from researchers, engineers, and developers working in the fiber optic sensing space. Please see our contribution guidelines to get started.
This project is licensed under the MIT License — see the LICENSE file for details.
This repository follows the SEAFOM Governance Policy.
