Causality APIs 23: The Serve Broke Down. Or Did The Same Motion Never Exist?

A tennis serve is practiced as a repeatable motion, but match pressure changes toss variability, fatigue, target risk, and contact point. A causal detective story separates those suspects.

A tennis player hits serve after serve in practice. The motion is drilled, filmed, corrected, repeated, and repeated again. Then the match gets tight and the serve disappears.

The usual explanation is mechanical: the serve broke down. The better detective story starts one step earlier. A serve is not one identical event repeated forever. The toss changes. The legs tire. The target changes. The score changes the body.

The same serve motion never exists twice; the causal question is which source of variation pushed the error over the line.

Share: A tennis serve is repetitive practice under changing toss, timing, fatigue, pressure, and target conditions. #Causality #Tennis #SportsAnalytics

This article uses a causal detective story to explain why high-volume practice does not eliminate serve errors.

Start with the apparent cause

Professional tennis moves into Rome in early May; the Association of Tennis Professionals (ATP) lists the Internazionali BNL d’Italia in Rome for May 6-17, 2026 [1]. Clay-court conditions, long rallies, and pressure games make the serve feel less automatic than it looks in practice.

The apparent cause is simple:

  • the player missed because the serve mechanics failed

That is not wrong. It is just not specific enough to fix.

Biomechanics research treats the tennis serve as a variable movement, not a perfectly duplicated machine motion. Studies have examined motor variability, toss variability, serve accuracy, and pressure effects [2, 3, 4].

Put the suspects on the board

The directed acyclic graph (DAG), a graph whose arrows do not loop back on themselves, uses TossVariability, Fatigue, and RiskChoice as competing treatment suspects, with ServeError as the outcome:

  • PracticeVolume: repetitions and drilling
  • Fatigue: tired legs, shoulder load, and loss of precision
  • MatchPressure: score and consequence
  • TossVariability: how far the toss moves from the intended window
  • RiskChoice: how aggressive the target is
  • ContactPointError: mismatch between body and ball
  • ServeError: fault or weak serve outcome

Directed acyclic graph linking practice volume, fatigue, match pressure, toss variability, risk choice, contact-point error, and serve error

Here is the graph as a py-scm setup. This uses the py-scm reference implementation for a continuous Gaussian structural causal model (SCM). An SCM defines each variable through direct causes. The coefficients are illustrative.

import numpy as np

from pyscm.reasoning import create_reasoning_model

nodes = [
    "PracticeVolume",
    "Fatigue",
    "MatchPressure",
    "TossVariability",
    "RiskChoice",
    "ContactPointError",
    "ServeError",
]

weighted_edges = [
    ("PracticeVolume", "TossVariability", -0.55),
    ("PracticeVolume", "RiskChoice", 0.20),
    ("PracticeVolume", "ServeError", -0.15),
    ("Fatigue", "TossVariability", 0.45),
    ("Fatigue", "ContactPointError", 0.35),
    ("Fatigue", "ServeError", 0.20),
    ("MatchPressure", "TossVariability", 0.25),
    ("MatchPressure", "RiskChoice", 0.25),
    ("MatchPressure", "ServeError", 0.25),
    ("TossVariability", "ContactPointError", 0.90),
    ("RiskChoice", "ServeError", 0.50),
    ("ContactPointError", "ServeError", 0.80),
]

idx = {node: i for i, node in enumerate(nodes)}
B = np.zeros((len(nodes), len(nodes)))
for parent, child, weight in weighted_edges:
    B[idx[child], idx[parent]] = weight

A = np.eye(len(nodes)) - B
cov = np.linalg.inv(A) @ np.eye(len(nodes)) @ np.linalg.inv(A).T

model = create_reasoning_model(
    {"nodes": nodes, "edges": [(p, c) for p, c, _ in weighted_edges]},
    {"v": nodes, "m": [0.0] * len(nodes), "S": cov.tolist()},
)

The graph says practice helps by reducing toss variability and direct error. It does not make fatigue or pressure disappear.

Test the suspects

The inference code compares three intervention contrasts:

toss_effect = model.equery(
    "ServeError",
    {"TossVariability": 1.0},
    {"TossVariability": 0.0},
)
fatigue_effect = model.equery(
    "ServeError",
    {"Fatigue": 1.0},
    {"Fatigue": 0.0},
)
risk_effect = model.equery(
    "ServeError",
    {"RiskChoice": 1.0},
    {"RiskChoice": 0.0},
)

The first query changes toss variability. The second changes fatigue. The third changes target risk.

Observed toss-variability gap: +0.94
Intervention toss effect:      +0.72

Observed fatigue gap:          +0.80
Intervention fatigue effect:   +0.80

Observed target-risk gap:      +0.50
Intervention target effect:    +0.50

In this toy model, toss variability has a large causal effect through contact-point error. Fatigue has a large effect because it changes both toss and contact. Target risk matters, but it is a different fix.

Observed serve-error slices compared with intervention effects for toss variability, fatigue, and target risk

The landing chart shows the intuition. Practice landings are tighter. Pressure landings widen and drift. The target window did not move; the distribution did.

Scatter plot of tennis serve landings showing tighter practice dispersion and wider pressure dispersion around a target window

How players overcome the error

The model points to different interventions:

  • reduce toss variability with a routine that makes the toss cancellable when it leaves the window
  • reduce fatigue effects by practicing serves after physical load, not only at the start of a session
  • reduce target risk by choosing bigger margins on second serves and pressure points
  • practice pressure explicitly so MatchPressure is not a new parent in the graph on match day

The fix is not “serve more” by itself. The fix is to practice the sources of variation that appear when the serve actually matters.

Sources

  1. Internazionali BNL d’Italia, ATP Tour, accessed April 28, 2026.
  2. Relationship between motor variability, accuracy, and ball speed in the tennis serve, PubMed, accessed April 28, 2026.
  3. Biomechanical case study on toss up motion in tennis serve, International Society of Biomechanics in Sports, accessed April 28, 2026.
  4. Preventing a loss of accuracy of the tennis serve under pressure, PLOS One, accessed April 28, 2026.

Download the runnable standalone Python example: Python example ZIP.

Leave a Reply

Discover more from Rocket Vector Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading