Skip to the content
PCBKitNew board
4 layers30 × 40 mmPulsepatch, the printed circuit board in 3D

Full-Stack Embedded System Wearable

Size
30 × 40 mm
Copper layers
4
Thickness
0.8 mm
Parts
90
Nets
65
Pads
281
Tracks, vias
873, 155
Pours
5
Routed
Yes
KiCad
KiCad 10.0 (file 20260206)
Created
3 Oct 2026
Updated
4 Oct 2026

Overview

Pulsepatch is an open-source printed circuit board by suhaant, from the suhaant/Amethyst repository on GitHub. It is a 4-layer board of 30 × 40 mm with 90 parts on 65 nets, routed with 873 tracks and 155 vias.

It is built around the MDBT42Q-512KV2, AD8603AUJ and DRV8837DSG, with the TPS61040DBV, TPS61165DBV and 74LVC1G08Z among its other parts. Its parts include 26 capacitors, 20 resistors, 12 ICs, 9 diodes and 3 inductors. It belongs with the wearables boards and the nRF52 and nRF5x boards of this library.

Main components

10

README

README.md
Amethyst

Smart wound care that catches infection early and treats it on the spot.

A wearable patch that senses infection before you can see it, scores the risk with an ML model, has an AI agent check the evidence, and treats with low-frequency ultrasound and 405 nm violet light.

Python XGBoost Gemini nRF52 KiCad Expo FastAPI Databricks

Watch the 40-second film · How it works · Quick start · The math · Safety


The problem

60% of diabetic foot ulcers become infected, and 15–20% of diabetic foot infections end in amputation. Nerve damage removes pain, the body's warning sign, so infection often goes unnoticed until it's visible, and by then it's serious.

The early signs are measurable long before that. Infected wounds turn alkaline (healthy wounds sit at pH 4–6; infected ones at 7.5–9), get warmer and wetter, and bacteria use up the glucose in wound fluid. Amethyst watches for exactly those changes.

Sources: Diabetes Care; Nussbaum et al., Value in Health 2018. More in hardware/research/.

How it works

mermaid
flowchart LR
    P["Amethyst patch<br/>pH · moisture · 3× temp"] -->|"BLE, every 30 min"| S
    C["CGM<br/>blood glucose"] --> S
    S["FastAPI server<br/>POST /api/readings"] --> A{{"Gemini agent"}}
    A -->|tool| M["XGBoost model<br/>risk = likelihood × severity"]
    A -->|tool| D["Dosing engine<br/>tiers + safety caps"]
    A --> F["Notes, fact-checked<br/>in code"]
    S --> App["Expo app<br/>alert · therapy · trends"]
    S --> DB[("Databricks<br/>care record + dashboard")]
    D -->|"therapy command"| P
  1. Sense. Every 30 minutes the patch reads wound pH, moisture (impedance) and temperature at three spots (wound edge, healthy reference skin, ambient). Blood glucose comes from the wearer's CGM.
  2. Predict. An XGBoost model compares each reading with the patient's own first-day baseline and outputs a 0–100 risk score and a tier: monitor, watch, treat or intensive.
  3. Reason. A Gemini agent calls the model and the dosing engine as tools, then writes a clinician-ready assessment. It covers the trend, sensor faults, signals that disagree with the model, its confidence, and whether a clinician should look. It never invents a number: risk and doses always come from our code, and its notes are fact-checked against the tool results.
  4. Treat. In the treat tier the patch runs ultrasound to break up biofilm, then 405 nm light to kill bacteria. Lower tiers get gentle healing ultrasound and closer monitoring.
  5. Alert. The app shows the patient their risk, trends and therapy. Every reading and assessment lands in Databricks for the care team.

Results

Validated leave-one-person-out (16 folds): every person is scored by a model that never saw their data.

Random forestXGBoost (shipped)
AUC0.9760.978
Brier skill score0.8340.845
Infected wounds detected100%100%
Median hours from onset to alarm30.327.2
False alarms, clean wounds0.3%2.1%
Model size11.9 MB3.1 MB
Time per prediction12.4 ms0.14 ms

