Skip to content

Gani332/visual-wind-sensor

Repository files navigation

Visual Wind Sensor

This repo contains the cleaned version of our camera-and-flag wind-speed sensor project.

Built as a group project by Riyaadh Gani, Omar Sayed, and Adrian Pailler.

The Idea

Wind is invisible, so the sensor watches something the wind can move.

The pipeline is:

camera frames
-> Lucas-Kanade point tracking
-> RMS motion feature
-> calibration against reference sensor
-> Kalman smoothing
-> wind-speed estimate

The important bit is that the camera is not trying to understand the exact flag shape. It is measuring how energetic the flag motion is over time, then using calibration to translate that visual motion into metres per second.

What This Clean Repo Contains

  • Reproducible calibration and validation code.
  • Raw logs copied from the original coursework repo.
  • A timestamp merge step that pairs Pi sensor output with the reference sensor.
  • Chronological train/holdout validation.
  • Generated CSV, JSON, and plot outputs.
  • Optional realtime Lucas-Kanade camera code for the Raspberry Pi/camera setup.

The old repo also had empty calibration CSVs, generated caches, debug scripts, and rolling-shutter experiments. Those were intentionally left out because they made the final result harder to inspect.

Install

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install -e .

Reproduce The Validation

python scripts/run_validation.py

This writes:

  • results/paired_validation.csv
  • results/validation_predictions.csv
  • results/metrics.json
  • results/calibration_scatter.png
  • results/time_series_validation.png
  • results/error_over_time.png

You can also run the module directly:

python -m wind_sensor.calibration \
  --pi-log data/raw/pi_log.csv \
  --gt-log data/raw/gt_log.csv \
  --output-dir results

Validation Results

The included validation reconstructs 1,676 paired rows by aligning:

  • data/raw/pi_log.csv
  • data/raw/gt_log.csv

The split is chronological: first 70% for calibration, last 30% for holdout. No random shuffling.

Model Holdout RMSE Holdout MAE Holdout R2
Linear + Kalman 1.639 m/s 1.057 m/s 0.682
Quadratic + Kalman 0.958 m/s 0.854 m/s 0.891
Cubic + Kalman 1.254 m/s 1.048 m/s 0.814
Logarithmic + Kalman 1.195 m/s 0.799 m/s 0.831

On this included holdout, the quadratic + Kalman model gives the lowest RMSE. The logarithmic + Kalman model is also included because it captures saturation with a simpler curve and is useful when you want a more conservative model.

The full-dataset fits reproduce the coefficients used in the original code comments:

cubic:       0.0186*rms^3 - 0.5154*rms^2 + 3.9319*rms - 0.4072
logarithmic: 2.3969*ln(rms) + 3.9180

Run The Live Sensor

The live sensor needs a camera and OpenCV GUI support. On the Raspberry Pi, Picamera2 is used when available; otherwise the script falls back to an OpenCV camera.

python -m wind_sensor.realtime --method log_kalman --output-dir results

Use an OpenCV camera explicitly:

python -m wind_sensor.realtime --opencv-camera --method log_kalman

With a serial reference sensor:

python -m wind_sensor.realtime --gt-port /dev/ttyACM0

Caveats

This is controlled validation, not proof that the sensor works everywhere. Lighting, camera angle, marker quality, flag material, low wind speeds, and high wind saturation all matter.

The useful claim is narrower:

in a controlled setup, a cheap camera and marked flag can produce a meaningful wind-speed estimate when motion is tracked, calibrated, and filtered properly.

Project Notes

The methodology write-up is in docs/methodology.md.

Credits are in CREDITS.md.

About

Camera-and-flag wind-speed estimation using Lucas-Kanade optical flow, calibration, and filtering.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages