PLC的ST语言实现用于编码器跟踪的FIR整数滤波器

    机器人用编码器进行物件跟踪时容易抖动,传送带本身不稳定,或者编码器跳变本身就容易抖动. 可以用普通FIR滤波器进行滤波,但是一般编码器反馈32位值,超过32位后溢出会造成跳变,而且浮点型滤波器输入很大的值会降低精度,虽然可以变基来解决问题,但是不优美.

    最近把FIR滤波器移植到plc的st语言时发现整数滤波器可以完美解决这个问题,因为整数FIR滤波器可以保证一个冲击响应积分出来还是1,即可以把编码器的delta作为输入,输出的速度可以直接数字积分加起来得到滤波后的信号.

    FIR滤波因为相位延迟是线性的,得到的速度可以乘上延迟系数,可以补偿相位延迟

FUNCTION_BLOCK DintFirFilter
VAR_INPUT
	inputVal : DINT;
END_VAR
VAR_OUTPUT
	outputVal : DINT;
	maxVal : DINT;
	minVal : DINT;
	limitCount : DINT;
END_VAR
VAR
	size : UDINT;
	w : ARRAY [0..127] OF DINT;
	v : ARRAY[0..127] OF DINT;
	vi : UDINT;
	i : UDINT;
	i_vi : UDINT;
END_VAR
VAR CONSTANT
	gainTarget : LREAL := 10000;
	inputLimit : DINT := 10000;
	//gainTarget * inputLimit < MAX_DINT32 -> overflow safe
END_VAR
//整数FIR滤波将10000作为增益目标,对于int32来说,输入10000以内的值是比较安全,不会超出int32范围的
maxVal := MAX(inputVal,maxVal);
minVal := MIN(inputVal,minVal);
IF inputVal > inputLimit THEN
	inputVal := inputLimit;
	limitCount := limitCount + 1;
ELSIF inputVal < -inputLimit THEN
	inputVal := -inputLimit;
	limitCount := limitCount + 1;
END_IF
v[vi] := inputVal;
outputVal := 0;
FOR i := 0 TO size-1 DO
	i_vi := (vi+i+1) MOD size;
	outputVal:= outputVal + w[i]*v[i_vi];
END_FOR
vi := vi+1;
IF vi >=size THEN
	vi := 0;
END_IF

//---------------------------------------------
METHOD barthannwinInit
VAR_INPUT
	n : UDINT;
	Fc : LREAL;
END_VAR
VAR
	x : LREAL;
	h : LREAL;
	n_1 : LREAL;
	i : UDINT;
	sum : LREAL;
	w : ARRAY[0..127] OF LREAL;
END_VAR
(*
barthannwin 把首尾的0去掉了
*)
IF n<=1 THEN
	size := 1;
	w[0] := TO_DINT(gainTarget);
	RETURN;
ELSIF n=2 THEN
	size := 2;
	w[0] := TO_DINT(gainTarget/2);
	w[1] := TO_DINT(gainTarget/2);
	RETURN;
ELSIF n>128 THEN
	n := 128;
END_IF
size := n;
n_1 := TO_LREAL(size+1);   // N-1 = n+2-1 = size + 1
sum := 0;
FOR i:=0 TO size-1 DO
	x := ABS( TO_LREAL(i+1)/(n_1) - 0.5);
	w[i] := 0.62 - 0.48*x + 0.38*COS(2.0*MATH.PI*x);
	h := SINC(2*Fc*( TO_LREAL(i+1) - (n_1)*0.5));
	w[i] := h*w[i];
	sum := sum + w[i];
END_FOR
FOR i:=0 TO size-1 DO
	w[i] := gainTarget*w[i]/sum;
END_FOR
sum := 0;
FOR i:=0 TO size-1 DO
	sum := sum + w[i];
	b[i] := TO_DINT(sum);
END_FOR
sum := 0;
FOR i:=size-1 TO 1 BY -1 DO
	b[i] := b[i] - b[i-1];
	sum := sum + b[i];
END_FOR
sum := sum + b[0];
WHILE sum<>gainTarget DO
	i := 0;
	sum := sum/i;
END_WHILE

reset();



//----------------------------------------
METHOD reset
VAR_INPUT
END_VAR
VAR
	i : UDINT;
END_VAR

FOR i := 0 TO size-1 DO
	v[i] := 0;
END_FOR
vi := 0;
outputVal := 0;
maxVal := 0;
minVal := 0;
limitCount := 0;


//---------------------------------------
METHOD SINC : LREAL
VAR_INPUT
	x : LREAL;
END_VAR

IF x = 0 THEN
	SINC := 1;
ELSE
	SINC := SIN(Math.PI*x) / (Math.PI*x);
END_IF





附上用来验证的matlab代码

%离散化正确的barthannwin 整数FIR滤波器
%N=17,fc=0.2 =>>  16  88  0 -384   -428    787   2891   4060   2891    787   -428   -384      0     88     16
N = 17;
fc = 0.2;

hn = 0:N-1;
h = sinc(2*fc*(hn-(N-1)/2));

arrn = 0:N-1;
x = abs((arrn./(N-1)) - 0.5);
bb = 0.62 - 0.48.*x + 0.38*cos(2*pi.*x);
bh = bb.*h;
b=bh;

b = 10000*b./sum(b);

len = length(b);

ss = 0;
sb = [];
for i=1:len-1
  ss = ss + b(i);
  sb = [sb round(ss)];
endfor

ib = [];
for i=1:len-2
  ib = [ib sb(i+1) - sb(i)];
endfor
b
ib = ib'
length(ib)

[hh,ww]=freqz(ib,1,512,2);
freqz_plot(ww,hh,'false');

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值