We shipped XGBoost: it alarms 3.1 h earlier and is 3.8× smaller and 89× faster, which matters on a wearable. The extra false alarms are absorbed by risk smoothing and the agent's review.

Which sensors matter most (AUC of each sensor on its own): moisture 0.952 · temperature 0.933 · pH 0.917 · wound glucose 0.886 · blood glucose 0.650 · pH + temp + moisture together 0.976.

All results are on simulated data (see limits). The full method is in docs/ml-pipeline.md.

The math

Training data. No public dataset of continuous wound-sensor readings with infection labels exists, so we simulated one from 30+ published studies and real Dexcom glucose traces from 16 people (PhysioNet):

$$600 \text{ wounds} \times 14 \text{ days} \times 48 \text{ readings/day} = 403{,}200 \text{ labelled readings}$$

Features. 5 signals × (6 h median, change vs. day-1 baseline, 6 h change, 24 h change, 24 h std) + 2 time-of-day terms = 27 features.

Risk = likelihood × severity. Trained on cleanly separated data, the classifier is near-certain for any sustained shift. So we scale its probability by how far the signs have actually moved toward a full infection:

$$p = P(\text{warning}) + P(\text{infection})$$

$$s = \text{mean of the 3 largest of } \left\lbrace \frac{\Delta \text{pH}}{0.65},\ \ \frac{\Delta T}{1.6^{\circ}\text{C}},\ \ \frac{-\Delta \ln Z}{-\ln 0.65},\ \ \frac{-\Delta g / g_0}{0.40}\right\rbrace$$

Each Δ is a 2 h median minus the patient's day-1 baseline. The denominators are a full infection's average effect in the simulator: pH +0.65, temperature +1.6 °C, impedance −35%, wound glucose −40%. Each term is clipped to [0, 1.25] and s to [0, 1]. Using the top 3 of 4 means a wound whose pH doesn't rise, which happens in real infections, still scores. The score is then smoothed so one noisy reading can't trigger treatment (τ = 3 h, Δt = 0.5 h):

$$R_t = R_{t-1} + \alpha(100 p_t s_t - R_{t-1}), \qquad \alpha = \frac{0.5}{3 + 0.5} \approx 0.143$$

Tiers use 10-point hysteresis: each is entered at its threshold and left only 10 points below it, so the device doesn't flicker.

TierEnter atTherapy each 8 h session (3/day)
0 · Monitor—1.5 MHz healing ultrasound, 6.7 min (20 min/day ÷ 3)
1 · Watch30Healing ultrasound + closer monitoring
2 · Treat55Ultrasound to break biofilm → 405 nm light
3 · Intensive80Same, scaled up toward the caps

Light dose (treat tier and above) at 10 mW/cm², with the 36 J/cm² daily cap split over 3 sessions:

$$x = \text{clip}\left(\frac{R - 30}{60}, 0, 1\right), \qquad E = 12x \ \text{J/cm}^2, \qquad t = \frac{E}{0.010 \ \text{W/cm}^2}$$

Ultrasound (treat tier and above), run before the light:

$$y = \text{clip}\left(\frac{R - 55}{35}, 0, 1\right), \qquad t_{\text{US}} = \max(4,\ 10y) \ \text{min}, \qquad I = 0.1 + 0.4y \ \text{W/cm}^2$$

Risk RLightUltrasound
55 (enters treat)5 J/cm² → 8.3 min4 min at 0.10 W/cm²
72.58.5 J/cm² → 14.2 min5 min at 0.30 W/cm²
10012 J/cm² → 20 min (3 × 12 = 36 J/cm²/day cap)10 min at 0.50 W/cm²

The AI agent

