Human Paradox - Colin's Blog

Detecting gunshots with a watch accelerometer

Shot timers are fun little range toys. They clip on your belt. You press the big button, and some random amount of time later, it beeps. Then it starts timing how long from the beep, to the first shot:

It's a useful tool for practicing your draw, acquire, aim and fire routine, and exposes a lot of bad habits that rise to the surface when you are under time pressure. Some folks also use them as a competition tool as well (i.e. best score when timed).

They are also in the $100-$150 range, which is quite a lot for something pretty niche. Fundamentally, they are a computer with one function. I'm sure there's many Android apps that also can act as shot timers, but since I have a low-IQ phone, and who actually wants to deal with pulling their phone out of their pocket, and then awkwardly maneuvering it back in after hitting the app button, before freeing up their hand to shoot, it occurred to me I might be able to program the computer on my wrist, instead: my Garmin Fenix 8 Pro.

Now, I have this watch for reasons that I will get into at some other point, but it's a pretty incredible package, with LTE, Iridium Satellite network, Bluetooth, WiFi, etc. It has a microphone, a speaker, and a touchscreen. It ought to be trivial to detect a gunshot and...wait, what's that? Connect IQ, which is Garmin's actually not that terrible SDK for their watches, does not expose the microphone.

...

Well, perhaps there's another way to do this. The watch does have an accelerometer. Maybe I can actually use that to detect the gunshot? I found this interesting publication on PLoS One that describes the typical accelerometer signature from a handgun:

Pasted image 20260419202859

I figured we could actually probably reliably detect the Y signature with relative ease. The question was basically going to come down to if we could tell it apart from a normal draw motion, and if the window was long enough to be picked up by the Fenix's polling rate.

The actual implementation is as follows: poll at 25 Hz (it's unclear whether Garmin watches can poll faster, it's configurable but not something I have yet played with). Each poll arrives as three parallel arrays: accel.x/y/z. We compute the magnitude per sample as mag = √(x² + y² + z²), and then compute jerk, not acceleration, as |mag[i] − mag[i−1]|. In other words, we are looking at the delta between consecutive samples, not raw magnitude itself. Since gunshots are sharp transients, not sustained events, this signature seemed to make the most sense. Finally, if jerk > threshold (defaults to 1.5 g, but is configurable in-app), that sample is detected as a gunshot.

It turns out that this works fairly well. I am primarily shooting a S&W 329 PD. For the uninitiated, this is a .44 Magnum in a scandium frame with a titanium cylinder. In other words, a very large cartridge through a very light gun, and it produces significant jerk.

The app flow is as such: press the top right ("Select") button on the watch. It waits a random time (configurable), then vibrates and beeps. At that point, the timer starts, and the app logs when it detects the first shot, and displays that. Nothing fancy, but an extremely convenient package. I hope to eventually do more with the gunshot detection in other apps (to be continued...).

The code and compiled .prg file are available at https://github.com/ccgauvin94/ShotTimer - to install the app, connect the USB cable to your watch, and drag and drop it into the Apps folder. I've not tried compiling for any other watch, but I imagine it will build for any Garmin watch that supports accelerometers.