09. CWRU Bearing-Fault NPU on Silicon
This page carries the L3 pattern from 08. kws_silicon (full graph in a single IP) to a deeper graph in a different domain. Speech recognition → industrial rotating-machinery condition-based monitoring (CBM). Same board, same toolchain, different model.
The Model
examples/silicon_bearing/ — a 4-class 1D CNN fault classifier
trained on CWRU bearing-data-center vibration records.
Input : FFT[128] INT8 (12 kHz accelerometer → 512-pt FFT → 128 freq bins)
Classes : normal / inner_race / ball / outer_race
Graph : Conv1D × 3 → MaxPool × 2 → GAP → fc1 → fc2
Training : RTX 3090, 30 epochs, val 99.62 % / test 99.00 %
Weights : INT8 quantized, 60.5 KB header
A standard dataset used in defence / shipbuilding / heavy industry for rotating-machinery condition monitoring.
Silicon Result in One Line
40/40 CPU↔NPU MATCH, NPU 11.13× speedup, and a 200-window stream monitor with 0 false alarms and 150/150 fault detections.
| CPU | NPU | |
|---|---|---|
| inference cycles | 29.4 M cyc | 2.65 M cyc |
| inference wall (@ 666 MHz) | 44 ms | 4.0 ms |
| speedup | 1× | 11.13× |
Higher than P06 (KWS)'s 8.07× — the graph is deeper (3 Conv1D layers) so the ARM baseline is heavier.
L3 Pattern — Same IP Shape
Same single-IP, ARM-input-only pattern as P06:
ARM (PS, 666 MHz)
├── FFT input prep
├── ap_start once
├── ap_done poll
└── softmax + argmax
NPU (PL, 90 MHz) — bearing_npu_top
├── Conv1D × 3
├── MaxPool × 2
├── GAP
├── fc1 + ReLU
├── fc2
└── INT8 weight ROM (on-chip BRAM)
One ap_start per inference — Apple ANE / Edge-TPU pattern.
Resource Ceiling — II=64 Fix
First synth attempt with II=4:
| Resource | 1st try (II=4) | XC7Z020 limit |
|---|---|---|
| DSP | 231 % | 220 |
| LUT | 265 % | 53 K |
→ Over board. With ALLOCATION operation instances=fmul=4 fadd=4
pragma capping float MAC units at 4 + II=64 re-synth:
| Resource | 2nd try (II=64 + ALLOC limit=4) |
|---|---|
| Fmax | 114 MHz (clocked at 90 MHz) |
| DSP | 189 (86 %) |
| BRAM | 12 % |
| LUT | < 50 % |
Latency went up but CWRU 4-class separation is wide enough that accuracy held.
This is a common trade-off for small-NPU synthesis: raise II, constrain ALLOC, fit inside resources. The parameters that fit P06 (II=4) may not fit P07; that has to be re-measured per model.
Two Demos
demo1 — Accuracy Gate
4 classes × 10 samples = 40 inferences. CPU and NPU run side-by-side.
idx truth pred(cpu) c_cpu cyc(cpu) pred(npu) c_npu cyc(npu) speedup
00 normal normal 0.999 29,439,352 normal 0.999 2,648,130 11.1×
10 inner_race inner_race 0.988 29,425,653 inner_race 0.988 2,647,073 11.1×
20 ball ball 0.998 29,427,387 ball 0.998 2,647,196 11.1×
30 outer_race outer_race 0.999 29,425,254 outer_race 0.999 2,647,133 11.1×
... (40 rows)
CPU accuracy : 40/40 (100%)
NPU accuracy : 40/40 (100%)
CPU↔NPU agree : 40/40 (100%)
RESULT: PASS
demo2 — 200-window Streaming Monitor
50 normal → 50 inner_race → 50 ball → 50 outer_race. Threshold
conf ≥ 0.75 → *** FAULT *** alert.
[frame 50] normal conf=0.999 cyc=2,646,863
[frame 51] inner_race conf=0.988 cyc=2,647,101 *** FAULT: inner_race ***
[frame 101] ball conf=0.998 cyc=2,647,071 *** FAULT: ball ***
[frame 151] outer_race conf=0.999 cyc=2,647,047 *** FAULT: outer_race ***
[frame 200] outer_race conf=0.999 cyc=2,647,087 *** FAULT: outer_race ***
Windows processed : 200
False alarms : 0 (all 50 normal windows passed)
Fault alerts : 150 / 150
Avg cycles/window : 2,646,970
Total wall time : 4,884 ms
RESULT: PASS
Precision 100 %, recall 100 %. Byte-identical on a second run. 252 inferences/sec is achievable.
Reproduce — Same One Line as P06
# board just-reset
bash examples/silicon_bearing/scripts/run_npu_test.sh
Expected: ~3 minutes
demo1 : PASS (40/40)
demo2 : PASS (200/200, 0 false alarms)
Honest Caveats
CWRU is an "easy problem"
12 kHz / 0.007-inch fault size / clean drive-end accelerometer — under these conditions 4-class separation is so obvious that even non-AI approaches work. Real-world industrial CBM (varying bearing types, variable RPM, compound faults) is much harder.
The point of this demo is toolchain validation: before tackling the hard problem, show that the same flow produces a working circuit.
100 MHz fails timing
The first Vivado run at 100 MHz lands at WNS = -0.4 ns → timing fail. Drop the clock to 90 MHz, re-run, get +0.071 ns with margin. Same pattern observed in P06 KWS L3. XC7Z020's float MAC placement gets tight at 100 MHz.
Detailed References
- examples/silicon_bearing/docs/tutorial.md — full walkthrough
- examples/silicon_bearing/docs/results/SUMMARY.md
- examples/silicon_bearing/docs/results/demo_combined_npu_silicon.mp4 — 35-second combined demo video
Next
10. llm_silicon_hybrid — the deliberate departure from the P06/P07 L3 pattern (LLM weights don't fit BRAM).