wound_agent/ wraps the model and dosing in three tools: get_sensor_history → predict_infection → plan_treatment. The LLM writes structured notes: summary, trend, reasoning, data_quality_flags, conflicting_signals, recommend_clinician_review and confidence.

  • Gemini by default. Gemini 3.8 Flash with low thinking takes about 5 s and about $0.005 per assessment. GEMINI_MODEL=gemini-3.1-pro-preview with GEMINI_THINKING=high gives maximum care. OpenRouter and Claude Opus also work (AGENT_PROVIDER=gemini|openrouter|claude).
  • Fact-checked. After the agent writes, code checks its notes against the tool results (risk score, tier, lifted patch, clinician review) and asks for one correction if anything is off.
  • Knows what to distrust. It's told each sensor's standalone accuracy, that infections don't always raise pH, and how hysteresis works. In testing it caught a 43 °C reading as a sensor fault rather than a fever, and blamed a risk jump on a meal-time glucose spike while the wound sensors stayed healthy.
  • Never blocks the demo. With no API key, the same model and dosing run and a rule-based summary stands in.

Hardware

Amethyst board, top Amethyst board, wound side

A reusable 30 × 40 mm, 4-layer pod that clips onto a disposable hydrogel pad. Full spec →

BlockParts
Radio + MCURaytac MDBT42Q (nRF52832), Bluetooth LE
Temperature3× TMP117: wound edge, reference skin, ambient
Moisture1 kHz square wave through a 47 kΩ reference into the pad electrodes, read as impedance (no dedicated chip)
pHAD8603 buffer on the working electrode
Light6× 405 nm LEDs, TPS61165 constant-current boost, PWM dimming
Ultrasound15 mm 30 kHz piezo disc, TPS61040 boost (5–10 V) + DRV8837 H-bridge + 4.7 mH resonant inductor
PowerSingle LiPo, MCP73831 charger, AP2112K 3.3 V regulator
ExtrasPad-ID resistor, button for a daily pain/odour check-in, SWD debug pads

Generated, not drawn. One Python file (design.py) generates the schematic, places every part, autoroutes all 178 connections and runs KiCad's electrical and design-rule checks in one command.

Power and heat budget (details):

  • Sensing averages ~22 µA, which is about 60 days on a 40 mAh cell.
  • At 10 mW/cm² of light, skin reaches 37.3 °C, or 38.7 °C on a poorly perfused diabetic foot, including the LEDs' own heat. Both stay under our 41 °C ceiling.
  • Doubling to 20 mW/cm² would hit 43.4 °C, so we didn't.

Safety in three layers

LayerWhat it enforces
1 · Software (risk_to_dose.py)Dose caps, tier hysteresis, no therapy when impedance > 150 kΩ (patch lifted)
2 · Firmware (firmware/)The same caps again, whatever the phone asks: 10 mW/cm², 36 J/cm²/day, 10 min of pulsed ultrasound (500 ms on / off), stop at 41 °C, and no session without a pad attached and on the skin, a working wound sensor, and battery > 3.5 V
3 · HardwareEvery TMP117 alert pin feeds AND gates on the light and ultrasound enables. At 42 °C, therapy cuts out even if the firmware has crashed

Quick start

