6.8
0 GPT提问
def projFrenSerretBasis(s: Union[ca.MX, float]):
''' project to the Frenet Serret space
<-- kap_impl : Curvature
<-- tau_impl : torsion
<-- dGamma_ds, d2Gamma_ds2, d3Gamma_ds3 : First 3 derivates of the curve w.r.t arc length
<-- et_MX, en_MX, eb_MX : tangent , normal , binormal unit vectors'''
InterOpts = {'degree': [5]}
y_ref_MX = ca.interpolant("y_ref", "bspline", [s_ref], y_ref, InterOpts)
z_ref_MX = ca.interpolant("z_ref", "bspline", [s_ref], z_ref, InterOpts)
x_ref_MX = ca.interpolant("x_ref", "bspline", [s_ref], x_ref, InterOpts)
[d2GammaX_ds2, dGammaX_ds] = ca.hessian(x_ref_MX(s), s)
[d2GammaY_ds2, dGammaY_ds] = ca.hessian(y_ref_MX(s), s)
[d2GammaZ_ds2, dGammaZ_ds] = ca.hessian(z_ref_MX(s), s)
[d4GammaX_ds4, d3GammaX_ds3] = ca.hessian(d2GammaX_ds2, s)
[d4GammaY_ds4, d3GammaY_ds3] = ca.hessian(d2GammaY_ds2, s)
[d4GammaZ_ds4, d3GammaZ_ds3] = ca.hessian(d2GammaZ_ds2, s)
dGamma_ds = ca.vertcat(dGammaX_ds, dGammaY_ds, dGammaZ_ds)
d2Gamma_ds2 = ca.vertcat(d2GammaX_ds2, d2GammaY_ds2, d2GammaZ_ds2)
d3Gamma_ds3 = ca.vertcat(d3GammaX_ds3, d3GammaY_ds3, d3GammaZ_ds3)
d4Gamma_ds4 = ca.vertcat(d4GammaX_ds4, d4GammaY_ds4, d4GammaZ_ds4)
kap = ca.norm_2(d2Gamma_ds2)
kapBar_MX = ca.jacobian(kap, s)
et_MX = dGamma_ds
en_MX = d2Gamma_ds2/ kap
eb_MX = ca.cross(et_MX, en_MX)
etBar_MX = d2Gamma_ds2
enBar_MX = (1/ kap**3) * (kap**2 * d3Gamma_ds3 - d2Gamma_ds2 @ d3Gamma_ds3.T @ d2Gamma_ds2)
ebBar_MX = (1/ kap) * ca.cross(dGamma_ds, d3Gamma_ds3)
tau_MX = ca.dot(en_MX, ebBar_MX)
tauBar_MX = ca.jacobian(tau_MX, s)
return kap, tau_MX, et_MX, en_MX, eb_MX, kapBar_MX, tauBar_MX, etBar_MX, enBar_MX, ebBar_MX 我有一个问题,你能不能教教我这些公式是怎么推导的,并且告诉我这个 ca.jacobian是在干嘛
1 Gpt回答
一、Frenet–Serret 坐标系基本公式
对于一个以弧长 s s s 为参数的平滑曲线 γ ( s ) \gamma(s) γ(s) ,其 Frenet–Serret 坐标系定义如下:
-
切向量
t ( s ) = d γ d s \mathbf{t}(s) = \frac{d\gamma}{ds} t(s)=dsdγ
如果曲线以弧长参数化,则 ∥ t ( s ) ∥ = 1 \|\mathbf{t}(s)\| = 1 ∥t(s)∥=1。
-
曲率
曲率描述了曲线弯曲的程度,定义为第二阶导数的范数:κ ( s ) = ∥ d 2 γ d s 2 ∥ \kappa(s) = \left\|\frac{d^2\gamma}{ds^2}\right\| κ(s)= ds2d2γ
在程序中用变量
kap
表示。 -
法向量
法向量给出了曲线弯曲的方向,由二阶导数归一化得到:n ( s ) = d 2 γ d s 2 κ ( s ) \mathbf{n}(s) = \frac{\frac{d^2\gamma}{ds^2}}{\kappa(s)} n(s)=κ(s)ds2d2γ
代码中用
en_MX = d2Gamma_ds2/kap
实现。 -
副法向量
副法向量通过切向量和法向量的叉积定义:b ( s ) = t ( s ) × n ( s ) \mathbf{b}(s) = \mathbf{t}(s) \times \mathbf{n}(s) b(s)=t(s)×n(s)
代码中用
eb_MX = ca.cross(et_MX, en_MX)
实现。 -
Frenet–Serret 公式
这些单位向量满足以下微分关系:t ′ ( s ) = κ ( s ) n ( s ) , n ′ ( s ) = − κ ( s ) t ( s ) + τ ( s ) b ( s ) , b ′ ( s ) = − τ ( s ) n ( s ) , \begin{aligned} \mathbf{t}'(s) &= \kappa(s) \mathbf{n}(s), \\ \mathbf{n}'(s) &= -\kappa(s) \mathbf{t}(s) + \tau(s) \mathbf{b}(s), \\ \mathbf{b}'(s) &= -\tau(s) \mathbf{n}(s), \end{aligned} t′(s)n′(s)b′(s)=κ(s)n(s),=−κ(s)t(s)+τ(s)b(s),=−τ(s)n(s),
其中 τ ( s ) \tau(s) τ(s) 是扭率(torsion),描述曲线如何扭转。
二、代码中公式的对应与推导
1. 计算导数
程序通过 ca.hessian
求解 B 样条插值得到的函数的导数。比如:
[d2GammaX_ds2, dGammaX_ds] = ca.hessian(x_ref_MX(s), s)
- 一阶导数
d
γ
x
d
s
\frac{d\gamma_x}{ds}
dsdγx 用变量
dGammaX_ds
表示; - 二阶导数
d
2
γ
x
d
s
2
\frac{d^2\gamma_x}{ds^2}
ds2d2γx 用变量
d2GammaX_ds2
表示。
对
x
x
x、
y
y
y 和
z
z
z 分量分别计算,然后用 ca.vertcat
将它们组合成向量:
d γ d s = [ d γ x d s d γ y d s d γ z d s ] (代码中为 d G a m m a _ d s ) \frac{d\gamma}{ds} = \begin{bmatrix} \frac{d\gamma_x}{ds} \\ \frac{d\gamma_y}{ds} \\ \frac{d\gamma_z}{ds} \end{bmatrix} \quad \text{(代码中为 } dGamma\_ds \text{)} dsdγ= dsdγxdsdγydsdγz (代码中为 dGamma_ds)
d 2 γ d s 2 = [ d 2 γ x d s 2 d 2 γ y d s 2 d 2 γ z d s 2 ] (代码中为 d 2 G a m m a _ d s 2 ) \frac{d^2\gamma}{ds^2} = \begin{bmatrix} \frac{d^2\gamma_x}{ds^2} \\ \frac{d^2\gamma_y}{ds^2} \\ \frac{d^2\gamma_z}{ds^2} \end{bmatrix} \quad \text{(代码中为 } d2Gamma\_ds2 \text{)} ds2d2γ= ds2d2γxds2d2γyds2d2γz (代码中为 d2Gamma_ds2)
同样地,三阶和四阶导数也被计算出来,记为 d3Gamma_ds3
和 d4Gamma_ds4
。
2. 曲率和曲率导数
-
曲率
代码中:kap = ca.norm_2(d2Gamma_ds2)
对应数学公式:
κ = ∥ d 2 γ d s 2 ∥ \kappa = \left\| \frac{d^2\gamma}{ds^2} \right\| κ= ds2d2γ
-
曲率的导数
代码中:kapBar_MX = ca.jacobian(kap, s)
这表示求 κ \kappa κ 关于 s s s 的导数:
κ ˙ = d κ d s \dot{\kappa} = \frac{d\kappa}{ds} κ˙=dsdκ
这里
ca.jacobian
用于计算函数 κ ( s ) \kappa(s) κ(s) 对 s s s 的雅可比(即导数)。
3. 单位向量
-
切向量
代码中:et_MX = dGamma_ds
对应公式:
t ( s ) = d γ d s \mathbf{t}(s) = \frac{d\gamma}{ds} t(s)=dsdγ
注意:如果路径已经以弧长参数化,则 ∥ t ( s ) ∥ = 1 \|\mathbf{t}(s)\|=1 ∥t(s)∥=1。
-
法向量
代码中:en_MX = d2Gamma_ds2 / kap
对应公式:
n ( s ) = γ ′ ′ ( s ) κ ( s ) \mathbf{n}(s) = \frac{\gamma''(s)}{\kappa(s)} n(s)=κ(s)γ′′(s)
-
副法向量
代码中:eb_MX = ca.cross(et_MX, en_MX)
对应公式:
b ( s ) = t ( s ) × n ( s ) \mathbf{b}(s) = \mathbf{t}(s) \times \mathbf{n}(s) b(s)=t(s)×n(s)
4. 单位向量的导数
代码中带有 Bar
的变量代表的是对
s
s
s 求导后的结果:
-
切向量的导数
etBar_MX = d2Gamma_ds2
对应公式(由于 t = γ ′ ( s ) \mathbf{t} = \gamma'(s) t=γ′(s)):
t ˙ ( s ) = γ ′ ′ ( s ) \dot{\mathbf{t}}(s) = \gamma''(s) t˙(s)=γ′′(s)
在 Frenet–Serret 公式中应满足 t ˙ = κ n \dot{\mathbf{t}} = \kappa \mathbf{n} t˙=κn,这与 γ ′ ′ ( s ) = κ n \gamma''(s) = \kappa \mathbf{n} γ′′(s)=κn 一致。
-
法向量的导数
enBar_MX = (1/ kap**3) * (kap**2 * d3Gamma_ds3 - d2Gamma_ds2 @ d3Gamma_ds3.T @ d2Gamma_ds2)
该公式是从
n = γ ′ ′ ( s ) κ ( s ) \mathbf{n} = \frac{\gamma''(s)}{\kappa(s)} n=κ(s)γ′′(s)
对 s s s 求导后,通过商法则推导得到的结果。推导过程涉及到 γ ′ ′ ′ ( s ) \gamma'''(s) γ′′′(s) 和 κ ˙ \dot{\kappa} κ˙ 的结合。
- 副法向量的导数
对应公式为对 b = t × n \mathbf{b} = \mathbf{t} \times \mathbf{n} b=t×n 求导,结果中包含 γ ′ ( s ) \gamma'(s) γ′(s) 与 γ ′ ′ ′ ( s ) \gamma'''(s) γ′′′(s) 的叉积,再除以曲率 κ \kappa κ。ebBar_MX = (1/ kap) * ca.cross(dGamma_ds, d3Gamma_ds3)
5. 扭率及其导数
-
扭率
tau_MX = ca.dot(en_MX, ebBar_MX)
对应公式:
− τ ( s ) n ( s ) = b ˙ ( s ) -\tau(s)\mathbf{n}(s) = \dot{\mathbf{b}}(s) −τ(s)n(s)=b˙(s)
其中 b ˙ ( s ) \dot{\mathbf{b}}(s) b˙(s) 就是副法向量的导数,负号表示 n \mathbf{n} n的方向和 d b d s \frac{d\mathbf{b}}{ds} dsdb方向相反, τ \tau τ表示标量,只是大小
-
扭率的导数
tauBar_MX = ca.jacobian(tau_MX, s)
表示求扭率 τ ( s ) \tau(s) τ(s) 关于 s s s 的导数:
τ ˙ = d τ d s \dot{\tau} = \frac{d\tau}{ds} τ˙=dsdτ
三、ca.jacobian
的作用
-
ca.jacobian
是 CasADi 的一个函数,用于计算一个函数对给定变量的雅可比矩阵。 -
对于一个标量函数 f ( s ) f(s) f(s),其雅可比矩阵就是该函数对 s s s 的导数,即:
d f d s \frac{df}{ds} dsdf
-
在本代码中:
kapBar_MX = ca.jacobian(kap, s)
计算的是曲率 κ ( s ) \kappa(s) κ(s) 关于 s s s 的导数 d κ d s \frac{d\kappa}{ds} dsdκ。tauBar_MX = ca.jacobian(tau_MX, s)
计算的是扭率 τ ( s ) \tau(s) τ(s) 关于 s s s 的导数 d τ d s \frac{d\tau}{ds} dsdτ。
这样,我们就能够获得曲率和扭率变化的速率,这在动态路径跟踪和控制中是非常有用的信息。
四、总结
-
路径的导数
- 一阶导数: γ ′ ( s ) \gamma'(s) γ′(s)(切向量 t \mathbf{t} t)
- 二阶导数: γ ′ ′ ( s ) \gamma''(s) γ′′(s) 用于计算曲率 κ = ∥ γ ′ ′ ( s ) ∥ \kappa = \|\gamma''(s)\| κ=∥γ′′(s)∥
- 三阶导数: γ ′ ′ ′ ( s ) \gamma'''(s) γ′′′(s) 用于计算法向量和导数
-
Frenet-Serret 基
- 切向量: t = γ ′ ( s ) \mathbf{t} = \gamma'(s) t=γ′(s)
- 法向量: n = γ ′ ′ ( s ) κ \mathbf{n} = \frac{\gamma''(s)}{\kappa} n=κγ′′(s)
- 副法向量: b = t × n \mathbf{b} = \mathbf{t} \times \mathbf{n} b=t×n
-
导数及其雅可比
- 曲率的导数:
κ
˙
=
d
κ
d
s
\dot{\kappa} = \frac{d\kappa}{ds}
κ˙=dsdκ 由
ca.jacobian(kap, s)
实现 - 扭率: − n τ = b ˙ - \mathbf{n} \tau = \dot{\mathbf{b}} −nτ=b˙ 。负号表示 n \mathbf{n} n的方向和 d b d s \frac{d\mathbf{b}}{ds} dsdb方向相反, τ \tau τ表示标量,只是大小
- 扭率的导数:
τ
˙
=
d
τ
d
s
\dot{\tau} = \frac{d\tau}{ds}
τ˙=dsdτ 由
ca.jacobian(tau_MX, s)
实现
- 曲率的导数:
κ
˙
=
d
κ
d
s
\dot{\kappa} = \frac{d\kappa}{ds}
κ˙=dsdκ 由
-
ca.jacobian
- 用于计算函数相对于某变量的偏导数或导数矩阵。在本例中,它用于求曲率和扭率关于进度 s s s 的导数。
这些公式与代码直接对应,带有 “Bar” 的变量表示对原始量关于 s s s 求导得到的结果。希望这些 LaTeX 公式和解释能帮助你更好地理解代码的数学推导过程。
6.9
0 GPT提问
扭率 为什么是tau_MX = ca.dot(en_MX, ebBar_MX),
是不是少了个负号,但是程序里面没有负号。
还有就是副法向量的导数是怎么求的
ebBar_MX = (1/ kap) * ca.cross(dGamma_ds, d3Gamma_ds3)
1 GPT回答
下面我来详细说明这段代码中扭率(
τ
\tau
τ)和副法向量导数的推导思路,以及 ca.jacobian
的作用。
一、扭率的定义与符号约定
在经典的 Frenet–Serret 公式中,扭率通常定义:
-
定义为
− n τ = d b d s - \mathbf{n} \tau = \frac{d\mathbf{b}}{ds} −nτ=dsdb,负号表示 n \mathbf{n} n的方向和 d b d s \frac{d\mathbf{b}}{ds} dsdb方向相反, τ \tau τ表示标量,只是大小
二、副法向量的导数推导
给定 Frenet–Serret 基的定义:
-
切向量:
t = d γ d s \mathbf{t} = \frac{d\gamma}{ds} t=dsdγ
-
法向量:
n = γ ′ ′ ( s ) κ , κ = ∥ γ ′ ′ ( s ) ∥ \mathbf{n} = \frac{\gamma''(s)}{\kappa}, \quad \kappa = \left\|\gamma''(s)\right\| n=κγ′′(s),κ=∥γ′′(s)∥
-
副法向量:
b = t × n \mathbf{b} = \mathbf{t} \times \mathbf{n} b=t×n
对副法向量求导,根据叉积的导数法则:
d b d s = d t d s × n + t × d n d s \frac{d\mathbf{b}}{ds} = \frac{d\mathbf{t}}{ds} \times \mathbf{n} + \mathbf{t} \times \frac{d\mathbf{n}}{ds} dsdb=dsdt×n+t×dsdn
根据 Frenet–Serret 公式:
d t d s = κ n , d n d s = − κ t + τ b \frac{d\mathbf{t}}{ds} = \kappa \mathbf{n}, \quad \frac{d\mathbf{n}}{ds} = -\kappa \mathbf{t} + \tau \mathbf{b} dsdt=κn,dsdn=−κt+τb
代入上式:
d
b
d
s
=
(
κ
n
)
×
n
+
t
×
(
−
κ
t
+
τ
b
)
=
0
+
τ
(
t
×
b
)
=
τ
(
t
×
b
)
\begin{aligned} \frac{d\mathbf{b}}{ds} &= (\kappa \mathbf{n}) \times \mathbf{n} + \mathbf{t} \times (-\kappa \mathbf{t} + \tau \mathbf{b}) \\ &= \mathbf{0} + \tau (\mathbf{t} \times \mathbf{b}) \\ &= \tau (\mathbf{t} \times \mathbf{b}) \end{aligned}
dsdb=(κn)×n+t×(−κt+τb)=0+τ(t×b)=τ(t×b)
而由于 t × b = − n \mathbf{t} \times \mathbf{b} = -\mathbf{n} t×b=−n(遵循右手定则),故有:
d
b
d
s
=
−
τ
n
\frac{d\mathbf{b}}{ds} = -\tau\, \mathbf{n}
dsdb=−τn
这个公式里面的负号是个方向,负号表示
n
\mathbf{n}
n的方向和
d
b
d
s
\frac{d\mathbf{b}}{ds}
dsdb方向相反,
τ
\tau
τ表示标量,只是大小
代码中是这样写的,为了后续用到,只用大小,不用方向。
tau_MX = ca.dot(en_MX, ebBar_MX)
tau的推导
来源tau_MX
来源tau_MX
三、副法向量导数的计算
代码中计算副法向量导数的部分为:
ebBar_MX = (1/ kap) * ca.cross(dGamma_ds, d3Gamma_ds3)
解释如下:
-
d
Γ
/
d
s
d\Gamma/ds
dΓ/ds 对应
t
\mathbf{t}
t(切向量),即
dGamma_ds
。 -
d
3
γ
/
d
s
3
d^3\gamma/ds^3
d3γ/ds3 对应
γ
′
′
′
(
s
)
\gamma'''(s)
γ′′′(s),即
d3Gamma_ds3
。
在弧长参数化的情况下,副法向量的导数可以推导为:
d b d s = 1 κ ( t × γ ′ ′ ′ ( s ) ) \frac{d\mathbf{b}}{ds} = \frac{1}{\kappa}\left(\mathbf{t} \times \gamma'''(s)\right) dsdb=κ1(t×γ′′′(s))
这就是代码中用的公式:
ebBar_MX = 1 κ ca.cross ( d G a m m a _ d s , d 3 G a m m a _ d s 3 ) \text{ebBar\_MX} = \frac{1}{\kappa}\, \text{ca.cross}(dGamma\_ds, d3Gamma\_ds3) ebBar_MX=κ1ca.cross(dGamma_ds,d3Gamma_ds3)
这个公式的推导基于对 b = t × n \mathbf{b} = \mathbf{t} \times \mathbf{n} b=t×n 求导,并利用 n = γ ′ ′ ( s ) κ \mathbf{n} = \frac{\gamma''(s)}{\kappa} n=κγ′′(s) 以及 t = γ ′ ( s ) \mathbf{t} = \gamma'(s) t=γ′(s) 得到。
四、总结
-
关于扭率:
- 经典 Frenet–Serret 公式中常见的定义为 τ = − n ⋅ b ′ \tau = -\mathbf{n} \cdot \mathbf{b}' τ=−n⋅b′,但也有定义为 τ = n ⋅ b ′ \tau = \mathbf{n} \cdot \mathbf{b}' τ=n⋅b′ 的约定。代码中使用的是后一种定义,因此没有负号。
-
关于副法向量导数:
- 副法向量 b \mathbf{b} b 定义为 b = t × n \mathbf{b} = \mathbf{t} \times \mathbf{n} b=t×n。
- 其导数
d
b
d
s
\frac{d\mathbf{b}}{ds}
dsdb 推导可得:
d b d s = 1 κ ( t × γ ′ ′ ′ ( s ) ) \frac{d\mathbf{b}}{ds} = \frac{1}{\kappa}\left(\mathbf{t} \times \gamma'''(s)\right) dsdb=κ1(t×γ′′′(s)) - 代码中写为:
ebBar_MX = (1/ kap) * ca.cross(dGamma_ds, d3Gamma_ds3)
-
ca.jacobian
:ca.jacobian(f, s)
用于计算函数 f ( s ) f(s) f(s) 关于变量 s s s 的雅可比矩阵,即对 s s s 求导。代码中用于计算曲率和扭率的导数(如kapBar_MX
和tauBar_MX
)。
只要整个模型中保持一致的符号约定,即使与某些文献中有负号差异,也是可以接受的。关键在于系统内各个部分的定义和使用是一致的。
希望这能帮助你理解这些公式的推导思路以及代码中 ca.jacobian
的作用!