1. 前向欧拉离散化不能保证稳定性,但并不是不能使用,根据实际应用场景和参数选择合适的离散化方法。
  2. 对位置指令的滤波操作必须要考虑是否会丢失指令脉冲。

前言

安川伺服Pn14A/Pn14B振动抑制2是行业典型位置指令陷波器,用于抑制机械手、龙门等长传动机构末端抖动。网上大多只给调试经验,很少结合底层参数计算逻辑做完整数学推导。

一、伺服参数与滤波系数数学定义

1. 变量映射伺服功能码及系数计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void PcmdFilCalculatePrmVibSupFil( VIBSUPFIL *VibSupFil, ULONG ff_frq, ULONG ff_fil, LONG ScanTimeNs )
{
VIBSUPFILPRM wrkp;
LONG u1 = ff_fil;
LONG wk = (LONG)ff_frq * (LONG)ff_fil;
LONG omega2 = MlibMIN( wk, (MAXOMEGA2(ScanTimeNs) * 1000) );

// Kff1 = ff_fil^2 / 10000
wrkp.Kff1 = MlibScalKxgain( u1 * u1, 1, 10000, NULL, 24 );

// Kff2 = π * omega2 * ScanTimeNs / 10^12
// Kff3 = 4π * omega2 * ScanTimeNs / 10^12
kx = MlibScalKxgain( omega2, ScanTimeNs, C10POW9, &s, 0 );
wrkp.Kff2 = MlibPcalKxgain( kx, 3141593, 1, &s, 24 ); // π×10^6
wrkp.Kff3 = MlibPcalKxgain( kx, 12566371, 1, &sx, 24 ); // 4π×10^6

VibSupFil->conf.VibSupPrm = wrkp;
}

Image Token: 5bf995132d104b9f98fa1c470175cd31

代码内部变量 伺服参数 物理含义 单位
ff_frq Pn14A 振动抑制2中心频率参数 0.1Hz
ff_fil Pn14B 振动抑制2补偿/增益参数 1%
ScanTimeNs $T_s$ 伺服控制周期 ns
Kff1 $k_1$ 系数1 定点24位
Kff2 $k_2$ 系数2 定点24位
Kff3 $k_3$ 系数3 定点24位

2. 代码数学公式剥离

代码内部全部为定点整数运算,去除缩放库MlibScalKxgain定点换算逻辑后,纯数学表达式如下:

  1. 中间频率乘积并饱和限幅

    $\omega_{2\text{max}}=\text{MAXOMEGA2}(T_s) \times 1000$,限制最大抑制频率。

  2. 高频增益系数 $k_1$

  3. 周期耦合中间量

  4. 状态系数 $k_2、k_3$

关键结论:代码仅完成滤波器系数离线计算,真正滤波迭代由离散状态空间方程执行。

二、离散域:状态空间迭代方程

安川该陷波器为二阶离散状态滤波器,两个状态变量 $wb_1[n],wb_2[n]$,输入$u$为位置指令增量,输出$y$为滤波后位置指令增量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

