[英]How can I write the Matlab “filter”-function myself?
我想在1D信號上使用巴特沃斯濾波器。 在Matlab中,腳本看起來像這樣:
f=100;
f_cutoff = 20;
fnorm =f_cutoff/(f/2);
[b,a] = butter(8,fnorm,'low');
filteredData = filter(b,a,rawData); % I want to write this myself
現在我不想直接使用Matlab中給出的filter -function,而是自己編寫。 在Matlab文檔中,它描述如下:
濾波器功能實現為直接形式II轉置結構,
y(n)= b(1)* x(n)+ b(2)* x(n-1)+ ... + b(nb + 1)* x(n-nb) - a(2)* y(n-1) - ... - a(na + 1)* y(n-na)
其中n-1是濾波器階數,它處理FIR和IIR濾波器[1],na是反饋濾波器階數,nb是前饋濾波器階數。
所以我已經嘗試過編寫這樣的函數:
f=100;
f_cutoff = 20;
fnorm =f_cutoff/(f/2);
[b,a] = butter(8,fnorm,'low');
for n = 9:size(rawData,1)
filteredData(n,1) = b(1)*n + b(2)*(n-1) + b(3)*(n-2) + b(4)*(n-3) + b(5)*(n-4) ...
- a(2)*rawData(n-1,1) - a(3)*rawData(n-2,1) - a(4)*rawData(n-3,1) - a(5)*accel(n-4,1);
end
但那不起作用。 你能幫我么? 我究竟做錯了什么?
真誠的,Cerdo
PS:過濾器文檔可以在這里foud: http : //www.mathworks.de/de/help/matlab/ref/filter.html#f83-1015962擴展更多關於 - >算法
檢查我的答案
過濾
public static double[] filter(double[] b, double[] a, double[] x) {
double[] filter = null;
double[] a1 = getRealArrayScalarDiv(a,a[0]);
double[] b1 = getRealArrayScalarDiv(b,a[0]);
int sx = x.length;
filter = new double[sx];
filter[0] = b1[0]*x[0];
for (int i = 1; i < sx; i++) {
filter[i] = 0.0;
for (int j = 0; j <= i; j++) {
int k = i-j;
if (j > 0) {
if ((k < b1.length) && (j < x.length)) {
filter[i] += b1[k]*x[j];
}
if ((k < filter.length) && (j < a1.length)) {
filter[i] -= a1[j]*filter[k];
}
} else {
if ((k < b1.length) && (j < x.length)) {
filter[i] += (b1[k]*x[j]);
}
}
}
}
return filter;
}
CONV
public static double[] conv(double[] a, double[] b) {
double[] c = null;
int na = a.length;
int nb = b.length;
if (na > nb) {
if (nb > 1) {
c = new double[na+nb-1];
for (int i = 0; i < c.length; i++) {
if (i < a.length) {
c[i] = a[i];
} else {
c[i] = 0.0;
}
}
a = c;
}
c = filter(b, new double [] {1.0} , a);
} else {
if (na > 1) {
c = new double[na+nb-1];
for (int i = 0; i < c.length; i++) {
if (i < b.length) {
c[i] = b[i];
} else {
c[i] = 0.0;
}
}
b = c;
}
c = filter(a, new double [] {1.0}, b);
}
return c;
}
deconv
public static double[] deconv(double[] b, double[] a) {
double[] q = null;
int sb = b.length;
int sa = a.length;
if (sa > sb) {
return q;
}
double[] zeros = new double[sb - sa +1];
for (int i =1; i < zeros.length; i++){
zeros[i] = 0.0;
}
zeros[0] = 1.0;
q = filter(b,a,zeros);
return q;
}
deconvRes
public static double[] deconvRes(double[] b, double[] a) {
double[] r = null;
r = getRealArraySub(b,conv(a,deconv(b,a)));
return r;
}
getRealArraySub
public static double[] getRealArraySub(double[] dSub0, double[] dSub1) {
double[] dSub = null;
if ((dSub0 == null) || (dSub1 == null)) {
throw new IllegalArgumentException("The array must be defined or diferent to null");
}
if (dSub0.length != dSub1.length) {
throw new IllegalArgumentException("Arrays must be the same size");
}
dSub = new double[dSub1.length];
for (int i = 0; i < dSub.length; i++) {
dSub[i] = dSub0[i] - dSub1[i];
}
return dSub;
}
getRealArrayScalarDiv
public static double[] getRealArrayScalarDiv(double[] dDividend, double dDivisor) {
if (dDividend == null) {
throw new IllegalArgumentException("The array must be defined or diferent to null");
}
if (dDividend.length == 0) {
throw new IllegalArgumentException("The size array must be greater than Zero");
}
double[] dQuotient = new double[dDividend.length];
for (int i = 0; i < dDividend.length; i++) {
if (!(dDivisor == 0.0)) {
dQuotient[i] = dDividend[i]/dDivisor;
} else {
if (dDividend[i] > 0.0) {
dQuotient[i] = Double.POSITIVE_INFINITY;
}
if (dDividend[i] == 0.0) {
dQuotient[i] = Double.NaN;
}
if (dDividend[i] < 0.0) {
dQuotient[i] = Double.NEGATIVE_INFINITY;
}
}
}
return dQuotient;
}
使用示例
使用示例
double[] a, b, q, u, v, w, r, z, input, outputVector;
u = new double [] {1,1,1};
v = new double [] {1, 1, 0, 0, 0, 1, 1};
w = conv(u,v);
System.out.println("w=\n"+Arrays.toString(w));
a = new double [] {1, 2, 3, 4};
b = new double [] {10, 40, 100, 160, 170, 120};
q = deconv(b,a);
System.out.println("q=\n"+Arrays.toString(q));
r = deconvRes(b,a);
System.out.println("r=\n"+Arrays.toString(r));
a = new double [] {2, -2.5, 1};
b = new double [] {0.1, 0.1};
u = new double[31];
for (int i = 1; i < u.length; i++) {
u[i] = 0.0;
}
u[0] = 1.0;
z = filter(b, a, u);
System.out.println("z=\n"+Arrays.toString(z));
a = new double [] {1.0000,-3.518576748255174,4.687508888099475,-2.809828793526308,0.641351538057564};
b = new double [] { 0.020083365564211,0,-0.040166731128422,0,0.020083365564211};
input = new double[]{1,2,3,4,5,6,7,8,9};
outputVector = filter(b, a, input);
System.out.println("outputVector=\n"+Arrays.toString(outputVector));
OUTPUT
w=
[1.0, 2.0, 2.0, 1.0, 0.0, 1.0, 2.0, 2.0, 1.0]
q=
[10.0, 20.0, 30.0]
r=
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
z=
[0.05, 0.1125, 0.115625, 0.08828125, 0.0525390625, 0.021533203124999997, 6.469726562499979E-4, -0.009957885742187502, -0.012770843505859377, -0.010984611511230471, -0.007345342636108401, -0.003689372539520266, -9.390443563461318E-4, 6.708808243274683E-4, 0.0013081232085824014, 0.0012997135985642675, 9.705803939141337E-4, 5.633686931105333E-4, 2.189206694310998E-4, -8.033509766391922E-6, -1.195022219235398E-4, -1.453610225212288E-4, -1.219501671897661E-4, -7.975719772659323E-5, -3.8721413563358476E-5, -8.523168090901481E-6, 8.706746668052387E-6, 1.5145017380516224E-5, 1.4577898391619086E-5, 1.0649864299265747E-5, 6.023381178272641E-6]
outputVector=
[0.020083365564211, 0.11083159422936348, 0.31591188140651166, 0.648466936215357, 1.0993782391344866, 1.6451284697769106, 2.25463601232057, 2.8947248889603028, 3.534126758562552]
請給我你的反饋!
我發現一個文本描述了在Matlab過濾器功能中使用的Direct Form II Transposed,它完美地運行。 見下面的腳本。 其他實現也可用但是大約1e-15的錯誤,您將通過自己運行腳本來看到這一點。
%% Specification of the Linear Chebysev filters
clc;clear all;close all
ord = 5; %System order (from 1 to 5)
[bq,aq] = cheby1(ord,2,0.2);theta = [bq aq(2:end)]';
figure;zplane(bq,aq); % Z-Pole/Zeros
u = [ones(40,1); zeros(40,1)];
%% Naive implementation of the basic algorithm
y0 = filter(bq,aq,u); % Built-in filter
b = fliplr(bq);a = fliplr(aq);a(end) = [];
y1 = zeros(40,1);pad = zeros (ord,1);
yp = [pad; y1(:)];up = [pad; u(:)];
for i = 1:length(u)
yp(i+ord) = sum(b(:).*up(i:i+ord))-sum(a(:).*yp(i:i+ord-1));
end
y1 = yp(ord+1:end); % Naive implementation
err = y0(:)-y1(:);
figure
plot(y0,'r')
hold on
plot(y1,'*g')
xlabel('Time')
ylabel('Response')
legend('My code','Built-in filter')
figure
plot(err)
xlabel('Time')
ylabel('Error')
%% Direct Form II Transposed
% Direct realization of rational transfer functions
% trps: 0 for direct realization, 1 for transposed realisation
% b,a: Numerator and denominator
% x: Input sequence
% y: Output sequence
% u: Internal states buffer
trps = 1;
b=theta(1:ord+1);
a=theta(ord+2:end);
y2=zeros(size(u));
x=zeros(ord,1);
%%
if trps==1
for i=1:length(u)
y2(i)=b(1)*u(i)+x(1);
x=[x(2:ord);0];
x=x+b(2:end)*u(i)-a*y2(i);
end
else
for i=1:length(u)
xnew=u(i)-sum(x(1:ord).*a);
x=[xnew,x];
y2(i)=sum(x(1:ord+1).*b);
x=x(1:ord);
end
end
%%
err = y2 - filter(bq,aq,u);
figure
plot(y0,'r')
hold on
plot(y2,'*g')
xlabel('Time')
ylabel('Response')
legend('Form II Transposed','Built-in filter')
figure
plot(err)
xlabel('Time')
ylabel('Error')
% end
我在Java中實現了Matlab使用的過濾函數:
濾波器功能實現為直接形式II轉置結構,
y(n)= b(1)* x(n)+ b(2)* x(n-1)+ ... + b(nb + 1)* x(n-nb) - a(2)* y(n-1) - ... - a(na + 1)* y(n-na)
其中n-1是濾波器階數,它處理FIR和IIR濾波器[1],na是反饋濾波器階數,nb是前饋濾波器階數。
public void filter(double [] b,double [] a, ArrayList<Double> inputVector,ArrayList<Double> outputVector){
double rOutputY = 0.0;
int j = 0;
for (int i = 0; i < inputVector.size(); i++) {
if(j < b.length){
rOutputY += b[j]*inputVector.get(inputVector.size() - i - 1);
}
j++;
}
j = 1;
for (int i = 0; i < outputVector.size(); i++) {
if(j < a.length){
rOutputY -= a[j]*outputVector.get(outputVector.size() - i - 1);
}
j++;
}
outputVector.add(rOutputY);
}
這是一個例子:
ArrayList<Double>inputVector = new ArrayList<Double>();
ArrayList<Double>outputVector = new ArrayList<Double>();
double [] a = new double [] {1.0000,-3.518576748255174,4.687508888099475,-2.809828793526308,0.641351538057564};
double [] b = new double [] { 0.020083365564211,0,-0.040166731128422,0,0.020083365564211};
double []input = new double[]{1,2,3,4,5,6,7,8,9};
for (int i = 0; i < input.length; i++) {
inputVector.add(input[i]);
filter(b, a, inputVector, outputVector);
}
System.out.println(outputVector);
和輸出是:
[0.020083365564211, 0.11083159422936348, 0.31591188140651166, 0.6484669362153569, 1.099378239134486, 1.6451284697769086, 2.254636012320566, 2.894724888960297, 3.534126758562545]
如在Matlab輸出中
而已
我發現了自己的錯誤。 這是工作代碼(作為函數):
function filtered = myFilter(b, a, raw)
filtered = zeros(size(raw));
for c = 1:3
for n = 9:size(raw,1)
filtered(n,c) = b(1)* raw(n,c) + b(2)* raw(n-1,c) + b(3)* raw(n-2,c) ...
+ b(4)* raw(n-3,c) + b(5)* raw(n-4,c) + b(6)* raw(n-5,c) ...
+ b(7)* raw(n-6,c) + b(8)* raw(n-7,c) + b(9)* raw(n-8,c) ...
- a(1)*filtered(n,c) - a(2)*filtered(n-1,c) - a(3)*filtered(n-2,c) ...
- a(4)*filtered(n-3,c) - a(5)*filtered(n-4,c) - a(6)*filtered(n-5,c) ...
- a(7)*filtered(n-6,c) - a(8)*filtered(n-7,c) - a(9)*filtered(n-8,c);
end
end
現在過濾器工作得很好,但在前40個值我得到了不同的結果。 我不得不弄明白......
BlackEagle的解決方案不能將MATLAB與其他陣列重現相同的結果。 例如:
b = [0.1 0.1]
a = [2 -2.5 1]
u = [1, zeros(1, 30)];
z = filter(b, a, u)
完全給你其他結果。 小心。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.