Making My Apple Watch Strike Detector Useful for Training

·2300 words·11 minute read

In the previous post, I removed the contact-quality score from my Apple Watch hurling app. It was one of those ideas that looked convincing in the app, but I could not properly explain what the number meant. I decided to keep the measurements, let the player rate their own strikes, and stop trying to turn wrist data into a judgement about technique.

Since then, I have mostly gone in that direction. Instead of finding another formula for strike quality, I rebuilt how the Watch records motion, retrained the model to recognise more types of strike, and added tools for comparing practice sessions over time.

I also bought an Apple Watch Series 11.

The decision came after I watched Apple’s WWDC 2023 session “What’s new in Core Motion”. Apple used a baseball swing to demonstrate the new high-rate sensor API: 800 Hz acceleration to find impact, 200 Hz device motion to find the beginning of the swing, then the difference between those timestamps to calculate Time to Contact.

That example was very close to the problem I had been working on with hurling. It was the point where buying a newer Watch started to feel worthwhile rather than just nice to have.

My Series 6 was fine for the earlier experiments, but it could not record those two high-rate streams. The first recordings in this project were captured at 50 Hz, followed by later sessions at 100 Hz. Moving to the new Watch gave me a much better source for contact timing, although it did not suddenly make the data easy to interpret.

Two Sensor Streams With Different Jobs

The Watch does not record everything at 800 Hz. Each session contains two motion streams:

  • Device motion at 200 Hz, including user acceleration, rotation rate, gravity, and Watch orientation.
  • Raw acceleration at 800 Hz, which captures the short, sharp changes around contact.

The split is useful because the streams do different jobs. The CNN runs on the 200 Hz device-motion data. I also use that stream for movement metrics and the 3D visualisation. The 800 Hz acceleration is used to place contact more precisely and calculate timing. It gives me roughly one raw acceleration sample every 1.25 milliseconds around the impact.

Both streams have their own timestamps, so I align them by time rather than assuming that every device-motion sample has exactly four matching acceleration samples. Sensor batches can be delayed and recordings can contain small gaps. The timestamps keep those gaps visible.

I also moved away from CSV files. A session is now stored as two compact binary files and a metadata file inside an .mmrec package. The same package can transfer from the Watch to the iPhone, open in my analysis tool, and later be used for model training. I decided not to add a lower-frequency fallback for older Watches because I want new recordings to follow the same format.

Apple Watch practice session split into 200 Hz device motion for classification and movement analysis, and 800 Hz raw acceleration for contact timing.
Fig 1. The two motion streams are recorded together but used for different parts of the analysis.

From One Strike Label to Five Classes

The model from my earlier posts answered a simple question: strike or non-strike. That was enough to get detection working, but it was not enough to describe a full practice session.

The current model has five classes: non-strike, regular dominant strike, non-dominant strike, ground strike, and free-puck. I did not jump straight to five. First I retrained the model on the native 200 Hz data. Then I separated dominant and non-dominant strikes. Ground strikes came next, after reviewing individual attempts showed that they did not fit the same timing rules as self-toss air strikes. Free-puck was the final class I added.

Free-pucks needed more motion before contact than an ordinary self-toss strike. The current input window contains 160 samples, or about 0.8 seconds at 200 Hz, and more of that window sits before the prediction point. This lets the model see more of the preparation and lift instead of mostly seeing the final swing.

Fig 2 shows the latest training run. The graph on the left is training and validation loss. The one on the right is macro F1 across the five classes. I pay more attention to F1 than plain accuracy because the recordings contain far more background than actual strikes. The validation score finishes above 0.9, although it jumps around more than the training score because the validation set is much smaller.

Training and validation loss alongside five-class macro F1 over 50 epochs for the strike model.
Fig 2. Training and validation loss, with the class-balanced F1 score across all five model classes.

The confusion matrix is easier to read than one overall accuracy number. In this validation split, the model found all 52 regular strikes, 83 non-dominant strikes, and 69 ground strikes. It found 143 of 150 free-pucks, while the other seven were classified as regular strikes.

There are more than 12,000 non-strike windows in the same split. If I only reported accuracy, that large background class would make the result look better than it really is. The smaller strike classes are the interesting part.

Validation confusion matrix for non-strike, regular strike, non-dominant strike, ground strike, and free-puck classes.
Fig 3. Most validation events land on the diagonal. The main remaining confusion is between free-pucks and regular strikes.

The probability plots show roughly the same thing. Most correct predictions are close to full confidence, while free-puck is more spread out. It is now a useful class, but some examples are still much less obvious to the model than others.

Histograms of predicted probabilities for each of the five model classes.
Fig 4. Correct predictions are usually confident, while free-puck has a wider range of confidence values.

I also had a couple of dead ends. A hierarchical model, which first separated strikes from non-strikes and then classified the subtype, sounded sensible but treated most validation free-pucks as regular strikes. I tried another version with positive windows aligned directly around impact, and all five of its canonical validation free-pucks became regular strikes as well. In both cases I went back to the simpler flat five-class model.

There is still an important limit to the free-puck label. It means the wrist motion looks like the lift-and-strike examples in my training data. The Watch does not know whether it happened during a match or what the playing context was.

Finding the Beginning of the Swing

Once the CNN finds the rough strike range, I switch to the 800 Hz stream to refine contact. I then look backwards from contact to find the beginning of the swing.

For the self-toss strikes I usually practise, there is often a small movement when the ball leaves the hand, followed by the main swing. The analyser searches for the latest completed placement movement and uses its strongest acceleration peak as the start. If that is not clear, it can fall back to wrist rotation or the beginning of the main acceleration rise. Nearby aftershocks are grouped so that a smaller wobble does not move the start forward.

Time to Contact is simply the elapsed time from that selected start to contact. I use it as a timing measurement, not a quality score.

The raw-acceleration graph shows the two points used for this calculation: start and contact.

Raw acceleration along three axes with analysis markers for the selected swing start and detected contact.
Fig 5. The 800 Hz acceleration signal with the selected start and detected contact.

Ground strikes exposed another assumption in this calculation. They can have a detectable contact, but there is no self-toss placement movement to use as the start. For that reason, I do not calculate Time to Contact or projected Hand Speed for ground strikes. Wrist Rotation Speed and Peak Jerk can still be available around contact.

Turning Recordings Into Practice Sessions

Detection and metrics are not very useful if reviewing them is awkward. I wanted the normal flow to stay simple: start a session on the Watch, practise and rate the latest strike, stop the recording, then review the session on the iPhone.

The iPhone review shows detected attempts, my ratings, an optional note, summary measurements, charts, and estimated 3D paths. Ratings stay separate from the sensor data. They are my own assessment on a 0–10 scale. A zero can mark the latest candidate as a miss, while other ratings can sit beside Time to Contact, Projected Hand Speed, or Wrist Rotation Speed without changing those measurements.

Session Review showing 15 detected strikes, summary measurements, and the start of the strike comparison chart.
Fig 6. Session Review combines detected strikes, ratings, summary measurements, and per-strike comparison.

The screenshot says 15 strikes were detected but refers to Strike 22 in one summary card. The number follows the complete attempt sequence, including misses and uncertain attempts that are hidden from the successful-strikes view.

After removing contact quality, I was careful not to rebuild the same idea with different-looking charts. The comparison view shows one measurement at a time, and all the bars use the same treatment. A taller bar is not marked as better. A shorter Time to Contact is not marked as an improvement. The bars are there to help me compare attempts from the same session.

Dominant, non-dominant, and dominant free-puck attempts are kept apart because their preparation and movement are different. Ground strikes are also left out of comparisons that depend on a self-toss start.

Comparing the Shape of a Swing

I wanted to keep working on the 3D view from Part 3, but comparing several reconstructed paths is difficult when they all begin in slightly different orientations.

The analyser now moves every path to a common origin, aligns its main pre-contact movement plane and early direction, and chooses a real strike near the centre of the group as the reference. The other paths are rotated towards it, and the same rotation is applied to their follow-through.

It does not mirror or resize the paths. It also does not stretch the timing to force different swings into the same shape. Differences should still be visible after alignment. The result is useful for comparison, but it is still an estimate of Watch movement rather than a measured path of the hand, hurley, or ball.

I can also save attempts as Reference Strikes. These are strikes I chose, not strikes the app judged to be best. A few saved strikes in one category can form a Reference Average for later sessions. Dominant, non-dominant, and dominant free-puck references are kept separate.

I like this direction much more than the old contact-quality score. Instead of trying to define a universally good strike, I can compare a new session with examples that felt useful to me.

Session Review showing Time to Contact bars and estimated 3D strike paths compared with a Reference Average.
Fig 7. The same session can be compared using individual measurements and estimated 3D paths.

Two Months of Personal Progress

The part I find most satisfying is not the model evaluation. It is finally having enough practice history to see whether my own measurements are changing.

The Home screen has progress cards for Time to Contact, Projected Hand Speed, and Wrist Rotation Speed. Each point is the average of valid strikes from one session. When I record more than one session on the same day, they share one point on the chart, but I can still open the individual sessions.

The large number is the latest measured session average. The dashed line is an estimated trend across the compatible sessions. I use a robust trend calculation so that one unusually high or low day has less influence, and the line only appears after there are enough sessions and strikes.

My current charts cover 26 sessions and 402 measured strikes across roughly two months. Over that period, Time to Contact is estimated to be 21% faster and Wrist Rotation Speed is estimated to be 10% faster.

There is a great feedback loop here. I needed more data for the app, so I kept going out to practise. Because I practised more, I started to improve, and the measurements began to move as well.

I can feel that my striking has improved, but the percentages are not a measurement of my overall hurling ability. They describe two signals from one sensor on my wrist. Accuracy, technique, decision-making, playing under pressure, and plenty of other parts of the game are outside these charts.

Home screen with Time to Contact and Wrist Rotation Speed progress cards across 26 practice sessions.
Fig 8. Progress across 26 sessions and 402 measured strikes. Time to Contact trends 21% faster and Wrist Rotation Speed trends 10% faster.

What the Watch Still Cannot Tell Me

The limitations from Part 3 have not disappeared.

Projected Hand Speed comes from integrating acceleration over a short swing window. It is useful when comparing similar recordings, but it is not hurley-head speed or ball speed.

The 3D path still contains drift, and a Watch on the wrist cannot account for the full movement of the hurley. Peak Jerk helps me find contact, but it changes with the ball, grip, vibration, and where contact happened. None of these measurements can tell the whole story on their own.

The project started as a strike detector, then briefly became an attempt to score strike quality. Now it feels more useful as a training log: record a session, recognise different attempts, compare their timing and movement, and look back over repeated practice.

The new Apple Watch Series 11 gives me better raw data, but it still cannot tell me whether a strike was good. That part is much more complicated than collecting more samples. For now, I am happy for the app to measure a few things honestly and give me another reason to keep practising.

What Is Next

The next step is user testing. I plan to share the TestFlight build with teammates and other people who are interested, then see how the app behaves with different players and practice routines.

I also want to explore having two recording modes. Training Mode would keep the current focus on individual strikes and practice-session review. Play Mode would look at the broader activity during a match or training game, starting with time spent running or idle and a few other session-level measurements. This is still an early idea, so I have not decided exactly which metrics will be useful yet.