utils.math

Portable math utilities shared between robot code and host tools.

 1"""Portable math utilities shared between robot code and host tools."""
 2
 3from .curves import (
 4    default_segment_points,
 5    default_spline_points,
 6    evaluate_segments,
 7    evaluate_spline,
 8    hermite_eval,
 9    numerical_slope,
10)
11
12__all__ = [
13    "default_segment_points",
14    "default_spline_points",
15    "evaluate_segments",
16    "evaluate_spline",
17    "hermite_eval",
18    "numerical_slope",
19]
def default_segment_points() -> list[dict]:
75def default_segment_points() -> list[dict]:
76    """Generate default 3-point linear control points (y = x)."""
77    return [
78        {"x": -1.0, "y": -1.0},
79        {"x": 0.0, "y": 0.0},
80        {"x": 1.0, "y": 1.0},
81    ]

Generate default 3-point linear control points (y = x).

def default_spline_points() -> list[dict]:
37def default_spline_points() -> list[dict]:
38    """Generate default 3-point linear control points (y = x)."""
39    return [
40        {"x": -1.0, "y": -1.0, "tangent": 1.0},
41        {"x": 0.0, "y": 0.0, "tangent": 1.0},
42        {"x": 1.0, "y": 1.0, "tangent": 1.0},
43    ]

Generate default 3-point linear control points (y = x).

def evaluate_segments(points: list[dict], x: float) -> float:
 84def evaluate_segments(points: list[dict], x: float) -> float:
 85    """Evaluate the piecewise-linear curve at input *x*.
 86
 87    Linearly interpolates between adjacent control points.
 88    """
 89    if not points or len(points) < 2:
 90        return x
 91    x = max(points[0]["x"], min(points[-1]["x"], x))
 92    for i in range(len(points) - 1):
 93        x0, x1 = points[i]["x"], points[i + 1]["x"]
 94        if x <= x1 or i == len(points) - 2:
 95            dx = x1 - x0
 96            if dx == 0:
 97                return points[i]["y"]
 98            t = (x - x0) / dx
 99            y0, y1 = points[i]["y"], points[i + 1]["y"]
100            return y0 + t * (y1 - y0)
101    return x

Evaluate the piecewise-linear curve at input x.

Linearly interpolates between adjacent control points.

def evaluate_spline(points: list[dict], x: float) -> float:
46def evaluate_spline(points: list[dict], x: float) -> float:
47    """Evaluate the cubic hermite spline at input *x*, returning output *y*.
48
49    Mathematically identical to wpimath.spline.CubicHermiteSpline.
50    """
51    if not points or len(points) < 2:
52        return x
53    x = max(points[0]["x"], min(points[-1]["x"], x))
54    for i in range(len(points) - 1):
55        x0, x1 = points[i]["x"], points[i + 1]["x"]
56        if x <= x1 or i == len(points) - 2:
57            dx = x1 - x0
58            if dx == 0:
59                return points[i]["y"]
60            t = (x - x0) / dx
61            return hermite_eval(
62                points[i]["y"], points[i]["tangent"],
63                points[i + 1]["y"], points[i + 1]["tangent"],
64                dx, t)
65    return x

Evaluate the cubic hermite spline at input x, returning output y.

Mathematically identical to wpimath.spline.CubicHermiteSpline.

def hermite_eval(y0, m0, y1, m1, dx, t):
19def hermite_eval(y0, m0, y1, m1, dx, t):
20    """Evaluate one cubic hermite segment at parameter *t* in [0, 1].
21
22    Args:
23        y0, y1: endpoint Y values
24        m0, m1: endpoint slopes (dy/dx)
25        dx: segment width (x1 - x0)
26        t: parameter in [0, 1]
27    """
28    t2 = t * t
29    t3 = t2 * t
30    h00 = 2 * t3 - 3 * t2 + 1
31    h10 = t3 - 2 * t2 + t
32    h01 = -2 * t3 + 3 * t2
33    h11 = t3 - t2
34    return h00 * y0 + h10 * dx * m0 + h01 * y1 + h11 * dx * m1

Evaluate one cubic hermite segment at parameter t in [0, 1].

Args: y0, y1: endpoint Y values m0, m1: endpoint slopes (dy/dx) dx: segment width (x1 - x0) t: parameter in [0, 1]

def numerical_slope(points: list[dict], x: float) -> float:
68def numerical_slope(points: list[dict], x: float) -> float:
69    """Estimate dy/dx at *x* by central difference."""
70    eps = 0.001
71    return (evaluate_spline(points, x + eps)
72            - evaluate_spline(points, x - eps)) / (2 * eps)

Estimate dy/dx at x by central difference.