### 如何使用 Python 绘制曲线的上下包络线
为了实现这一目标,通常会采用信号处理技术来提取给定时间序列数据的最大和最小局部极值点,并通过插值方法构建上包络线和下包络线。下面展示了一个具体的例子,该实例利用 `scipy` 库中的 `find_peaks()` 函数找到峰值位置,再借助于三次样条插值(`CubicSpline`)完成光滑连接这些峰点形成最终的包络线。
#### 示例代码:绘制正弦波形及其对应的上下包络线
```python
import numpy as np
from scipy.signal import find_peaks, argrelextrema
from scipy.interpolate import CubicSpline
import matplotlib.pyplot as plt
# 创建模拟的时间序列数据
t = np.linspace(0, 10, num=500)
x = np.sin(t)
# 查找所有的极大值与极小值索引
peaks_max_indices, _ = find_peaks(x)
peaks_min_indices = argrelextrema(-x, np.greater)[0]
# 使用立方样条插值创建平滑的包络线
cs_upper = CubicSpline(peaks_max_indices, x[peaks_max_indices], bc_type='natural')
cs_lower = CubicSpline(peaks_min_indices, x[peaks_min_indices], bc_type='natural')
# 插入额外的端点以确保完整的覆盖范围
all_points = np.sort(np.concatenate([peaks_max_indices, peaks_min_indices]))
extended_t = np.append(all_points, [0, len(t)-1])
upper_envelope = cs_upper(extended_t)
lower_envelope = cs_lower(extended_t)
plt.figure(figsize=(8, 6))
plt.plot(t, x, color="blue", alpha=0.7, linewidth=2., label="Original Signal")
plt.scatter(t[peaks_max_indices], x[peaks_max_indices], c="red", marker="o", s=30, zorder=5, label="Maxima Points")
plt.scatter(t[peaks_min_indices], x[peaks_min_indices], c="green", marker="v", s=30, zorder=5, label="Minima Points")
# 将原始数据映射到扩展后的坐标系中用于绘制定义域内的完整包络线
mapped_x_values = (np.arange(len(t)) / (len(t) - 1)) * (max(extended_t) - min(extended_t)) + min(extended_t)
plt.fill_between(mapped_x_values, upper_envelope[mapped_x_values.astype(int)], lower_envelope[mapped_x_values.astype(int)],
where=None, interpolate=True, facecolor='yellow', alpha=.3, label="Upper & Lower Envelopes")
plt.title("Sinusoidal Waveform with Upper and Lower Envelopes")
plt.xlabel('Time')
plt.ylabel('Amplitude')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
```
此段程序首先定义了一组代表理想化正弦波动的数据集;接着分别定位到了这串数据里的最大值和最小值所在的位置;最后运用了基于上述两者的三次多项式拟合方式得到了两条连续变化着的边界线——即所谓的“上包络线”和“下包络线”。值得注意的是,在实际应用当中可能还需要考虑更多因素比如噪声过滤等问题[^2]。