Skip to content

Latest commit

 

History

History
78 lines (51 loc) · 8.96 KB

File metadata and controls

78 lines (51 loc) · 8.96 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

What this is

Educational materials for applied signal processing and time-series classification in HCI / ubiquitous computing (a University of Washington course, part of the Makeability Lab "physcomp" curriculum). The artifacts are Jupyter notebooks backed by small supporting Python packages. There is no build; work is done interactively in notebooks. Tests do exist (added after the v2 modernization): pytest unit tests for the helper packages plus nbmake headless notebook smoke tests, run in GitHub Actions CI — see the Testing section below. The tests live entirely outside the .ipynb files (nothing was added inside the notebooks).

Top-level layout:

  • Tutorials/ — standalone teaching notebooks (NumPy, Matplotlib, Python, and signals: sampling/quantization, frequency analysis, comparing signals). Supported by the makelab/ package.
  • Projects/GestureRecognizer/ — accelerometer gesture classification. The most substantial project; supported by the gesturerec/ package.
  • Projects/StepTracker/ — step-counting from accelerometer data (a single teaching notebook, StepTracker-Exercises.ipynb, that keeps the exercise prompts and shows worked "Example solution" cells).
  • Per issue #6, the published notebooks are now complete teaching artifacts: each keeps its exercise prompt / "your turn" framing but adds a clearly-labeled ### Example solution (markdown heading + worked code) immediately below, so the notebook runs top-to-bottom and serves as both lesson and answer key. New graded assignments are authored separately. (Historically there was an *-Exercises.ipynb / *-WithExampleSolution.ipynb / *-Private.ipynb split; the StepTracker pair has been consolidated, and *-Private.ipynb files remain gitignored.)

Running

Setup (Python 3.12; see README.md): python -m venv .venv → activate → pip install -r requirements.txt. This also installs the repo itself editable (pip install -e .), which is what makes the helper packages importable.

The two helper packages (makelab in Tutorials/makelab/, gesturerec in Projects/GestureRecognizer/gesturerec/) are mapped to top-level import names by the root pyproject.toml, so after the editable install they import from any working directory, no sys.path hacks:

import gesturerec.data as grdata
import makelab.signal

However, data loading is still CWD-relative. Notebooks use paths like ./GestureLogs, ./Logs, and data/audio/..., so a notebook's kernel must run with its own folder as the working directory (JupyterLab/VS Code do this automatically; nbconvert --execute does too). Don't "fix" those into absolute paths — they must stay repo-relative to work in Colab/Binder (textbook contract).

Pinned dependencies live in requirements.txt / environment.yml: NumPy, SciPy, scikit-learn, pandas, Matplotlib, seaborn, librosa, JupyterLab. The .venv/ and a registered signals Jupyter kernel are local-only (gitignored).

Notebook files contain non-ASCII characters (arrows, curly quotes). When parsing a .ipynb with a script, open as UTF-8 and run Python with PYTHONUTF8=1 — the default Windows cp1252 codec will raise UnicodeDecodeError.

Testing

Install the test stack with pip install -e ".[test]" (pytest + nbmake + pytest-xdist). Two layers, both outside the notebooks:

  • Unit tests (tests/): pure-function tests for the helper packages — makelab.signal, gesturerec.signalproc/utility/data/experiments. Run with pytest tests/. tests/fixtures/TestGestures/ is a tiny synthetic gesture corpus (3 trial CSVs + a *_fulldatastream_* exclusion file) so the data.py parser tests don't depend on the large real GestureLogs/. It deliberately includes a Midair Zorro _Z__*.csv file to exercise the Windows double-underscore filename quirk.
  • Notebook smoke tests (nbmake): pytest --nbmake <paths> executes notebooks headless and fails on any uncaught error. Intentional teaching errors are already tagged raises-exception (notebooks 2 and 5) and are honored — no notebook edits needed. nbmake runs each notebook in its own dir, so the CWD-relative data loads work.

