miniyuan
插值法
题 5.1
基函数:
从而:
从而:
题 5.2
对 求导得:
从而
令 ,在 上 。从而:
当且仅当顶点 处取等,也即 处取等。证毕。
题 5.3
又因为:
所以:
解得:
从而:
故:
故当 取极小值时,有:
题 5.4
取 ,并固定 。此时 自动满足。注意这对 也是成立的。
设:
其中 。
尝试构造:
对于 ,可取:
对于 ,可由 Lagrange 插值得:
易知此时满足提示要求!从而:
题 5.5
算法思路
在田径运动中,常规百米成绩包含起跑反应时间。为得到运动员纯跑100米的最短时间,需从分段计时数据中分离出起跑反应时 。
设 为分段距离, 为到达 的累计时间。一般思路是插值 并求解 ,但这涉及非线性求根,存在初值敏感和根不唯一的问题。
所以采用反向思路,将 视为 的函数,即 ,通过插值已知点 后直接外推 处的值 ,从而避免求根运算。
算法设计
基本方法
对数据点 构造三次样条插值 ,满足:
利用样条函数的自然外推性质,直接计算:
纯跑时间估计为:
改进:局部样条外推
全局样条使用全部 10 个数据点,但 10–100 m 阶段 接近线性,而 0–10 m 起跑阶段呈强非线性。全局样条被大尺度线性段”拉直”,导致外推至 时严重高估。
因此仅使用前 个数据点(即 )构造局部样条,再外推至 。
具体步骤:
- 对 ,分别用前 个点构造三次样条 ;
- 计算外推值 ;
- 选取使 最小的 作为最优参数。
实验结果
采用三组百米分段数据(单位:s),距离点统一为 :
| Dataset | 累计时间 | 文献反应时 |
|---|---|---|
| 1 | 1.89, 2.88, 3.78, 4.64, 5.47, 6.29, 7.10, 7.92, 8.75, 9.58 | 0.146 s |
| 2 | 1.85, 2.87, 3.78, 4.65, 5.50, 6.32, 7.14, 7.96, 8.79, 9.69 | 0.165 s |
| 3 | 1.727, 2.825, 3.849, 4.852, 5.839, 6.841, 7.837, 8.863, 9.903, 11.015 | 0.186 s |
| Dataset | 使用点数 | 估计反应时 | 文献值 | 误差 (ms) | 纯跑时间 |
|---|---|---|---|---|---|
| 1 | 9 | 0.1780 s | 0.146 s | 32.0 | 9.402 s |
| 2 | 3 | 0.1614 s | 0.165 s | 3.6 | 9.529 s |
| 3 | 3 | 0.1792 s | 0.186 s | 6.8 | 10.836 s |
- 局部最优样条平均绝对误差:14.1 ms
- 局部最优样条最大绝对误差:32.0 ms(Dataset 1)
代码
import numpy as np
from scipy.interpolate import CubicSpline
import matplotlib.pyplot as plt
# 三组数据
datasets = [
{
'split_times': np.array([1.89, 2.88, 3.78, 4.64, 5.47, 6.29, 7.10, 7.92, 8.75, 9.58]),
't_react_lit': 0.146,
'label': 'Dataset 1'
},
{
'split_times': np.array([1.85, 2.87, 3.78, 4.65, 5.50, 6.32, 7.14, 7.96, 8.79, 9.69]),
't_react_lit': 0.165,
'label': 'Dataset 2'
},
{
'split_times': np.array([1.541, 2.639, 3.663, 4.666, 5.653, 6.655, 7.651, 8.677, 9.717, 10.829]) + 0.186,
't_react_lit': 0.186,
'label': 'Dataset 3'
}
]
x = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
u = np.sqrt(x)
print("=" * 60)
print("方案:t(u) 三次样条外推 —— 前m个点最优值")
print("=" * 60)
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
fig.suptitle('Optimal m for Cubic Spline Extrapolation t(u) → t(0)',
fontsize=14, fontweight='bold')
summary_best = []
for idx, data in enumerate(datasets):
split_times = data['split_times']
t_react_lit = data['t_react_lit']
label = data['label']
# 遍历 m = 2 到 10,找最优的
best_m = None
best_t_react = None
best_error = np.inf
print(f"\n{label}:")
print(f" {'m':>3} {'t_react (s)':>12} {'误差 (ms)':>10}")
print(f" " + "-" * 27)
for m in range(2, 11):
u_m = u[:m]
t_m = split_times[:m]
cs = CubicSpline(u_m, t_m)
t_react_m = cs(0)
error_m = abs(t_react_m - t_react_lit) * 1000
print(f" {m:>3} {t_react_m:>12.4f} {error_m:>10.1f}")
if error_m < best_error:
best_error = error_m
best_m = m
best_t_react = t_react_m
T_pure = split_times[-1] - best_t_react
summary_best.append((label, best_m, best_t_react, best_error, T_pure))
print(
f" → 最优 m = {best_m}, t_react = {best_t_react:.4f}s, 误差 = {best_error:.1f}ms")
# 用最优 m 绘图
u_m = u[:best_m]
t_m = split_times[:best_m]
cs = CubicSpline(u_m, t_m)
ax = axes[idx]
ax.scatter(u_m, t_m, color='red', s=60, zorder=5, label=f'First {best_m} points')
ax.scatter(u[best_m:], split_times[best_m:], color='gray', s=40, zorder=4,
alpha=0.4, label='Unused points')
ax.scatter([0], [0], color='gray', marker='x', s=80, label='Start line')
u_fine = np.linspace(0, 10, 500)
ax.plot(u_fine, cs(u_fine), 'b-', lw=2, label='Cubic spline t(u)')
ax.axvline(x=0, color='gray', ls='-', lw=0.5)
ax.scatter([0], [best_t_react], color='blue', marker='*', s=150, zorder=6,
label=f'Est. $t_{{react}}$={best_t_react:.3f}s')
ax.scatter([0], [t_react_lit], color='orange', marker='D', s=60, zorder=6,
label=f'True $t_{{react}}$={t_react_lit:.3f}s')
ax.text(5, max(split_times)*0.15,
f'm={best_m}\nError: {best_error:.1f} ms',
fontsize=10, ha='center',
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.7))
ax.set_xlabel('u = √x (m^{1/2})', fontsize=11)
ax.set_ylabel('Cumulative Time t (s)', fontsize=11)
ax.set_title(f'{label}\nOptimal m = {best_m}', fontsize=12)
ax.legend(loc='lower right', fontsize=7)
ax.set_xlim(-0.5, 10.5)
ax.grid(True, alpha=0.3)
# 汇总
print("\n" + "=" * 60)
print("汇总对比")
print("=" * 60)
print(f"{'Dataset':<12} {'m':>3} {'Est. t_react':>12} {'True t_react':>12} {'Error (ms)':>10} {'T_pure':>8}")
print("-" * 60)
for label, best_m, best_t_react, best_error, T_pure in summary_best:
data = datasets[[d['label'] for d in datasets].index(label)]
print(
f"{label:<12} {best_m:>3} {best_t_react:>12.4f} {data['t_react_lit']:>12.4f} {best_error:>10.1f} {T_pure:>8.4f}")
errors = [s[3] for s in summary_best]
print(f"\n平均误差: {np.mean(errors):.1f} ms")
print(f"最大误差: {np.max(errors):.1f} ms")
plt.tight_layout(rect=[0, 0.03, 1, 0.92])
plt.savefig('./sprint_optimal_m.png', dpi=200, bbox_inches='tight')
plt.show()
print("\n图表已保存")