Part I · 第 2 章 微积分 · 2.1

导数:局部线性近似

用显微镜看一条光滑曲线,放大得足够多,它就变成一条直线。这条直线的斜率就是导数。机器人里几乎所有"线性化"都是这一句话:在工作点附近,把复杂的函数换成一条直线,算起来便宜得多,误差也有明确的上界。

约 20 分钟 前置:函数与直线(高中数学) 5 个交互

    1为什么机器人需要它

    轮子上的编码器只会告诉你"现在转到了哪个角度"。可控制器要的是转速,规划器要的是加速度。从位置到速度,中间隔着一次求导。

    另一件事更普遍:机器人的世界几乎全是非线性的。关节角到末端位置有 \(\sin\)、\(\cos\),相机投影要除以深度。非线性函数很难直接分析,直线却很好对付。导数就是把曲线在一点附近换成直线的方法:EKF 的线性化、逆运动学的每一步迭代、Newton 法、反向传播,全靠它。

    这一节只做三件事:看清导数是什么(一条放大后的直线),知道这个近似好到什么程度(误差随距离的平方缩小),再看一个它会咬人的地方(对带噪声的数据求导)。

    2直觉:显微镜下的曲线是直线

    地球是圆的,可站在操场上它是平的。曲线上任何一点附近都是这样:放得够大,弯曲就看不出来了。放大后看到的那条直线,斜率就是导数 \(f'(x_0)\)。

    下面是一台"显微镜"。拖动黄点选位置,拖动滑块放大。先在平滑的曲线上试,再换成 \(|x|\),看看会发生什么。

    FIG 1放大镜:曲线什么时候变直?
    蓝青色是曲线,黄色虚线是该点处的切线。右侧的"偏离"是窗口内曲线与切线的最大距离,占窗口高度的百分比。放大 100 倍后,光滑曲线与切线几乎重合;尖角处无论放多大,左右两边的斜率都不一样(红、绿两条射线)。
    试一试
    • 在光滑曲线上放大到 ×200 以上,直到曲线几乎变成直线。
    • 切换到 |x|,把黄点拖到尖角 x = 0,放大到 ×50 以上:曲线始终不变直。
    核心洞见

    "可导"的意思是:放大后能看到一条直线。导数 \(f'(x_0)\) 就是这条直线的斜率,它回答的问题是"输入动一点点,输出会动多少倍"。\(|x|\) 在尖角处没有这条直线,所以不可导。

    3动手玩:从割线到切线

    放大镜给了直觉,现在把它变成公式。过曲线上两点 A、B 画一条直线,叫割线,斜率是"纵向增量 / 横向增量"。让 B 向 A 靠近,割线就转成切线。右图画出割线斜率随 \(h\)(B 到 A 的水平距离)的变化:\(h\to 0\) 时它趋向的那个数,就是导数。

    FIG 2割线逼近切线
    曲线与割线
    割线斜率 q(h)
    拖动 A 或 B(紫色割线、黄色切线)。右图里紫色曲线是 \(q(h)\),黄色虚线是 \(f'(a)\),空心点标出 \(h=0\) 处"缺失"的那一点:\(q(0)\) 是 \(0/0\),没有定义,但左右极限可以存在。\(|x|\) 在 \(a=0\) 处左极限是 −1、右极限是 +1(两个空心点),二者不等,极限不存在,所以这时不画切线。
    • 让 |h| 小于 0.01:割线与切线重合,右图上的点贴到虚线上。
    • 切到 |x|,把 A 放在 x = 0,分别从左边和右边把 |h| 压到 0.05 以下:两侧斜率不同。

    这个直线近似有多准?

    在 \(x_0\) 处用切线代替曲线,在距离 \(\delta\) 处的误差是多少?下面拖动 \(\delta\) 看看。右图是误差随 \(|\delta|\) 变化的双对数图:直线的斜率就是"误差随距离的几次方缩小"。

    FIG 3线性近似的误差
    曲线与切线
    误差(对数–对数)
    拖动黄点(\(x_0\))和紫点(\(x_0+\delta\))。青色曲线是真实误差;紫色虚线是理论估计(误差主项)\(\tfrac12|f''|\,\delta^2\),斜率为 2。\(\delta\) 缩小一半,光滑函数的误差缩小到约 1/4;\(|x|\) 在尖角处没有切线(图中换成一条斜率为 0 的灰色参考线),误差只缩小一半,斜率为 1,说明那里没有好的线性近似。
    • 在光滑曲线上,找一个位置使得"δ 减半,误差约变成 1/4"(读数栏里的比值接近 4)。
    • 切到 |x|,把 x₀ 放在 0:比值变成 2,不再是 4。

    导数本身也是一个函数

    每个 \(x\) 都对应一个斜率,把所有斜率画出来就得到导函数 \(f'\)。左边拖动黄点,右边的点会沿 \(f'\) 的图像一起走。

    FIG 4f 与 f′
    f(x)
    f′(x)
    切线上升(斜率为正)时是红色,下降时是蓝色;斜率为零的地方是曲线的峰与谷。\(|x|\) 的导函数在 0 处断开:左边 −1,右边 +1。
    • 在 sin 或三次曲线上,把黄点拖到 f′ = 0 的位置(峰或谷)。

    4再看数学

    提示:把鼠标悬停在公式中带底色的符号上,FIG 2 中对应的线段会被高亮。

    定义

    函数 \(f\) 在 \(a\) 处的导数是割线斜率当 \(h\to 0\) 时的极限:

    $$ f'(a) \;=\; \lim_{h\to 0}\; \frac{\hl{df}{f(a+h)-f(a)}}{\hl{dx}{h}} \;=\; \lim_{h\to 0}\;\hl{sec}{q(h)}. $$

    极限存在,等价于从左、右两侧趋近得到同一个数。这正是 \(|x|\) 在 0 处失败的原因。

    局部线性近似

    把上式移项,就是机器人里最常用的一句话:

    $$ f(a+\delta) \;=\; \underbrace{f(a) + \hl{tan}{f'(a)}\,\delta}_{L(\delta)} \;+\; \underbrace{\tfrac12 f''(a)\,\delta^2 + \cdots}_{O(\delta^2)} \;\approx\; f(a) + f'(a)\,\delta . $$

    误差项里最先出现的是 \(\delta^2\):\(\delta\) 缩小为原来的 1/10,误差缩小为 1/100。\(f''\)(导数的导数,描述曲线弯得多厉害)越大,线性近似失效得越快。完整的展开见 2.4 泰勒展开。

    两种读法

    放大镜读法:\(f'(a)\) 是放大后那条直线的斜率。放大倍率读法:输入的一点点变化 \(\Delta x\) 被乘以 \(f'(a)\) 变成输出变化 \(\Delta f\approx f'(a)\,\Delta x\)。第二种读法在多元函数里变成"矩阵乘向量",那就是 3.3 节的雅可比。

    常用求导规则

    规则公式来源
    线性\((c f + g)' = c f' + g'\)极限保持加法和数乘
    乘积\((f g)' = f' g + f g'\)展开 \((f+\Delta f)(g+\Delta g)\),丢掉 \(\Delta f\,\Delta g\)
    幂\((x^n)' = n x^{n-1}\)\((x+h)^2 - x^2 = 2xh + h^2\),除以 \(h\) 再令 \(h\to0\)
    \(\sin,\cos\)\((\sin x)' = \cos x,\ (\cos x)' = -\sin x\)小角度 \(\sin h\approx h\)(2.4)
    \(e^x,\ \ln x\)\((e^x)' = e^x,\ (\ln x)' = 1/x\)指数函数是"变化率等于自身"的函数
    复合\((f\circ g)' = f'(g)\,g'\)下一节

    数值求导:步长不能太大,也不能太小

    用计算机估计导数,最直接的是差商。前向差分 \(\frac{f(x+h)-f(x)}{h}\) 的截断误差约为 \(\tfrac12 f''\,h\),中心差分 \(\frac{f(x+h)-f(x-h)}{2h}\) 的误差约为 \(\tfrac16 f'''\,h^2\),所以中心差分更准。但 \(h\) 也不能太小:两个几乎相等的数相减,舍入误差(双精度约 \(10^{-16}\))被 \(1/h\) 放大。因此双精度下前向差分的最佳 \(h\) 约是 \(10^{-8}\),中心差分约是 \(10^{-5}\)。3.3 节有一个可以拖动步长观察这一现象的实验。

    5机器人中的它:从编码器估计转速

    编码器每转一圈输出 \(N\) 个脉冲,位置只能被量化到 \(q = 2\pi/N\)。要得到转速,最直接的是对位置求差:\(\hat\omega_n = \dfrac{\theta_n-\theta_{n-k}}{k\,\Delta t}\)。

    这里有一个两难。窗口 \(k\) 取得小,响应快,但量化误差 \(\sim q/(k\Delta t)\) 被放大;窗口取得大,噪声小了,估计却滞后(约 \(k\Delta t/2\) 秒)。下面是一个真实的权衡:真实角度 \(\theta(t)=2\sin(0.9t)+0.5t\),采样 100 Hz,编码器把它量化后再求差。

    FIG 5对编码器数据求导
    黄色是真实转速 \(\omega(t)=\dot\theta(t)\),青色是从量化后的位置估出来的。"因果"只用过去的采样,实时可用;"居中"同时用前后各一半窗口,没有滞后,但只能离线做。
    • 设窗口 k = 1:估计乱得不能用(RMS 误差大于 0.2 rad/s)。
    • 用"因果"模式、分辨率 ≤ 1024,把 RMS 误差压到 0.065 rad/s 以下。你会发现再怎么调也有一个最低点。
    真实系统里

    电机驱动器常常同时用两种办法:高速时数脉冲(M 法),低速时测相邻脉冲的间隔(T 法)。想要既无滞后又低噪声,办法是把"求导"改成"估计":用位置、加速度模型加传感器噪声模型,做卡尔曼滤波(4.8 节)。不要对原始数据硬求导,这是机器人里最老的教训之一。

    6常见误区

    误区 1:线性近似在哪里都好用

    它只在工作点附近好用,误差按 \(\delta^2\) 增长。关节角偏离线性化点 30° 时,\(\sin\theta\approx\theta\) 的误差已经有 5%;EKF 里若状态变化太大,线性化会让滤波器发散。

    误区 2:对带噪声的数据直接求导

    求导是"高通"操作:它放大高频成分,噪声基本都在高频。位置噪声 \(\sigma\) 进了差分后变成 \(\sqrt2\sigma/\Delta t\),采样越快反而越糟。要么平滑后再差分,要么用滤波器。

    误区 3:连续就一定可导

    \(|x|\) 连续,但在尖角不可导。机器人里的尖角很多:接触瞬间的力、\(\max/\min\)、ReLU、限幅、静摩擦。基于梯度的方法碰到它们要小心,必要时用平滑版本或"次梯度"。

    误区 4:角度用度,而不是弧度

    \((\sin x)'=\cos x\) 只在 \(x\) 以弧度为单位时成立。若 \(x\) 以度为单位,导数里会多出一个 \(\pi/180\)。代码里统一用弧度,只在输入输出的边界做换算。

    7小练习

    1. \(f(x)=x^2\),\(f'(3)\) 等于多少?
    \(f'(x)=2x\),所以 \(f'(3)=6\)。检查:\(\frac{(3+h)^2-9}{h}=6+h\to 6\)。
    2. 不用计算器,估计 \(\sin(0.1)\)。(提示:在 \(x_0=0\) 处线性近似。)
    \(\sin 0 = 0\),\(\cos 0 = 1\),所以 \(\sin(0.1)\approx 0 + 1\cdot 0.1 = 0.1\)。真值是 0.0998,误差约 \(\tfrac16 (0.1)^3\),在 0.2% 以内。
    3. 对光滑函数做线性近似,把偏离量 \(\delta\) 缩小为一半,误差大约变成原来的……
    误差主项是 \(\tfrac12 f''\delta^2\),所以 \(\delta\to\delta/2\) 时误差变成 \(1/4\)。这就是 FIG 3 里斜率为 2 的直线。
    4. 对编码器位置做差分估计转速,把窗口 \(k\) 从 5 加到 20,会发生什么?
    量化噪声 \(\sim q/(k\Delta t)\) 随 \(k\) 增大而减小,滞后 \(\sim k\Delta t/2\) 却随 \(k\) 增大而增大。这是差分法的基本权衡。
    5. 为什么 \(|x|\) 在 \(x=0\) 处不可导?
    \(|x|\) 在 0 处是连续的;问题在于放大后看到的是一个"V",而不是一条直线。

    8延伸阅读

    • 3Blue1Brown, Essence of Calculus — 第 2 章(导数的悖论)与第 3 章(求导公式的几何直觉)
    • G. Strang, Calculus (MIT OpenCourseWare) — 第 2 章:导数
    • K. Lynch & F. Park, Modern Robotics, 附录:速度与线性化
    • T. Barfoot, State Estimation for Robotics, Ch. 2 — 线性化与估计