Help needed to set proper curve fitting constraints for a comprehensive solution for fitting data to custom models

26 Ansichten (letzte 30 Tage)
Hello,
Trying to fit a custom model to my data but unable to get any results. So far tried playing with a bunch of curve fitting parameters like step size tolerance etc. but I don't think I have a proper understanding of the different parameters in the curvefitter app. Need help finding details/examples for the parameters in the advanced options section of the app.
Currently using the lsqcurvefit function with expected intitial value for the coefficients. Need to know which parameters to tweak to get any fit at all. I have tried curtailing my data to fit a section of it intead of the whole thing. See the attached code and data below:
Thanks!
clc
close all
clear
data = csvread('AT COAX, OPEN ELECTRODE3.CSV',3,0,[3,0,1603,2]);
datax = data(:,1);
datay = data(:,2);
freq = datax(650:850);
%freq = data(:,1);
realZ = datay(650:850);
%realZ = data(:,2);
fun = @(x, R_E, C_E, C_C, L_E) ((R_E.*C_E.^2)./...
(((C_C.*C_E.*L_E.*(2*pi*x).^2).^2) + ...
((C_C.*C_E.*R_E.*(2*pi*x)).^2) + (C_C.^2) + ...
(C_E.^2) + 2*C_C.*C_E - 2*(C_C.^2).*C_E.*L_E.*((2*pi*x).^2) - ...
2*(C_E.^2).*C_C.*L_E.*((2*pi*x).^2)));
%options = optimoptions(@lsqcurvefit,'StepTolerance',1e-10)
sol = lsqcurvefit(@(x,xdata) fun(xdata,x(1),x(2),x(3),x(4)) , [1, 100e-12, 100e-12, 100e-9], freq, realZ);
Local minimum possible. lsqcurvefit stopped because the size of the current step is less than the value of the step size tolerance.
hold on
plot(freq, realZ)
plot(freq,fun(freq,sol(1),sol(2),sol(3),sol(4)))
hold off

Antworten (2)

Sam Chak
Sam Chak am 17 Nov. 2025
Hi @sxh
It appears you used the Witch of Agnesi, a well-known bell-shaped function (technically, the derivative of the arctangent function) to fit the curve. A closer look shows that the frequency‑response data are not perfectly symmetric.
However, the following composite bell‑shaped function can approximate the curve where the generalized Gaussian controls the peak sharpness, while the hyperbolic secant shapes the decaying tails.
data = csvread('AT COAX, OPEN ELECTRODE3.CSV',3,0,[3,0,1603,2]);
datax = data(:,1);
datay = data(:,2);
freq = datax(650:850);
realZ = datay(650:850);
xdata = freq/max(freq);
ydata = realZ/max(realZ);
fun = @(p, xdata) p(4)*exp(- abs((xdata - p(1))/p(2)).^(2/p(3))) + (1 - p(4))*sech(p(5)*(xdata - p(1)));
lb = [0.8, 0.005, 1.0, 0.8, 29.0];
ub = [0.9, 0.015, 2.0, 1.0, 49.0];
p0 = [0.87 0.010, 1.7, 0.9, 2.0];
sol = lsqcurvefit(fun, p0, xdata, ydata, lb, ub)
Local minimum possible. lsqcurvefit stopped because the final change in the sum of squares relative to its initial value is less than the value of the function tolerance.
sol = 1×5
0.8671 0.0107 1.2930 0.8504 38.6035
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
hold on
plot(freq, realZ, '.'), grid on % data
plot(freq, max(realZ)*fun(sol, freq/max(freq))) % fitted model
hold off
xlabel('freq')
ylabel('realZ')
title('Frequency‑response curve')
legend('data', 'fitted model')