/****************************************************************************************************/
/* */
/* 振动抑制滤波器运算 */
/* */
/* 概要: 振动抑制滤波器具备针对设定频率的陷波滤波特性。 */
/* 用于抑制定位时机台振动等末端抖动。 */
/* 可与移动平均类位置指令滤波器、MFC滤波器串联使用。 */
/* */
/****************************************************************************************************/
LONG PcmdFilVibSupFilter( VIBSUPFIL *VibSupFil, LONG dPcmd, BOOL *RefZSignal )
{
LONG AvffFili;
LONG AvffFilo;
LONG x1;
LONG x2;
LONG x3;
LONG wk = 0;

/*--------------------------------------------------------------------------------------------------*/
/* 指令完成&输出完成检测 */
/*--------------------------------------------------------------------------------------------------*/
if( (dPcmd == 0) && (VibSupFil->var.Buf == 0) )
{ /* 指令完成 && 滤波器缓存无残留 → 输出全部完成 */
VibSupFil->conf.Pexe = VibSupFil->conf.VibSupPrm; /* 执行参数切换 */
}
AvffFili = dPcmd; /* 振动抑制滤波器输入 = 位置指令脉冲 */

/*--------------------------------------------------------------------------------------------------*/
/* 振动抑制滤波器运算 */
/*--------------------------------------------------------------------------------------------------*/
if( VibSupFil->conf.Pexe.enable )
{ /* 功能使能 */
x1 = MlibPfbkxremNolim( AvffFili, VibSupFil->conf.Pexe.Kff1, &VibSupFil->var.rem1 );
x2 = MlibPfbkxremNolim( VibSupFil->var.wkbf1, VibSupFil->conf.Pexe.Kff2, &VibSupFil->var.rem2 );
x3 = MlibPfbkxremNolim( VibSupFil->var.wkbf2, VibSupFil->conf.Pexe.Kff3, &VibSupFil->var.rem3 );

VibSupFil->var.wkbf1 += (x1 - x3 - AvffFili);
VibSupFil->var.wkbf2 += (x1 - x3 + x2);

AvffFilo = x1 - x3; /* 振动抑制滤波器输出 */

/*--------------------------------------------------------------------------------------------------*/
/* 滤波器输入输出差值(缓存残留量) */
/*--------------------------------------------------------------------------------------------------*/
VibSupFil->var.Buf = MlibPerrcalx( AvffFili, AvffFilo, VibSupFil->var.FilioErr );
if( VibSupFil->var.Buf != 0 )
{ /* 位置指令未全部输出完毕 */
*RefZSignal = FALSE;
}

/*--------------------------------------------------------------------------------------------------*/
/* 振动抑制滤波器内部变量初始化 */
/*--------------------------------------------------------------------------------------------------*/
if( (AvffFilo == 0) && (VibSupFil->var.wkbf1 == 0) && (VibSupFil->var.wkbf2 == 0) )
{ /* 振动抑制滤波器输出=0 && 滤波器状态缓存全部清零 */
/* 重置振动抑制滤波器全部内部变量 */
MlibResetLongMemory( &VibSupFil->var, sizeof(VibSupFil->var)/4 );
}

/*--------------------------------------------------------------------------------------------------*/
/* 滤波器输出处理 */
/*--------------------------------------------------------------------------------------------------*/
wk += AvffFilo; /* 功能关闭状态下直接透传输入 */
VibSupFil->var.Filo = wk; /* 滤波器输出赋值给全局输出缓存 */
}
else
{ /* 功能关闭 */
wk = AvffFili; /* 输入信号直接原样输出 */
VibSupFil->var.Filo = wk;
}

return( wk );
}

1. 状态更新方程

2. 输出方程

离散系统标准形式:

三、推导z域离散传递函数

离散系统传递函数通用公式:

步骤1:构造特征矩阵 $zI-G$

步骤2:二阶矩阵求逆

行列式:

步骤3:代入$C、H、D$展开化简

合并多项式后得到二阶离散传递函数:

步骤4:形式标准化

四、前向欧拉离散变换,映射连续域s域

伺服嵌入式为降低算力,采用前向欧拉法实现s域↔z域映射。
前向欧拉法不能保证离散化的稳定性,一定要进行验证
转换公式:

令等效陷波角频率 $\omega = \dfrac{2\pi \omega_2}{10^{12}}$,则 $2k_2 = \omega T_s$。

代入化简得到连续域传递函数

$T_s^2$ 分子分母抵消,最终得到安川伺服连续域陷波传递函数:

五、传递函数物理含义与代码参数对应验证

1. 传递函数结构解读

  • 零点 $s=\pm j\omega$:在机械共振频率$f=\omega/(2\pi)$处设置传输零点,大幅衰减共振幅值,抑制末端抖动;
  • 重极点$(s+\omega)^2$:安川定制改良结构,相比标准对称陷波稳定性更强;
  • $k_1=\text{Pn14B}^2/10000$:同步控制高频增益与陷波深度,Pn14B越大,高频增益越高、陷波衰减越浅。

2. 仿真数据验证推导正确性

案例1:$\text{Pn14A}=800,\text{Pn14B}=100$

Image Token: 0b309610bb0641eaaf0bc0dad0dbc37c

伯德图高频幅值平直,80Hz陷波点幅值-35.9dB,与公式匹配。

案例2:$\text{Pn14A}=800,\text{Pn14B}=141$

Image Token: a3481b4f8e2448858f87c7a4f756c646

伯德图高频抬升6dB,陷波点幅值-33.4dB,完全匹配推导结果。

六、滤波前后脉冲总数稳定

伺服一般情况下接收的都是位置增量,位置环上的滤波器一定要保证在长时间运行过程中,滤波前后总指令脉冲数保持一致 ,不然就会出现丢拍现象。
这个问题看似简单,但是因为计算过程中的舍入误差等原因,实际上很难实现。安川的滤波器很巧妙的保证了这一点。

观察离散状态方程的第一个式子:

以及输出式:

可以得到:

这就是说,状态$wb_1[n+1]$就是输入输出误差$y - u$的积分。
只要输入指令还有哪怕一个指令没有发出,状态$wb_1$就不会是0,滤波器就还会有输出。
这并不是巧合,而是在设计之初就考虑到的:
位置指令的滤波器,一定要选择误差的积分做系统状态