Can't fit nonlinear filter equation by lsqcurvefit()
1 visualización (últimos 30 días)
Mostrar comentarios más antiguos
Md Nure Alam Dipu
el 19 de Jul. de 2021
Editada: Walter Roberson
el 20 de Jul. de 2021
I want to fit a passive RLC bandstop filter equation to the following data:
f = [5500 6000 6500 7000 7500 8000 8500 9000];
y = [0.998 0.997 0.994 0.988 0.947 0.255 0.956 0.987];
Where f is the frequency and y is the value of transfer function. Here is my code:
fun = @(p, x) abs(j.*(x.*p(2)-1./(x.*p(3)))./(p(1) + j.*(x.*p(2)-1./(x.*p(3))))); % transfer function of RLC bandstop
% x, p(1), p(2), p(3) correspond to w, R, L, C respectively
x = f(1):f(end); % for plotting purpose
x0 = [1 1e-3 1e-6] % starting points
lb = [1 1e-3 1e-6];ub = [100E3 100 1000E-6];
p_fit = lsqcurvefit(fun, x0, f, y, lb, ub) % p_fit is the vector of fitted parameters
semilogx(f, y, 'ro'); hold on;
semilogx(x, fun(p_fit, x), '--m'); grid on; % semilog plot of the transfer function
hold off;
I am not familiar with lsqcurvefit() parameter's starting points. Please, suggest any modification or any other method which could fit for any frequency range.
I have attached the image of actual plot and the transfer function.
0 comentarios
Respuesta aceptada
Walter Roberson
el 20 de Jul. de 2021
Editada: Walter Roberson
el 20 de Jul. de 2021
format long g
f = [5500 6000 6500 7000 7500 8000 8500 9000];
y = [0.998 0.997 0.994 0.988 0.947 0.255 0.956 0.987];
fun = @(p, x) abs(1i.*(x.*p(2)-1./(x.*p(3)))./(p(1) + 1i.*(x.*p(2)-1./(x.*p(3))))); % transfer function of RLC bandstop
% x, p(1), p(2), p(3) correspond to w, R, L, C respectively
x = f(1):f(end); % for plotting purpose
x0 = [1 1e-3 1e-6] % starting points
lb = [1 1e-3 1e-6];ub = [100E3 100 1000E-6];
ub = [1 0.02 2e-5];
x0 = [1 0.0038733109633344873895993294337111 4e-6]
[p_fit, fval_fit] = lsqcurvefit(fun, x0, f, y, lb, ub) % p_fit is the vector of fitted parameters
semilogx(f, y, 'ro', 'displayname', 'original'); hold on;
semilogx(x, fun(p_fit, x), '--m', 'displayname', 'lsq'); grid on; % semilog plot of the transfer function
E = @(p) sum((fun(p,f)-y).^2);
[Pfc, fval_fc] = fmincon(E, x0, [], [], [], [], lb, ub)
[Pfs, fval_fs] = fminsearch(E, x0)
semilogx(x, fun(Pfs,x), '--g', 'displayname', 'fminsearch');
semilogx(x, fun(Pfc,x), ':b', 'displayname', 'fmincon');
hold off
legend show
6 comentarios
Walter Roberson
el 20 de Jul. de 2021
Editada: Walter Roberson
el 20 de Jul. de 2021
format long g
f = [5500 6000 6500 7000 7500 8000 8500 9000];
y = [0.998 0.997 0.994 0.988 0.947 0.255 0.956 0.987];
fun = @(p, x) abs(1i.*(x.*p(2)-1./(x.*p(3)))./(p(1) + 1i.*(x.*p(2)-1./(x.*p(3))))); % transfer function of RLC bandstop
% x, p(1), p(2), p(3) correspond to w, R, L, C respectively
x = f(1):f(end); % for plotting purpose
x0 = [1 1e-3 1e-6] % starting points
lb = [1 1e-3 1e-6];ub = [100E3 100 1000E-6];
ub = [1 0.02 2e-5];
%x0 = [1 0.0038733109633344873895993294337111 4e-6]
E = @(P) sum((fun(P,f)-y).^2);
syms P [1 3]
E2 = simplify(E([1, P(2), 4e-6]))
dE2 = diff(E2,P(2))
fplot(E2, [0.003 0.004])
fplot(E2, [0.0038 0.004])
E2f = matlabFunction(E2);
[bestP2, fval_E2] = fminsearch(E2f,50)
x0 = [1, bestP2, 4E-6]
[p_fit, fval_fit] = lsqcurvefit(fun, x0, f, y, lb, ub) % p_fit is the vector of fitted parameters
semilogx(f, y, 'ro', 'displayname', 'original');
hold on;
semilogx(x, fun(p_fit, x), '--m', 'displayname', 'lsq'); grid on; % semilog plot of the transfer function
[p_fit2, fval_fit2] = lsqcurvefit(fun, x0, f, y, lb, ub)
[Pfc, fval_fc] = fmincon(E, x0, [], [], [], [], lb, ub)
[Pfs, fval_fs] = fminsearch(E, x0)
semilogx(x, fun(Pfs,x), '--g', 'displayname', 'fminsearch');
semilogx(x, fun(Pfc,x), ':b', 'displayname', 'fmincon');
hold off
legend show
The result of [bestP2, fval_E2] = fminsearch(E2f,50) shows that you do not need to start the search from anywhere close by in order to hit one of the two best regions. The one found, the second of the two dips in the w, gives an even better fit (using fminsearch) than using the first of the w dips.
Walter Roberson
el 20 de Jul. de 2021
Editada: Walter Roberson
el 20 de Jul. de 2021
The following was not able to find a good solution... but
format long g
f = [80 190 216 224 234 243 254 314]*1e3
y = [999 984 897 679 205 801 938 993]*1e-3
fun = @(p, x) abs(1i.*(x.*p(2)-1./(x.*p(3)))./(p(1) + 1i.*(x.*p(2)-1./(x.*p(3))))); % transfer function of RLC bandstop
% x, p(1), p(2), p(3) correspond to w, R, L, C respectively
x = f(1):f(end); % for plotting purpose
lb = [1 1e-3 1e-6]; %ub = [100E3 100 1000E-6];
ub = [1 0.02 2e-5];
%x0 = [1 0.0038733109633344873895993294337111 4e-6]
E = @(P) sum((fun(P,f)-y).^2);
syms P [1 3]
E2 = simplify(E([1, P(2), 4e-6]))
dE2 = diff(E2,P(2))
%fplot(E2, [0.003 0.004])
%fplot(E2, [0.0038 0.004])
E2f = matlabFunction(E2);
[bestP2, fval_E2] = fminsearch(E2f,50)
x0 = [1, bestP2, 4E-6]
Notice that search came out with a negative P(2), which is out of range.
[p_fit, fval_fit] = lsqcurvefit(fun, x0, f, y, lb, ub) % p_fit is the vector of fitted parameters
Those search coordinates are in range, but the result is not great
semilogx(f, y, 'ro', 'displayname', 'original');
hold on;
semilogx(x, fun(p_fit, x), '--m', 'displayname', 'lsq'); grid on; % semilog plot of the transfer function
[Pfc, fval_fc] = fmincon(E, x0, [], [], [], [], lb, ub)
Again within range, but the results are not great
[Pfs, fval_fs] = fminsearch(E, x0)
and that one is out of range again
%semilogx(x, fun(Pfs,x), '--g', 'displayname', 'fminsearch');
semilogx(x, fun(Pfc,x), ':b', 'displayname', 'fmincon');
hold off
legend show
I did some grid searching, brute force. The locations I found varied a lot depending how fine a grid I used. The best I found so far was
63535.7188297698 0.710929969491426 0.001
but there was a lot of variability -- such as near 1000 0.01 1e-3 was only marginally more.
In short: there is no good fit.
Más respuestas (0)
Ver también
Categorías
Más información sobre Linear Least Squares en Help Center y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!