[tool.pytest.ini_options].testpaths = ["tests"] keeps a bare pytest fast and notebook-free; the notebook sweeps are invoked explicitly by path. CI (.github/workflows/) runs units + the fast notebooks (Tutorials + StepTracker) on every push/PR; the slow gesture notebooks run only when a change touches them (Projects/GestureRecognizer/** or the deps), plus a monthly drift-canary cron and on-demand (workflow_dispatch). If you add a helper function, add a unit test; if a dependency bump breaks a notebook, the nbmake job is what catches it (this automates the manual Pass 2–4 "Restart & Run All" sweeps).

gesturerec architecture (Projects/GestureRecognizer)

This package abstracts the data loading and experiment bookkeeping so notebook code can focus on the classification algorithm itself. The data flow is:

Raw logs → data structures → classifier → results.

Data structures (gesturerec/data.py):

  • SensorData — one sensor's signal as parallel NumPy arrays (time, sensor_time, x, y, z, plus computed mag). Holds *_p placeholders for processed (filtered) versions produced by notebook preprocessing. Also exposes sampling_rate and length_in_secs.
  • Trial — one recorded gesture (a single CSV). The constructor parses the CSV (np.genfromtxt) and builds the SensorData. Each trial knows its ground-truth gesture_name.
  • GestureSet — all trials for one participant, loaded from a directory of CSVs. Usage is always construct → load() → preprocess in the notebook. Filenames encode GestureName_endTimeMs_numRows.csv; trials are ordered by end-timestamp. Note the Windows quirk: Windows replaced ' in gesture names with _, producing __ double-underscore filenames, which the parser special-cases.
  • Module-level get_gesture_set* / get_all_gesture_sets* helpers operate on a map of gesture-set-name → GestureSet (one entry per participant directory under GestureLogs/).

Experiment bookkeeping (gesturerec/experiments.py):

  • TrialClassificationResult — result of classifying one test trial: holds the n-best list of (template_trial, score) tuples sorted by score, the chosen closest_trial, and is_correct.
  • ClassificationResults — aggregates results for a whole experiment: accuracy, per-gesture correctness, confusion matrix (via scikit-learn), n-best-list performance curves, timing. This is the object a matching algorithm returns.
  • Experiments — a collection of ClassificationResults, sortable by accuracy / compute time, for comparing approaches.

Two classification paradigms are taught (each in its own notebook), both running over gesturerec data structures:

  • Shape-based (GestureRecognizer-ShapeBased.ipynb) — template/similarity matching between time-series (e.g. Euclidean / DTW-style distance) on pre-segmented trials.
  • Feature-based (GestureRecognizer-FeatureBased.ipynb, Feature Selection and Hyperparameter Tuning.ipynb) — extract features (mean, variance, dominant frequency, …) and train a scikit-learn model (SVM in a StandardScaler→classifier Pipeline), evaluated with StratifiedKFold cross-validation.

Other modules:

  • gesturerec/signalproc.pycompute_fft and get_top_n_frequency_peaks, the shared FFT/feature primitives.
  • gesturerec/gesturestream.pyGestureStream (the full continuous fulldatastream.csv for offline segmentation work, vs. the pre-segmented per-trial CSVs) and Event (a segment cut from that stream). GestureStream.load() auto-cleans malformed rows, renaming the original to *_old_<ms>.csv and rewriting a cleaned file.
  • gesturerec/vis.py — plotting helpers (plot_confusion_matrix, signal plots).
  • gesturerec/utility.py — file-handling helpers; find_csv_filenames deliberately excludes files containing fulldatastream so trial loading and stream loading don't collide.

Two data corpora exist: GestureLogs/ (per-participant *Gestures/ dirs, the primary set) and ADXL335GestureLogs/ (an alternate sensor). Notebooks switch between them by changing root_gesture_log_path.

makelab (Tutorials)

makelab/signal.py and makelab/audio.py provide signal-generation and analysis helpers (sine/cosine generators, FFT, distance metrics, audio via librosa) used by the tutorial notebooks. Same import rule: run notebooks from Tutorials/.

Conventions

  • Code is written to be read by students — verbose docstrings, inline citations to Stack Overflow / library docs, and explanatory comments are intentional. Match that style; don't strip the pedagogy.
  • Loaders are tolerant of messy real-world logs (anomalous timestamps, empty columns, OS-specific filename mangling). Preserve those guards when touching parsing code.
  • int64 casts in SensorData are deliberate (Windows long is 32-bit) — keep them.