Quantcast
Channel: Predict trajectory of a bouncing ball - Stack Overflow
Viewing all articles
Browse latest Browse all 5

Answer by Reinderien for Predict trajectory of a bouncing ball

$
0
0

@anatolyg's method is the correct first step. After that,

  • apply find_peaks;
  • perform a first piecewise polynomial regression: first-degree in x and second-degree in y; then
  • as a further step that I don't demonstrate, you need to enforce that the boundary positions match between each segment and then do an end-to-end fit where the physical parameters are shared across the whole dataset.
import matplotlib.pyplot as pltimport numpy as npimport scipy.signaldef fit(    t: np.ndarray,    x: np.ndarray,    y: np.ndarray,) -> tuple[    list[np.polynomial.Polynomial],  # x(t)    list[np.polynomial.Polynomial],  # y(t)]:    # Second-order differential. This assumes a monotonic t.    d2ydt2 = np.gradient(y, 2)    # Boundary conditions for each bounce segment    bounce_idx, props = scipy.signal.find_peaks(d2ydt2)    left_indices = (0, *bounce_idx)    right_indices = (*bounce_idx, len(t))    # Boolean arrays selecting each segment    segment_predicates = [        (d2ydt2 < 0)   # Must be falling& (t >= left)  # Must be within second-order peaks& (t < right)        for left, right in zip(left_indices, right_indices)    ]    x_polys = [        np.polynomial.polynomial.Polynomial.fit(            x=t[predicate], y=x[predicate], symbol='t', deg=1,        )        for predicate in segment_predicates    ]    y_polys = [        np.polynomial.polynomial.Polynomial.fit(            x=t[predicate], y=y[predicate], symbol='t', deg=2,        )        for predicate in segment_predicates    ]    return x_polys, y_polysdef dump(    x_polys: list[np.polynomial.Polynomial],    y_polys: list[np.polynomial.Polynomial],) -> None:    for i, (xp, yp) in enumerate(zip(x_polys, y_polys)):        print(f'Bounce {i}:')        print(f'  x={xp}')        print(f'  y={yp}')def plot(    t: np.ndarray,    x: np.ndarray,    y: np.ndarray,    x_polys: list[np.polynomial.Polynomial],    y_polys: list[np.polynomial.Polynomial],) -> plt.Figure:    fig, ax = plt.subplots()    ax.scatter(x, y, marker='+', label='experiment')    tfine = np.linspace(start=t[0], stop=t[-1], num=201)    for xp, yp in zip(x_polys, y_polys):        xt = xp(tfine)        yt = yp(tfine)        use = yt >= 0        ax.plot(xt[use], yt[use])    return figdef main() -> None:    x = np.array((        7.410000e-03, 9.591000e-02, 2.844100e-01, 5.729100e-01, 9.614100e-01,        1.449910e+00, 2.038410e+00, 2.726910e+00, 3.373700e+00, 4.040770e+00,        4.800040e+00, 5.577610e+00, 6.355180e+00, 7.132750e+00, 7.910320e+00,        8.687900e+00, 9.465470e+00, 1.020976e+01, 1.092333e+01, 1.163690e+01,        1.235047e+01, 1.306404e+01, 1.377762e+01, 1.449119e+01,    ))    y = np.array((        2.991964, 2.903274, 2.716584, 2.431894, 2.049204, 1.568514, 0.989824, 0.313134,        0.311512, 0.646741, 0.88397 , 1.0232  , 1.064429, 1.007658, 0.852887, 0.600116,        0.249345, 0.232557, 0.516523, 0.702488, 0.790454, 0.78042 , 0.672385, 0.466351,    ))    t = np.arange(len(x), dtype=x.dtype)    x_polys, y_polys = fit(t=t, x=x, y=y)    dump(x_polys=x_polys, y_polys=y_polys)    plot(t=t, x=x, y=y, x_polys=x_polys, y_polys=y_polys)    plt.show()if __name__ == '__main__':    main()
Bounce 0:  x=1.01716 + 1.35975·(-1.0 + 0.28571429t)  y=2.252799 - 1.339415·(-1.0 + 0.28571429t) - 0.60025·(-1.0 + 0.28571429t)²Bounce 1:  x=7.910324 + 1.555146·(-7.0 + 0.5t)  y=0.852887 - 0.407542·(-7.0 + 0.5t) - 0.196·(-7.0 + 0.5t)²Bounce 2:  x=13.77761667 + 0.713575·(-22.0 + t)  y=0.672385 - 0.1570345·(-22.0 + t) - 0.0489995·(-22.0 + t)²

fit


Viewing all articles
Browse latest Browse all 5

Trending Articles