Fola-lad commited on
Commit
4747670
Β·
1 Parent(s): 049d8fd

UI refinement

Browse files
src/phyphox_app_block.py CHANGED
@@ -16,8 +16,6 @@ import streamlit as st
16
 
17
  from phyphox_pipeline import process_phyphox_files, FS, WINDOW, STEP
18
 
19
- # ── Constants ─────────────────────────────────────────────────────────────────
20
-
21
  LABEL_MAP = {
22
  0: "WALKING",
23
  1: "WALKING_UPSTAIRS",
@@ -36,8 +34,6 @@ EXPLANATIONS = {
36
  "WALKING_UPSTAIRS": "Elevated vertical acceleration effort: climbing stairs.",
37
  }
38
 
39
- # ── Normalisation ─────────────────────────────────────────────────────────────
40
-
41
  @st.cache_resource
42
  def _load_norm_params(norm_path: str):
43
  """Load per-feature min/max from norm_params.json (keys are string indices 0-560)."""
@@ -62,8 +58,6 @@ def _normalize(features: np.ndarray, min_vals: np.ndarray, max_vals: np.ndarray)
62
  return 2.0 * (clipped - min_vals) / rng - 1.0
63
 
64
 
65
- # ── Public render function ────────────────────────────────────────────────────
66
-
67
  def render_phyphox_tab(
68
  ffn_model, ffn_status: str,
69
  cnn_model, cnn_status: str,
@@ -108,7 +102,6 @@ def render_phyphox_tab(
108
  st.info("Upload both files to continue.")
109
  return
110
 
111
- # ── Raw signal sanity check ───────────────────────────────────────────────
112
  try:
113
  import io as _io
114
  _raw = acc_file.read()
@@ -144,7 +137,6 @@ def render_phyphox_tab(
144
  except Exception:
145
  pass
146
 
147
- # ── Feature extraction ────────────────────────────────────────────────────
148
  try:
149
  with st.spinner("Extracting 561 features from sensor data…"):
150
  features, pipeline_warnings = process_phyphox_files(acc_file, gyro_file)
@@ -170,7 +162,6 @@ def render_phyphox_tab(
170
  f"50% overlap ({STEP / FS:.2f} s hop)"
171
  )
172
 
173
- # ── Normalisation ─────────────────────────────────────────────────────────
174
  if os.path.exists(norm_params_path):
175
  min_vals, max_vals = _load_norm_params(norm_params_path)
176
  features = _normalize(features, min_vals, max_vals)
@@ -185,7 +176,6 @@ def render_phyphox_tab(
185
  "Predictions will be unreliable until normalisation is applied."
186
  )
187
 
188
- # ── Predictions ───────────────────────────────────────────────────────────
189
  if ffn_status != "ready" and cnn_status != "ready":
190
  st.warning("Models not loaded: cannot predict yet.")
191
  return
 
16
 
17
  from phyphox_pipeline import process_phyphox_files, FS, WINDOW, STEP
18
 
 
 
19
  LABEL_MAP = {
20
  0: "WALKING",
21
  1: "WALKING_UPSTAIRS",
 
34
  "WALKING_UPSTAIRS": "Elevated vertical acceleration effort: climbing stairs.",
35
  }
36
 
 
 
37
  @st.cache_resource
38
  def _load_norm_params(norm_path: str):
39
  """Load per-feature min/max from norm_params.json (keys are string indices 0-560)."""
 
58
  return 2.0 * (clipped - min_vals) / rng - 1.0
59
 
60
 
 
 
61
  def render_phyphox_tab(
62
  ffn_model, ffn_status: str,
63
  cnn_model, cnn_status: str,
 
102
  st.info("Upload both files to continue.")
103
  return
104
 
 
105
  try:
106
  import io as _io
107
  _raw = acc_file.read()
 
137
  except Exception:
138
  pass
139
 
 
140
  try:
141
  with st.spinner("Extracting 561 features from sensor data…"):
142
  features, pipeline_warnings = process_phyphox_files(acc_file, gyro_file)
 
162
  f"50% overlap ({STEP / FS:.2f} s hop)"
163
  )
164
 
 
165
  if os.path.exists(norm_params_path):
166
  min_vals, max_vals = _load_norm_params(norm_params_path)
167
  features = _normalize(features, min_vals, max_vals)
 
176
  "Predictions will be unreliable until normalisation is applied."
177
  )
178
 
 
179
  if ffn_status != "ready" and cnn_status != "ready":
180
  st.warning("Models not loaded: cannot predict yet.")
181
  return
src/phyphox_pipeline.py CHANGED
@@ -17,8 +17,6 @@ import pandas as pd
17
  from scipy import signal as sp_signal
18
  from scipy.stats import skew, kurtosis as sp_kurtosis
19
 
20
- # ── Constants ─────────────────────────────────────────────────────────────────
21
-
22
  FS = 50 # target sampling rate Hz
23
  WINDOW = 128 # samples per window (2.56 s)
24
  STEP = 64 # hop size β€” 50% overlap
@@ -35,8 +33,6 @@ ACC_COLS = ["Time (s)", "X (m/s^2)", "Y (m/s^2)", "Z (m/s^2)"]
35
  GYRO_COLS = ["Time (s)", "X (rad/s)", "Y (rad/s)", "Z (rad/s)"]
36
 
37
 
38
- # ── CSV helpers ───────────────────────────────────────────────────────────────
39
-
40
  def _parse_csv(file_obj, expected_cols: list) -> pd.DataFrame:
41
  """Parse a Phyphox CSV export and validate required columns.
42
 
@@ -68,8 +64,6 @@ def _parse_csv(file_obj, expected_cols: list) -> pd.DataFrame:
68
  return df[expected_cols].apply(pd.to_numeric, errors="coerce").dropna()
69
 
70
 
71
- # ── DSP helpers ───────────────────────────────────────────────────────────────
72
-
73
  def _butter_lp(data: np.ndarray, cutoff: float, fs: float = FS, order: int = 3) -> np.ndarray:
74
  """Zero-phase Butterworth low-pass filter applied along axis 0.
75
 
@@ -212,8 +206,6 @@ def _angle(u: np.ndarray, v: np.ndarray) -> float:
212
  return float(np.arccos(np.clip(np.dot(u, v) / (un * vn), -1.0, 1.0)))
213
 
214
 
215
- # ── Feature extractors ────────────────────────────────────────────────────────
216
-
217
  def _t3ax(sig: np.ndarray) -> np.ndarray:
218
  """40 time-domain features from a 3-axis signal (N, 3).
219
 
@@ -420,8 +412,6 @@ def _window_features(
420
  return result
421
 
422
 
423
- # ── Public API ────────────────────────────────────────────────────────────────
424
-
425
  def process_phyphox_files(
426
  acc_file,
427
  gyro_file,
@@ -460,7 +450,6 @@ def process_phyphox_files(
460
  gyro_t = gyro_df["Time (s)"].values
461
  gyro_xyz = gyro_df[["X (rad/s)", "Y (rad/s)", "Z (rad/s)"]].values
462
 
463
- # Common time window
464
  t0 = max(acc_t[0], gyro_t[0])
465
  t1 = min(acc_t[-1], gyro_t[-1])
466
  duration = t1 - t0
 
17
  from scipy import signal as sp_signal
18
  from scipy.stats import skew, kurtosis as sp_kurtosis
19
 
 
 
20
  FS = 50 # target sampling rate Hz
21
  WINDOW = 128 # samples per window (2.56 s)
22
  STEP = 64 # hop size β€” 50% overlap
 
33
  GYRO_COLS = ["Time (s)", "X (rad/s)", "Y (rad/s)", "Z (rad/s)"]
34
 
35
 
 
 
36
  def _parse_csv(file_obj, expected_cols: list) -> pd.DataFrame:
37
  """Parse a Phyphox CSV export and validate required columns.
38
 
 
64
  return df[expected_cols].apply(pd.to_numeric, errors="coerce").dropna()
65
 
66
 
 
 
67
  def _butter_lp(data: np.ndarray, cutoff: float, fs: float = FS, order: int = 3) -> np.ndarray:
68
  """Zero-phase Butterworth low-pass filter applied along axis 0.
69
 
 
206
  return float(np.arccos(np.clip(np.dot(u, v) / (un * vn), -1.0, 1.0)))
207
 
208
 
 
 
209
  def _t3ax(sig: np.ndarray) -> np.ndarray:
210
  """40 time-domain features from a 3-axis signal (N, 3).
211
 
 
412
  return result
413
 
414
 
 
 
415
  def process_phyphox_files(
416
  acc_file,
417
  gyro_file,
 
450
  gyro_t = gyro_df["Time (s)"].values
451
  gyro_xyz = gyro_df[["X (rad/s)", "Y (rad/s)", "Z (rad/s)"]].values
452
 
 
453
  t0 = max(acc_t[0], gyro_t[0])
454
  t1 = min(acc_t[-1], gyro_t[-1])
455
  duration = t1 - t0
src/streamlit_app.py CHANGED
@@ -9,8 +9,6 @@ _REPO_ROOT = os.path.dirname(_SRC_DIR)
9
  _SAMPLES_PATH = os.path.join(_REPO_ROOT, "data", "samples.csv")
10
  _NORM_PATH = os.path.join(_REPO_ROOT, "data", "norm_params.json")
11
 
12
- # ── Constants ──────────────────────────────────────────────────────────────
13
-
14
  LABEL_MAP = {
15
  0: "WALKING",
16
  1: "WALKING_UPSTAIRS",
@@ -29,8 +27,6 @@ EXPLANATIONS = {
29
  "WALKING_UPSTAIRS": "Elevated vertical acceleration effort with upward body displacement: consistent with climbing stairs.",
30
  }
31
 
32
- # ── Model loader ────────────────────────────────────────────────────────────
33
-
34
  @st.cache_resource
35
  def load_model(filename: str):
36
  try:
@@ -54,8 +50,6 @@ def load_model(filename: str):
54
  except Exception as e:
55
  return None, f"error: {e}"
56
 
57
- # ── Page config ─────────────────────────────────────────────────────────────
58
-
59
  st.set_page_config(
60
  page_title="Human Activity Recognition",
61
  page_icon="πŸƒ",
@@ -69,8 +63,6 @@ st.markdown(
69
  "Classifies six daily activities from accelerometer and gyroscope readings."
70
  )
71
 
72
- # ── Sidebar ──────────────────────────────────────────────────────────────────
73
-
74
  with st.sidebar:
75
  st.header("About")
76
  st.markdown("""
@@ -95,8 +87,6 @@ with st.sidebar:
95
  st.markdown("---")
96
  st.caption("DAT606 Group Assignment Β· Pan-Atlantic University")
97
 
98
- # ── Load both models at startup ───────────────────────────────────────────────
99
-
100
  ffn_model, ffn_status = load_model("model.keras")
101
  cnn_model, cnn_status = load_model("har_cnn.keras")
102
 
@@ -106,12 +96,8 @@ if ffn_status != "ready" or cnn_status != "ready":
106
  if cnn_status != "ready":
107
  st.warning(f"CNN not loaded: {cnn_status}")
108
 
109
- # ── Tabs ─────────────────────────────────────────────────────────────────────
110
-
111
  tab1, tab2 = st.tabs(["Select a Sample", "Upload Phyphox CSV"])
112
 
113
- # ── Tab 1: Sample selector ───────────────────────────────────────────────────
114
-
115
  with tab1:
116
  st.subheader("Select a pre-loaded test sample")
117
  st.caption(
@@ -161,7 +147,6 @@ with tab1:
161
 
162
  left, right = st.columns(2)
163
 
164
- # ── FFN column ──────────────────────────────────────────────
165
  with left:
166
  st.markdown("#### Feedforward Network")
167
  if ffn_label == true_label:
@@ -176,7 +161,6 @@ with tab1:
176
  index=[LABEL_MAP[i] for i in range(6)]
177
  ))
178
 
179
- # ── CNN column ──────────────────────────────────────────────
180
  with right:
181
  st.markdown("#### 1D Convolutional Network")
182
  if cnn_label == true_label:
@@ -194,8 +178,6 @@ with tab1:
194
  except FileNotFoundError:
195
  st.error("Sample data file not found. Add `data/samples.csv` to the repo.")
196
 
197
- # ── Tab 2: Phyphox upload ─────────────────────────────────────────────────────
198
-
199
  with tab2:
200
  from phyphox_app_block import render_phyphox_tab
201
  render_phyphox_tab(ffn_model, ffn_status, cnn_model, cnn_status, _NORM_PATH)
 
9
  _SAMPLES_PATH = os.path.join(_REPO_ROOT, "data", "samples.csv")
10
  _NORM_PATH = os.path.join(_REPO_ROOT, "data", "norm_params.json")
11
 
 
 
12
  LABEL_MAP = {
13
  0: "WALKING",
14
  1: "WALKING_UPSTAIRS",
 
27
  "WALKING_UPSTAIRS": "Elevated vertical acceleration effort with upward body displacement: consistent with climbing stairs.",
28
  }
29
 
 
 
30
  @st.cache_resource
31
  def load_model(filename: str):
32
  try:
 
50
  except Exception as e:
51
  return None, f"error: {e}"
52
 
 
 
53
  st.set_page_config(
54
  page_title="Human Activity Recognition",
55
  page_icon="πŸƒ",
 
63
  "Classifies six daily activities from accelerometer and gyroscope readings."
64
  )
65
 
 
 
66
  with st.sidebar:
67
  st.header("About")
68
  st.markdown("""
 
87
  st.markdown("---")
88
  st.caption("DAT606 Group Assignment Β· Pan-Atlantic University")
89
 
 
 
90
  ffn_model, ffn_status = load_model("model.keras")
91
  cnn_model, cnn_status = load_model("har_cnn.keras")
92
 
 
96
  if cnn_status != "ready":
97
  st.warning(f"CNN not loaded: {cnn_status}")
98
 
 
 
99
  tab1, tab2 = st.tabs(["Select a Sample", "Upload Phyphox CSV"])
100
 
 
 
101
  with tab1:
102
  st.subheader("Select a pre-loaded test sample")
103
  st.caption(
 
147
 
148
  left, right = st.columns(2)
149
 
 
150
  with left:
151
  st.markdown("#### Feedforward Network")
152
  if ffn_label == true_label:
 
161
  index=[LABEL_MAP[i] for i in range(6)]
162
  ))
163
 
 
164
  with right:
165
  st.markdown("#### 1D Convolutional Network")
166
  if cnn_label == true_label:
 
178
  except FileNotFoundError:
179
  st.error("Sample data file not found. Add `data/samples.csv` to the repo.")
180
 
 
 
181
  with tab2:
182
  from phyphox_app_block import render_phyphox_tab
183
  render_phyphox_tab(ffn_model, ffn_status, cnn_model, cnn_status, _NORM_PATH)