Python 3.12+ (Adam's pinned numpy 2.5 and xgboost 3.4 need it).

bash
python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env               # add GEMINI_API_KEY (or OPENROUTER_ / ANTHROPIC_API_KEY)

Run the agent on a simulated wound:

bash
python main.py -v --scenario infected        # healthy | early_infection | infected | sensor_fault | patch_lifted
python main.py --history sample_data/simulated_wound_history.csv
python main.py --offline                     # model + dosing only, no LLM

Live demo + hardware API (then open http://localhost:8000):

bash
python demo_ui/server.py
python demo_ui/send_reading.py --scenario infection --count 8 --every 3    # pretend to be the patch
EndpointWhat
POST /api/readingsOne patch reading in → risk, tier and therapy plan out
GET /api/stateLatest assessment (the app polls this)
GET /api/eventsServer-sent events for every pipeline step
POST /api/resetNew patient with a fresh 24 h baseline
GET /docsInteractive API docs

Phone app (Expo Go):

bash
cd app && npm install && npx expo start      # add --tunnel on campus Wi-Fi

Firmware tests (simulated board) and board build (KiCad 10):

bash
cd firmware && make test && make arm-check
cd hardware/kicad && ./build.sh              # about 6 min with autorouting; --no-route for seconds

Databricks care record (landing from the databricks branch; design in docs/superpowers/specs/):

bash
python main.py --databricks                  # readings + assessments to Databricks, care-team dashboard

Film:

bash
cd remotion && npm install && npm run dev

Tests:

bash
python -m pytest

Repo map

PathWhat
wound_agent/ · main.pyAI agent: tools, prompts, providers, fact check, CLI
predict.py · risk_to_dose.py · model/Trained XGBoost model, risk score, dosing engine
generate_data.py · train_*.py · compare_models.pySimulator, training, RF vs. XGBoost, validation (write-up)
research/ · hardware/research/Literature values for every simulator parameter, signal and dose, with sources
demo_ui/FastAPI server, hardware API, animated live demo
app/Expo companion app: Pair, Home, Alert, Therapy, Trends
hardware/ · firmware/KiCad board generator + board, C firmware with Zephyr port
remotion/Demo film and brand assets
tests/Pipeline tests: scenarios, tiers, dose caps, interlock

Honest limits

  • Simulated training data. The model has never seen a real wound. Retrain on real patch data before any clinical use.
  • Prototype doses from published studies, not a validated medical protocol.
  • The board is designed and autorouted but not yet fabricated, and the firmware has only run on a simulated board. Light and ultrasound intensity at the wound are estimates until measured.
  • Not all on the board yet. The board's ultrasound runs at 30 kHz (within the 20–40 kHz range of clinical wound devices). The 1.5 MHz healing mode and wound-fluid glucose sensing aren't on this board yet.
  • Combining light and ultrasound is backed by lab (in-vitro) studies so far.

Team

Built at WolfHacks 2026 by:

  • Adam Rakhmanov: ML model, simulator, dosing, demo server.
  • Anay Vaidya: hardware, firmware, Databricks.
  • Aarush: app and film.
  • Suhaan Temkar: AI agent.

Glucose data: BIG IDEAs Lab Glycemic Variability and Wearable Device Data v1.1.3, PhysioNet, ODC-By 1.0.

Parts

90
QtyValueFootprintReferences
10100nCapacitor_SMD:C_0402_1005MetricC5, C7, C8, C9, C10, C12, C15, C16, C17, C26
6100kResistor_SMD:R_0402_1005MetricR9, R10, R12, R13, R17, R20
6405nmLED_SMD:LED_Cree-XPD2, D3, D4, D5, D6, D7
51uCapacitor_SMD:C_0402_1005MetricC3, C4, C11, C14, C24
44.7uCapacitor_SMD:C_0603_1608MetricC1, C2, C18, C21
310kResistor_SMD:R_0402_1005MetricR6, R8, R11
31MResistor_SMD:R_0402_1005MetricR2, R3, R15
34.7kResistor_SMD:R_0402_1005MetricR1, R4, R5
3GNDTestPoint:TestPoint_Pad_1.5x1.5mmTP2, TP4, TP11
3TMP117Package_SON:WSON-6-1EP_2x2mm_P0.65mm_EP1x1.6mmU4, U5, U6
210uInductor_SMD:L_Taiyo-Yuden_NR-30xxL1, L2
274LVC1G08Package_TO_SOT_SMD:SOT-23-5U8, U9
2GNDTestPoint:TestPoint_Pad_2.0x2.0mmTP16, TP19
2MBR0540Diode_SMD:D_SOD-123D1, D8
1+3V3TestPoint:TestPoint_Pad_1.5x1.5mmTP10
1+3V3TestPoint:TestPoint_Pad_2.0x2.0mmTP18
1100n 25VCapacitor_SMD:C_0402_1005MetricC25
1100pCapacitor_SMD:C_0402_1005MetricC13
110RResistor_SMD:R_0402_1005MetricR14
110uCapacitor_SMD:C_0603_1608MetricC6
1180kResistor_SMD:R_0402_1005MetricR16
11kResistor_SMD:R_0402_1005MetricR19
11u 50VCapacitor_SMD:C_0805_2012MetricC19
1220nCapacitor_SMD:C_0402_1005MetricC20
122pCapacitor_SMD:C_0402_1005MetricC23
14.7mInductor_SMD:L_6.3x6.3_H3L3
14.7u 25VCapacitor_SMD:C_0805_2012MetricC22
147k 1%Resistor_SMD:R_0402_1005MetricR7
1560kResistor_SMD:R_0402_1005MetricR18
1AD8603Package_TO_SOT_SMD:TSOT-23-5U7
1AP2112K-3.3Package_TO_SOT_SMD:SOT-23-5U2
1DRV8837Package_SON:WSON-8-1EP_2x2mm_P0.5mm_EP0.9x1.6mmU12
1MCP73831Package_TO_SOT_SMD:SOT-23-5U1
1MDBT42Q-512KRF_Module:Raytac_MDBT42QU3
1MOIST_1TestPoint:TestPoint_Pad_2.0x2.0mmTP14
1PAD_AUXTestPoint:TestPoint_Pad_2.0x2.0mmTP15
1PAD_IDTestPoint:TestPoint_Pad_2.0x2.0mmTP17
1PH_REFTestPoint:TestPoint_Pad_2.0x2.0mmTP13
1PH_WETestPoint:TestPoint_Pad_2.0x2.0mmTP12
1PIEZO_ATestPoint:TestPoint_Pad_1.5x1.5mmTP5
1PTS810Button_Switch_SMD:SW_SPST_PTS810SW1
1RESET_NTestPoint:TestPoint_Pad_1.5x1.5mmTP9
1SWDCLKTestPoint:TestPoint_Pad_1.5x1.5mmTP8
1SWDIOTestPoint:TestPoint_Pad_1.5x1.5mmTP7
1TPS61040Package_TO_SOT_SMD:SOT-23-5U11
1TPS61165Package_SON:WSON-6-1EP_2x2mm_P0.65mm_EP1x1.6mmU10
1US_OUT2TestPoint:TestPoint_Pad_1.5x1.5mmTP6
1VBATTestPoint:TestPoint_Pad_1.5x1.5mmTP3
1VCHGTestPoint:TestPoint_Pad_1.5x1.5mmTP1
1statusLED_SMD:LED_0603_1608MetricD9

Questions

How big is the Pulsepatch PCB?

It measures 30 × 40 mm and has 4 copper layers, 0.8 mm thick.

What parts does the Pulsepatch use?

90 parts, built around the MDBT42Q-512KV2, AD8603AUJ, DRV8837DSG and TPS61040DBV. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the Pulsepatch KiCad files?

From the suhaant/Amethyst repository on GitHub, at the commit this page was made from: the board is hardware/kicad/pulsepatch/pulsepatch.kicad_pcb and its schematic hardware/kicad/pulsepatch/pulsepatch.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the Pulsepatch design in my own project?

Its repository states no licence, so its author keeps all rights: ask suhaant before reusing the design.

Similar boards

  • 2 layers68 × 42 mmLcd dsi, the printed circuit board in 3D

    Lcd dsi

    Novin3dp/7inch-hdmi-screen

    این برد دولایه (۶۸×۴۲ میلی‌متر) همان پنل ۷ اینچ AT070TN92 و تاچ GT915 را این بار از پورت DSI رزبری‌پای راه می‌اندازد. نسخه‌ی HDMI در پوشه‌ی hardware/ دست‌نخورده باقی مانده است.

    85 parts1
  • 2 layers75 × 140 mmBadge, the printed circuit board in 3D

    Badge

    mmicko/workshop_badge

    Proposal for FPGA workshop badge for Hackaday Belgrade 2018

    45 parts10
  • 4 layers35.9 × 43.1 mmProx sensor, the printed circuit board in 3D

    Prox sensor

    cornway/vanity_mirror_pcb

    41 parts
  • 2 layers54.6 × 61 mmBB Dash Display, the printed circuit board in 3D

    BB Dash Display

    OxfordUniRacing/BB_Dash_Display

    46 parts
  • 2 layers65 × 75 mmPmod lcd35, the printed circuit board in 3D

    Pmod lcd35

    daveshah1/pmods

    PMODs primarily for demo usage with icestorm

    21 parts9
  • 2 layers54.9 × 23.5 mmStdc14 adapter, the printed circuit board in 3D

    Stdc14 adapter

    arvindsa/stlinkv3-adapter

    STVlink3 Adapter

    26 parts