Drake Autodiff中np.linalg.norm指定axis参数报错的技术问询
解决NumPy对Drake符号变量数组按axis求范数的报错问题
问题背景
执行以下归一化代码时触发TypeError:
contact_forces = contact_forces / (np.linalg.norm(contact_forces, axis=-1) + 1e-5)[..., np.newaxis]
报错信息:
TypeError: loop of ufunc does not support argument 0 of type pydrake.symbolic.Variable which has no callable conjugate method
调试细节
通过PDB确认:
contact_forces是包含Drake符号变量的object类型NumPy数组,形状为(1, 3, 2):
array([[[Variable('x(0)', Continuous), Variable('x(1)', Continuous)], [Variable('x(2)', Continuous), Variable('x(3)', Continuous)], [Variable('x(4)', Continuous), Variable('x(5)', Continuous)]]], dtype=object)
- 不指定
axis参数时,np.linalg.norm(contact_forces)能正常返回符号表达式;但指定axis=-1时触发上述报错。
核心原因
NumPy的np.linalg.norm在指定axis时,底层依赖元素的conjugate()方法进行运算,但Drake的symbolic.Variable未实现该方法,导致报错;而不指定axis时,计算全局范数的逻辑不依赖该方法,因此能正常运行。
解决方案
方法1:手动实现指定axis的L2范数
直接用符号运算逻辑手动计算每个最后一维的平方和开根号,绕开NumPy的axis处理逻辑:
# 计算每个最后一维的平方和,加小epsilon防止除零后开根号 norms = np.sqrt(np.sum(contact_forces ** 2, axis=-1) + 1e-5) # 广播归一化 contact_forces = contact_forces / norms[..., np.newaxis]
该方法利用Drake符号变量支持**和np.sum(axis=-1)的特性,完全兼容符号运算。
方法2:使用Drake原生符号工具计算
直接用Drake的symbolic模块处理范数计算,更贴合框架特性:
from pydrake.symbolic import sqrt, sum # 遍历数组计算每个子向量的范数 norms = [] for batch in contact_forces: row_norms = [sqrt(sum(vec ** 2) + 1e-5) for vec in batch] norms.append(row_norms) # 转换为NumPy数组并添加维度以支持广播 norms = np.array(norms, dtype=object) contact_forces = contact_forces / norms[..., np.newaxis]
方法3:转换为Drake Vector对象计算
如果数组结构规则,可将子向量转换为Drake的Vector对象,调用其原生norm()方法:
from pydrake.symbolic import Vector norms = [] for batch in contact_forces: row_norms = [] for vec in batch: drake_vec = Vector(vec) row_norms.append(drake_vec.norm() + 1e-5) norms.append(row_norms) norms = np.array(norms, dtype=object) contact_forces = contact_forces / norms[..., np.newaxis]
内容的提问来源于stack exchange,提问作者HoliInn
相关产品推荐
相关产品推荐

