Vortex Event Reactive Sensor Algorithm
VERSA is an onboard detection system designed to enable resource-efficient autonomous monitoring of Martian convective vortices (dust devils) for small spacecraft missions. This codebase enables systems using low-resource pressure sensor data to detect transient vortex encounters, allowing future high-resource instruments (cameras, wind sensors, etc.) to collect data only when phenomena of interest occur.
This repository implements and evaluates four distinct detection approaches—ranging from simple statistics-based methods to deep learning models—to understand the tradeoffs between algorithm complexity, computational requirements, and science return.
The typical processing chain involves:
- Collecting raw pressure sensor data from the Mars 2020 MEDA instrument and known vortex encounters from previous analysis (Jackson, 2022)
- Generating ML-ready training data with labeled vortex events
- Training and evaluating detection algorithms to quantify the balance between science captured versus onboard resources consumed
- Investigating the tradeoff between estimated resource usage (power and data volume) against estimated science return
MEDA data is available online from the PDS https://pds-atmospheres.nmsu.edu/PDS/data/PDS4/Mars2020/mars2020_meda/data_derived_env/
Known vortex encounters are available online from Jackson, 2022: https://iopscience.iop.org/article/10.3847/PSJ/ac4586
python ~/Builds/versa/versa/mlready_processing.py \
--compiled_meda_save_fpath ~/Data/versa/meda/compiled_meda.csv \
--vortex_detections_fpath ~/Data/versa/meda/Jackson_vortex_detections_reformatted.txt \
--ml_ready_output_fpath ~/Data/versa/meda/ml_ready_vortex_data.csv \
--vortex_detections_output_fpath ~/Data/versa/meda/Jackson_vortex_detections_reformatted_augmented.csv \
--nrows_meda 3590168
First, we sweep over a set of hyperparameters (in the config) to see which parameters give the best performance per detector.
# Current batch run scripts
# Ray Static Probabilistic Distribution
python ${BUILDS}/versa/versa/run_ray_detector_hpo_v2.py \
--model_type 'dist_fit'
# Ray Adaptive Probabilistic Distribution
python ${BUILDS}/versa/versa/run_ray_detector_hpo_v2.py \
--model_type 'adaptive_dist_fit'
# Ray RNNs
python ${BUILDS}/versa/versa/run_ray_detector_hpo_v2.py \
--model_type 'RNN'
# Ray Transformer
python ${BUILDS}/versa/versa/run_ray_detector_hpo_v2.py \
--model_type 'transformer'
Review the results via tensorboard
# Port forward tensorboard
tensorboard --logdir=/path/to/hpo_run
After we have the best hyperparameters, we use the entire training dataset to generate one mode, and then evaluate with the held out test set.
DIST_NAME='norm'
PROB_THRESH=0.98
EVENT_WINDOW_COOLDOWN=180
python /Users/wronk/Builds/versa/versa/detectors/simple_threshold_v2.py \
--ml_ready_data_fpath ~/Data/versa/meda/ml_ready_vortex_data.csv \
--test_results_save_fpath /Users/wronk/Data/versa/mlruns/delete_me/static_dist_${DIST_NAME}_test_results.csv \
--dist_name ${DIST_NAME} \
--prob_thresh ${PROB_THRESH} \
--only_neg_deflections \
--verbose
PROB_THRESH=0.98
python /Users/wronk/Builds/versa/versa/eval/eval_trial_v2.py \
--test_results_save_fpath /Users/wronk/Data/versa/mlruns/delete_me/static_dist_${DIST_NAME}_test_results.csv \
--events_save_fpath /Users/wronk/Data/versa/mlruns/delete_me/static_dist_${DIST_NAME}_prob_${PROB_THRESH}_cooldown_${EVENT_WINDOW_COOLDOWN}_eval.csv \
--plots_save_fpath /Users/wronk/Data/versa/mlruns/delete_me/static_dist_${DIST_NAME}_prob_${PROB_THRESH}_cooldown_${EVENT_WINDOW_COOLDOWN}_autonomous_detections_plots.png \
--det_save_fpath /Users/wronk/Data/versa/mlruns/delete_me/static_dist_${DIST_NAME}_prob_${PROB_THRESH}_cooldown_${EVENT_WINDOW_COOLDOWN}_det.png \
--autonomous_event_csv_dir /Users/wronk/Data/versa/mlruns/delete_me/static_dist_${DIST_NAME}_prob_${PROB_THRESH}_cooldown_${EVENT_WINDOW_COOLDOWN}_autonomous_events \
--timing_plot_save_fpath /Users/wronk/Data/versa/mlruns/delete_me/static_dist_${DIST_NAME}_prob_${PROB_THRESH}_cooldown_${EVENT_WINDOW_COOLDOWN}_detection_timing.png \
--prob_thresh ${PROB_THRESH} \
--event_window_cooldown ${EVENT_WINDOW_COOLDOWN}
PROB_THRESH=0.999975
WINDOW_SIZE=1000
TIME_SERIES_COL='PRESSURE'
MIN_VALID_DATA_POINTS=60
ADAPT_INTERVAL=1
EVENT_WINDOW_COOLDOWN=180
python /Users/wronk/Builds/versa/versa/detectors/adaptive_threshold_v1.py \
--ml_ready_data_fpath ~/Data/versa/meda/ml_ready_vortex_data.csv \
--test_results_save_fpath /Users/wronk/Data/versa/mlruns/results/adaptive_dist_v2/adaptive_dist_window_size_${WINDOW_SIZE}_min_pts_${MIN_VALID_DATA_POINTS}_col_${TIME_SERIES_COL}_adaptive_interval_${ADAPT_INTERVAL}_test_results.csv \
--prob_thresh ${PROB_THRESH} \
--window_size ${WINDOW_SIZE} \
--min_valid_data_points ${MIN_VALID_DATA_POINTS} \
--time_series_col ${TIME_SERIES_COL} \
--adapt_interval ${ADAPT_INTERVAL} \
--detrend \
--only_neg_deflections \
--verbose
PROB_THRESH=0.9985
python ~/Builds/versa/versa/eval/eval_trial_v2.py \
--test_results_save_fpath ~/Data/versa/mlruns/results/adaptive_dist_v2/adaptive_dist_window_size_${WINDOW_SIZE}_min_pts_${MIN_VALID_DATA_POINTS}_col_${TIME_SERIES_COL}_adaptive_interval_${ADAPT_INTERVAL}_test_results.csv \
--events_save_fpath ~/Data/versa/mlruns/results/adaptive_dist_v2/adaptive_dist_prob_thresh_${PROB_THRESH}_window_size_${WINDOW_SIZE}_min_pts_${MIN_VALID_DATA_POINTS}_col_${TIME_SERIES_COL}_adaptive_interval_${ADAPT_INTERVAL}_eval.csv \
--plots_save_fpath ~/Data/versa/mlruns/results/adaptive_dist_v2/adaptive_dist_prob_thresh_${PROB_THRESH}_window_size_${WINDOW_SIZE}_min_pts_${MIN_VALID_DATA_POINTS}_col_${TIME_SERIES_COL}_adaptive_interval_${ADAPT_INTERVAL}.png \
--timing_plot_save_fpath ~/Data/versa/mlruns/results/adaptive_dist_v2/adaptive_dist_prob_thresh_${PROB_THRESH}_window_size_${WINDOW_SIZE}_min_pts_${MIN_VALID_DATA_POINTS}_col_${TIME_SERIES_COL}_adaptive_interval_${ADAPT_INTERVAL}_detection_timing.png \
--autonomous_event_csv_dir ~/Data/versa/mlruns/results/adaptive_dist_v2/adaptive_dist_prob_thresh_${PROB_THRESH}_window_size_${WINDOW_SIZE}_min_pts_${MIN_VALID_DATA_POINTS}_col_${TIME_SERIES_COL}_adaptive_interval_${ADAPT_INTERVAL}_autonomous_events \
--prob_thresh ${PROB_THRESH} \
--event_window_cooldown ${EVENT_WINDOW_COOLDOWN} \
--plot_input_column "PRESSURE"
RNN_TYPE=LSTM
PROB_THRESH=0.94
EVENT_WINDOW_COOLDOWN=180
python ~/Builds/versa/versa/detectors/rnn_v2.py \
--ml_ready_data_fpath ~/Data/versa/meda/ml_ready_vortex_data.csv \
--prob_thresh ${PROB_THRESH} \
--epochs 25 \
--rnn_type ${RNN_TYPE} \
--rnn_size 32 \
--dropout 0.037 \
--recurrent_dropout 0.23 \
--output_activation sigmoid \
--batch_size 2048 \
--learning_rate 0.0035 \
--training_proportion 0.8 \
--test_results_save_fpath ~/Data/versa/mlruns/delete_me/${RNN_TYPE}_test_results.csv \
--config_save_fpath ~/Data/versa/mlruns/delete_me/${RNN_TYPE}_config.json \
--model_save_fpath ~/Data/versa/mlruns/delete_me/${RNN_TYPE}_model.keras \
--verbose 2
PROB_THRESH=0.94
python ~/Builds/versa/versa/eval/eval_trial_v2.py \
--test_results_save_fpath ~/Data/versa/mlruns/results/lstm_v3/${RNN_TYPE}_test_results.csv \
--events_save_fpath ~/Data/versa/mlruns/results/lstm_v3/${RNN_TYPE}_prob_${PROB_THRESH}_cooldown_${EVENT_WINDOW_COOLDOWN}_eval.csv \
--timing_plot_save_fpath ~/Data/versa/mlruns/results/lstm_v3/${RNN_TYPE}_prob_${PROB_THRESH}_cooldown_${EVENT_WINDOW_COOLDOWN}_detection_timing.png \
--autonomous_event_csv_dir ~/Data/versa/mlruns/results/lstm_v3/${RNN_TYPE}_prob_${PROB_THRESH}_cooldown_${EVENT_WINDOW_COOLDOWN}_autonomous_events \
--plots_save_fpath ~/Data/versa/mlruns/results/lstm_v3/${RNN_TYPE}_prob_${PROB_THRESH}_cooldown_${EVENT_WINDOW_COOLDOWN}_autonomous_detections_plots.png \
--prob_thresh ${PROB_THRESH} \
--event_window_cooldown ${EVENT_WINDOW_COOLDOWN}
PROB_THRESH=0.94
EVENT_WINDOW_COOLDOWN=180
python ~/Builds/versa/versa/detectors/transformer_v3.py \
--ml_ready_data_fpath ~/Data/versa/meda/ml_ready_vortex_data.csv \
--prob_thresh ${PROB_THRESH} \
--epochs 25 \
--num_heads 1 \
--d_model 16 \
--dff 16 \
--dropout 0.05 \
--pooling avg \
--batch_size 8192 \
--learning_rate 0.0008 \
--label_column "gt_4xfwhm" \
--window_length 60 \
--training_proportion 0.8 \
--test_results_save_fpath ~/Data/versa/mlruns/delete_me_run4/transformer_test_results.csv \
--config_save_fpath ~/Data/versa/mlruns/delete_me_run4/transformer_config.json \
--model_save_fpath ~/Data/versa/mlruns/delete_me_run4/transformer_model.keras \
--verbose 2
PROB_THRESH=0.94
EVENT_WINDOW_COOLDOWN=180
python ~/Builds/versa/versa/eval/eval_trial_v2.py \
--test_results_save_fpath ~/Data/versa/mlruns/results/transformer_v4/transformer_test_results.csv \
--events_save_fpath ~/Data/versa/mlruns/results/transformer_v4/transformer_prob_${PROB_THRESH}_cooldown_${EVENT_WINDOW_COOLDOWN}_eval.csv \
--timing_plot_save_fpath ~/Data/versa/mlruns/results/transformer_v4/transformer_prob_${PROB_THRESH}_cooldown_${EVENT_WINDOW_COOLDOWN}_detection_timing.png \
--autonomous_event_csv_dir ~/Data/versa/mlruns/results/transformer_v4/transformer_prob_${PROB_THRESH}_cooldown_${EVENT_WINDOW_COOLDOWN}_autonomous_events \
--plots_save_fpath ~/Data/versa/mlruns/results/transformer_v4/transformer_prob_${PROB_THRESH}_cooldown_${EVENT_WINDOW_COOLDOWN}_autonomous_detections_plots.png \
--prob_thresh ${PROB_THRESH} \
--event_window_cooldown ${EVENT_WINDOW_COOLDOWN}