
本文介绍如何基于正态分布概率密度函数(pdf)生成覆盖整数区间 [0, 10] 的平滑钟形高度序列,支持自由设定峰值位置(如偏移至 x=3)和最大高度(如 100),并提供可交互拖拽调节的 chart.js 实现方案。
在程序化生成地形、UI 动画缓动曲线或数据可视化中,常需构造一条“钟形”高度分布——起始于 0、终止于 10、峰值可控、整体平滑。虽然贝塞尔曲线(如 BezierJS)灵活直观,但若仅需数学上可预测、可参数化、易缩放的单峰曲线,正态分布的概率密度函数(PDF)是更简洁高效的选择。
✅ 核心原理:正态 PDF + 线性归一化
正态 PDF 公式如下(无需积分,仅求点值):
$$ f(x) = \frac{1}{\sigma\sqrt{2\pi}} \cdot e^{-\frac{(x-\mu)^2}{2\sigma^2}} $$
其中:
- μ(mean)控制峰值横坐标(如设为 3 即峰值在 x=3);
- σ(stdDev)控制“宽度”:σ 越小,曲线越陡峭;越大则越扁平;
- 函数天然关于 μ 对称,满足“钟形”要求。
由于 PDF 原始输出最大值不为 100,我们采用线性缩放法:先计算所有采样点中的最大 y 值 maxY,再将每个 y 乘以缩放因子 100 / maxY,确保最终数组严格满足 maxHeight = 100。
? 示例代码(完整可运行)
以下代码生成 [0,1,2,...,10] 对应的 11 个高度值,并用 Chart.js 可视化,集成 chartjs-plugin-dragdata 支持拖拽调节各点:
⚠️ 注意事项与进阶提示
- 非对称需求? 正态 PDF 天然对称。若需真正左/右偏斜(skewed bell),可考虑 Skew Normal Distribution 或分段二次/三次插值(如使用 BezierJS 构造控制点后 curve.get(t) 采样)。
- 整数点精度: 上述代码以 step = 1 严格对应 [0,1,...,10],若需更高密度(如每 0.5 单位采样),只需调整 step 并对结果取整或插值。
- 性能友好: PDF 计算为 O(n),无迭代或数值积分,适合实时生成(万级点亦无压力)。
-
替代库参考:
- BezierJS:适合手绘拟合 → const curve = new Bezier(p0, p1, p2, p3); curve.get(t);
- mathjs:提供 math.distribution('Normal') 封装;
- d3-shape:d3.line().curve(d3.curveBasis) 用于平滑连接离散点。
✅ 总结:当目标是参数简洁、数学可控、峰值可偏移、结果确定的钟形高度生成时,正态 PDF + 线性归一化是最轻量且专业的方案;配合 Chart.js 插件,即可快速构建带 UI 交互的“迷你 Inkscape 曲线编辑器”。










