Penn Neurotech Hack — Science Track
We chose ( N = 14 ) to keep the output space manageable. Larger alphabets made decoding unstable and harder to learn, while this size preserved enough expressivity for control.
Our decoder uses a windowed ridge regression approach. Neural data is binned at 10 ms resolution and a 20-bin (200 ms) causal context is flattened into a single feature vector. We compute both mean and RMS features, resulting in a 2560-dimensional input. RMS captures signal power that mean-only features suppress, improving validation correlation by ~0.05.
We standardize inputs and train ridge regression models for each output channel. Ridge was chosen for its stability under high-dimensional, correlated inputs and its suitability for real-time use. Sample weighting emphasizes behaviorally relevant periods so the model is not dominated by idle data. The regularization parameter ( \alpha ) is selected using a held-out validation file to balance bias and variance.
Predictions are clipped to valid controller ranges ([-1,1] for sticks, [0,1] for buttons) and rescaled to device units (int16). The full pipeline is causal and computationally efficient, making it suitable for live decoding.
Pipeline
- 10 ms bins with 200 ms context (20 bins)
- Mean + RMS features → 2560-dimensional input
- Standardization → ridge regression → clipping → rescaling
What Didn’t Work
- Classification on discretized targets performed at chance (balanced accuracy 0.33 for 4-class, 0.07 for ( N = 14 ))
- MLP regression (2-layer, 256/128, dropout 0.1) severely overfit (train corr ≈ 0.99, poor validation performance)
System Additions
GameState
- Added
peak_streak: int = 0, updated inprocess_inputon each correct hit and reset inreset()
CollectState
- Added
calib_curve_nsandcalib_curve_bsto store calibration sweep results poll()now unpacks a 6-tuple fromcalib_done:
(N, theta, B, path, curve_ns, curve_bs)
Calibration Worker
_auto_calib_workerextractscurve_nsandcurve_bsfrom the sweep results and includes them in thecalib_donemessage
Visualization
_draw_bn_chartrenders a native pygame bar chart:- Grey axes
- Blue bars for each tested
N - Green bar + “N*” label for the optimal value
- Bit rate
Bdisplayed inside each bar Nlabeled along the x-axis
- Grey axes
Results Screen
draw_results_screenprovides a full-screen, two-column layout:- Left panel:
- Bit rate (large)
- Accuracy (%)
- Total / correct / incorrect counts
- Peak streak
- Elapsed time
- Right panel:
- Optimal
N*,θ, peakB - B(N) bar chart or fallback message if calibration is skipped
- Bottom controls:
R — PLAY AGAIN(green)ESC — QUIT
Main Loop Behavior
- When
state.trial_endedisTrue(outside intro/collect screens):- Renders results screen
- Continues polling calibration in case it finishes after the trial ends
- Renders results screen
- Pressing
Rtriggersstate.reset():- Sets
trial_ended = False - Hides results screen and restarts the game
- Sets
How To Upload The Model And The App
- Extract the
synapse-example-appfolder - Run:
synapsectl apps build . - Run:
synapsectl -u "tamarin-of-silent-virtuosity" apps deploy . - Run:
synapsectl -u "tamarin-of-silent-virtuosity" deploy-model model.onnx --name model - Run:
synapsectl -u "tamarin-of-silent-virtuosity" start ./config/simulator_32ch.json
How To Run The Game
- Execute
run.shto start the game
Log in or sign up for Devpost to join the conversation.