diff --git a/Python/Xiao_BLE_tools/xiao_calibration_tool.py b/Python/Xiao_BLE_tools/xiao_calibration_tool.py index 015a787..177bc48 100644 --- a/Python/Xiao_BLE_tools/xiao_calibration_tool.py +++ b/Python/Xiao_BLE_tools/xiao_calibration_tool.py @@ -44,6 +44,9 @@ debug_mode = 3 # 0=OFF, 1=RAW, 2=TRIGGERS, 3=FULL (actif par défaut) import numpy as np X = np.arange(WINDOW_SIZE) # axe X fixe, ne change jamais +# Fenêtre de moyenne glissante en samples (60ms window / 50ms debug rate = ~1.2 → 3 samples min) +AVG_WINDOW = 3 # correspond à la accelWindow/gyroWindow/audioWindow envoyée au XIAO (60ms @ 20Hz) + # ─── BLE ──────────────────────────────────────────────── def debug_callback(sender, data): global audio_max_global, shot_pending @@ -192,9 +195,12 @@ from matplotlib.animation import FuncAnimation BG = '#1a1a2e' PANEL = '#16213e' TEXT = '#e0e0e0' -CA = '#4fc3f7' # accel -CG = '#81c784' # gyro -CM = '#ce93d8' # audio +CA = '#4fc3f7' # accel brut +CG = '#81c784' # gyro brut +CM = '#ce93d8' # audio brut +CA2 = '#0288d1' # accel moyenne (plus foncé) +CG2 = '#388e3c' # gyro moyenne +CM2 = '#7b1fa2' # audio moyenne CT = '#ef5350' # trigger / seuil CS = '#ff9800' # shot (orange vif) GRID = '#2a2a4a' @@ -222,15 +228,23 @@ axes[3].set_ylim(-0.1, 1.5) axes[3].set_yticks([]) # pas de graduations Y sur la timeline # Créer les artistes UNE SEULE FOIS — on ne les recrée jamais -line_a, = axes[0].plot(X, list(accel_buf), color=CA, lw=1.5) -line_g, = axes[1].plot(X, list(gyro_buf), color=CG, lw=1.5) -line_m, = axes[2].plot(X, list(audio_buf), color=CM, lw=1.5) -line_s, = axes[3].plot(X, list(shot_buf), color=CS, lw=0, marker='|', +line_a, = axes[0].plot(X, list(accel_buf), color=CA, lw=1.0, alpha=0.5, label='Brut') +line_g, = axes[1].plot(X, list(gyro_buf), color=CG, lw=1.0, alpha=0.5, label='Brut') +line_m, = axes[2].plot(X, list(audio_buf), color=CM, lw=1.0, alpha=0.5, label='Brut') +line_a2, = axes[0].plot(X, list(accel_buf), color=CA2, lw=2.0, label=f'Moyenne ({AVG_WINDOW} pts / 60ms)') +line_g2, = axes[1].plot(X, list(gyro_buf), color=CG2, lw=2.0, label=f'Moyenne ({AVG_WINDOW} pts / 60ms)') +line_m2, = axes[2].plot(X, list(audio_buf), color=CM2, lw=2.0, label=f'Moyenne ({AVG_WINDOW} pts / 60ms)') +line_s, = axes[3].plot(X, list(shot_buf), color=CS, lw=0, marker='|', markersize=20, markeredgewidth=2.5) # barres verticales -thr_a = axes[0].axhline(thresholds["accel"], color=CT, ls='--', lw=1.5) -thr_g = axes[1].axhline(thresholds["gyro"], color=CT, ls='--', lw=1.5) -thr_m = axes[2].axhline(thresholds["audio"], color=CT, ls='--', lw=1.5) +thr_a = axes[0].axhline(thresholds["accel"], color=CT, ls='--', lw=1.5, label='Seuil') +thr_g = axes[1].axhline(thresholds["gyro"], color=CT, ls='--', lw=1.5, label='Seuil') +thr_m = axes[2].axhline(thresholds["audio"], color=CT, ls='--', lw=1.5, label='Seuil') + +# Légendes +for ax in axes[:3]: + ax.legend(loc='upper left', fontsize=7, facecolor=PANEL, edgecolor='#444466', + labelcolor=TEXT, framealpha=0.8) from matplotlib.patches import Rectangle from matplotlib.collections import PatchCollection @@ -262,17 +276,30 @@ def update_spans(spans, trig_list): for i, span in enumerate(spans): span.set_alpha(0.25 if i < len(tl) and tl[i] else 0) +def rolling_avg(arr, window): + """Moyenne glissante simple — même logique que le XIAO""" + kernel = np.ones(window) / window + return np.convolve(arr, kernel, mode='same') + def update(frame): # Snapshot des buffers (rapide) a = np.array(accel_buf) g = np.array(gyro_buf) - m = np.array(audio_buf) + m = np.array(audio_buf, dtype=float) s = np.array(shot_buf) + # Moyennes glissantes (même fenêtre que le XIAO) + a_avg = rolling_avg(a, AVG_WINDOW) + g_avg = rolling_avg(g, AVG_WINDOW) + m_avg = rolling_avg(m, AVG_WINDOW) + # Mise à jour des données des lignes line_a.set_ydata(a) line_g.set_ydata(g) line_m.set_ydata(m) + line_a2.set_ydata(a_avg) + line_g2.set_ydata(g_avg) + line_m2.set_ydata(m_avg) line_s.set_ydata(s) # Mise à jour des seuils @@ -319,7 +346,7 @@ def update(frame): f"Debug XIAO : {DEBUG_MODE_NAMES[debug_mode]} [NUM0 = cycle OFF->RAW->TRIGGERS->FULL] | " f"MinSensors : {min_sensors}/3 [NUM6=+1 NUM4=-1]") - return (line_a, line_g, line_m, line_s, + return (line_a, line_g, line_m, line_a2, line_g2, line_m2, line_s, thr_a, thr_g, thr_m, *titles, status_txt, debug_txt)