Sam Chak
Sam Chak am 17 Nov. 2025
Hi @sxh
The Witch of Agnesi provides a very good fit for the curve, although your original "witch" function needs proper centering and scaling. I will leave solving the simultaneous equations for the parameters , , , , and the center point as an exercise.
Note that the Witch of Agnesi has 3 critical parameters, whereas your original "witch" function has 5 variables, including the center point. A system with more variables (5) than equations (3) is underdetermined because it has either infinitely many solutions or none. However, you may fix the center point and choose 2 of the 4 variables {, , , } as free parameters.
data = csvread('AT COAX, OPEN ELECTRODE3.CSV', 3, 0, [3, 0, 1603, 2]);
datax = data(:,1);
datay = data(:,2);
freq = datax(650:850);
realZ = datay(650:850);
xdata = freq/max(freq);
ydata = realZ/max(realZ);
%% Original "Witch of Agnesi"
% fun = @(x, R_E, C_E, C_C, L_E, ctr) ...
% ( ...
% (R_E.*C_E.^2)./...
% ( ...
% (C_C.*C_E.*L_E.*(2*pi*(x - ctr)).^2).^2 + ...
% (C_C.*C_E.*R_E.*(2*pi*(x - ctr)) ).^2 + ...
% C_C.^2 + C_E.^2 + 2*C_C.*C_E - ... % the constant
% 2*(C_C.^2).*C_E.*L_E.*(2*pi*(x - ctr)).^2 - ...
% 2*(C_E.^2).*C_C.*L_E.*(2*pi*(x - ctr)).^2 ...
% ) ...
% );
% sol = lsqcurvefit(@(p, xdata) fun(xdata, p(1), p(2), p(3), p(4), p(5)) , [1, 1, 1, 1, 0.8671], xdata, ydata)
figure
plot(xdata, ydata), grid minor
title('Normalized data')
xlabel('xdata')
ylabel('ydata')
% Simplified form of the Witch of Agnesi
fun = @(x, p1, p2, p3) p1./(p3*(x - p2).^2 + p1);
lb = [0.008, 0.80, 90];
ub = [0.010, 0.90, 110];
p0 = [0.009, 0.85, 100];
sol = lsqcurvefit(@(p, xdata) fun(xdata, p(1), p(2), p(3)), p0, xdata, ydata, lb, ub)
Local minimum found. Optimization completed because the size of the gradient is less than the value of the optimality tolerance.
sol = 1×3
0.0090 0.8671 100.1191
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
figure
hold on
plot(freq, realZ, '.'), grid on % data
plot(freq, max(realZ)*fun(freq/max(freq), sol(1), sol(2), sol(3))) % fitted model
hold off
xlabel('freq')
ylabel('realZ')
title('Fit Frequency‑response curve with the Witch of Agnesi')
legend('data', 'fitted model')
  3 Kommentare
Sam Chak
Sam Chak am 17 Nov. 2025
Thanks @Torsten. I believe the OP ultimately wants to determine the fundamental electrical properties, resistance , capacitances and , and inductance from the fitted curve. Would the solve() function be preferred over fsolve() for solving a system of nonlinear equations in this case?
sxh
sxh am 3 Dez. 2025
I simplified my model to look like your witch function although my model has 4 not 3 fitting parameters (p0, p1, p2 , p3). Here I chose initial values known to fit a similar frequency response curve (in red). Still no luck.See below:
clc
close all
clear
data = csvread('AT COAX, OPEN ELECTRODE3.CSV',3,0,[3,0,1603,2]);
Error using csvread (line 12)
File not found.
datax = data(:,1);
datay = data(:,2);
freq = datax(650:850);
freq2 = freq.^2; % xdata
realZ = datay(650:850); % ydata
fun = @(x, p0, p1, p2, p3) (p0./(p1.*(x.^2) + p2.*x + p3)); % model
x0 = [3.508848*10^(-21), 2.967903498*10^(-51), -1.334696553*10^(-35), 1.500625*10^(-20)];
sol = lsqcurvefit(@(x,xdata) fun(xdata,x(1),x(2),x(3),x(4)), x0, freq2, realZ)
plot(freq, realZ) % plot data
hold on
plot(freq,fun(freq2, 3.508848*10^(-21), 2.967903498*10^(-51), -1.334696553*10^(-35), 1.500625*10^(-20))) % plot a similar dataset with known fit parameters
hold on
plot(freq,fun(freq2,sol(1),sol(2),sol(3),sol(4))) % plot "fitted" model

Melden Sie sich an, um zu kommentieren.

Kategorien

Mehr zu Linear and Nonlinear Regression finden Sie in Help Center und File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by