Matlab function for lorentzian fit with global variables - matlab

I want to fit a Lorentzian to my data, so first I want to test my fitting procedure to simulated data:
X = linspace(0,100,200);
Y = 20./((X-30).^2+20)+0.08*randn(size(X));
starting parameters
a3 = ((max(X)-min(X))/10)^2;
a2 = (max(X)+min(X))/2;
a1 = max(Y)*a3;
a0 = [a1,a2,a3];
find minimum for fit
afinal = fminsearch(#devsum,a0);
afinal is vector with parameters for my fit. If I test my function as follows
d= devsum(a0)
then d= 0, but if I do exactly what's in my function
a=a0;
d = sum((Y - a(1)./((X-a(2)).^2+a(3))).^2)
then d is not equal to zero. How is this possible? My function is super simple so I don't know what's going wrong.
my function:
%devsum.m
function d = devsum(a)
global X Y
d = sum((Y - a(1)./((X-a(2)).^2+a(3))).^2);
end
Basically I'm just implementing stuff I found here
http://www.home.uni-osnabrueck.de/kbetzler/notes/fitp.pdf
page 7

It is usually better to avoid using global variables. The way I usually solve these problems is to first define a function which evaluates the curve you want to fit as a function of x and the parameters:
% lorentz.m
function y = lorentz(param, x)
y = param(1) ./ ((x-param(2)).^2 + param(3))
In this way, you can reuse the function later for plotting the result of the fit.
Then, you define a small anonymous function with the property you want to minimize, with only a single parameter as input, since that is the format that fminsearch needs. Instead of using global variables, the measured X and Y are 'captured' (technical term is doing a closure over these variables) in the definition of the anonymous function:
fit_error = #(param) sum((y_meas - lorentz(param, x_meas)).^2)
And finally you fit your parameters by minimizing the error with fminsearch:
fitted_param = fminsearch(fit_error, starting_param);
Quick demonstration:
% simulate some data
X = linspace(0,100,200);
Y = 20./((X-30).^2+20)+0.08*randn(size(X));
% rough guess of initial parameters
a3 = ((max(X)-min(X))/10)^2;
a2 = (max(X)+min(X))/2;
a1 = max(Y)*a3;
a0 = [a1,a2,a3];
% define lorentz inline, instead of in a separate file
lorentz = #(param, x) param(1) ./ ((x-param(2)).^2 + param(3));
% define objective function, this captures X and Y
fit_error = #(param) sum((Y - lorentz(param, X)).^2);
% do the fit
a_fit = fminsearch(fit_error, a0);
% quick plot
x_grid = linspace(min(X), max(X), 1000); % fine grid for interpolation
plot(X, Y, '.', x_grid, lorentz(a_fit, x_grid), 'r')
legend('Measurement', 'Fit')
title(sprintf('a1_fit = %g, a2_fit = %g, a3_fit = %g', ...
a_fit(1), a_fit(2), a_fit(3)), 'interpreter', 'none')
Result:

Related

How to use matlab to quickly judge whether a function is convex?

For example, FX = x ^ 2 + sin (x)
Just for curiosity, I don't want to use the CVX toolbox to do this.
You can check this within some interval [a,b] by checking if the second derivative is nonnegative. For this you have to define a vector of x-values, find the numerical second derivative and check whether it is not too negative:
a = 0;
b = 1;
margin = 1e-5;
point_count = 100;
f=#(x) x.^2 + sin(x);
x = linspace(a, b, point_count)
is_convex = all(diff(x, 2) > -margin);
Since this is a numerical test, you need to adjust the parameter to the properties of the function, that is if the function does wild things on a small scale we might not be able to pick it up. E.g. with the parameters above the test will falsely report the function f=#(x)sin(99.5*2*pi*x-3) as convex.
clear
syms x real
syms f(x) d(x) d1(x)
f = x^2 + sin(x)
d = diff(f,x,2)==0
d1 = diff(f,x,2)
expSolution = solve(d, x)
if size(expSolution,1) == 0
if eval(subs(d1,x,0))>0
disp("condition 1- the graph is concave upward");
else
disp("condition 2 - the graph is concave download");
end
else
disp("condition 3 -- not certain")
end

How to use dynamic function name in MATLAB?

I am trying to optimize the following program by using for loops
t = 0:0.1:100;
conc = rand(size(t));
syms x
equ_1(x) = 10*x.^2+1;
equ_2(x) = 5*x.^3+10*x.^2;
equ_3(x) = 5*x.^3+10*x.^2;
y_1 = equ_1(conc);
y_2 = equ_2(conc);
y_3 = equ_3(conc);
p_1 = polyfit(t,y_1,1);
p_2 = polyfit(t,y_2,1);
p_3 = polyfit(t,y_3,1);
yfit_1 = p_1(1)*conc+p_1(2);
yfit_2 = p_2(1)*conc+p_2(2);
yfit_3 = p_2(1)*conc+p_2(2);
rms_er_1 = double(sqrt((sum((yfit_1-y_1).^2)./length(yfit_1))));
rms_er_2 = double(sqrt((sum((yfit_2-y_2).^2)./length(yfit_2))));
rms_er_3 = double(sqrt((sum((yfit_3-y_3).^2)./length(yfit_3))));
rms = [rms_er_1 rms_er_2 rms_er_3]
In this program. I have many equations and I can write them manually like equ_1(x),equ_1(x),equ_1(x) etc. After writing equations, will it be possible to write remaining programs by using for loops?
Can anyone help?
Yes, it is possible. You can pack your functions in a cell array and give your values as parameters while looping over this cell array
t = (0:0.1:100)';
conc = rand(size(t));
% Packing your function handles in a cell array ( I do not have the
% symbolic math toolbox, so I used function handles here. In your case you
% have to pack your equations equ_n(x) in between the curly brackets{} )
allfuns = {#(x) 10*x.^2+1, ...
#(x) 5*x.^3+10*x.^2, ...
#(x) 5*x.^3+10*x.^2};
% Allocate memory
y = zeros(length(t), length(allfuns));
p = zeros(2,length(allfuns));
yfit = zeros(length(t), length(allfuns));
rms = zeros(1, length(allfuns));
% Loop over all functions the cell, applying your functional chain
for i=1:length(allfuns)
y(:,i) = allfuns{i}(t);
p(:,i) = polyfit(t,y(:,i),1);
yfit(:,i) = p(1,i)*conc+p(2,i);
rms(:,i) = double(sqrt((sum((yfit(:,i)-y(:,i)).^2)./ ...
length(yfit(:,i)))));
end
This leads to
>> rms
rms =
1.0e+06 *
0.0578 2.6999 2.6999
You can expand that to an arbitrary number of equations in allfuns.
Btw: You are fitting 1st order polynomials with polyfit to values calculated with 2nd and 3rd order functions. This leads of course to rough fits with high rms. I do not know how your complete problem looks like, but you could define an array poly_orders containing the polynomial order of each function in allfuns. If you give those values as parameter to the polyfit function in the loop, your fits will work way better.
You can try cellfun
Here is an example.
Define in a .m
function y = your_complex_operation(f,x, t)
y_1 = f(x);
p_1 = polyfit(t,y_1,1);
yfit_1 = p_1(1)*x+p_1(2);
y = double(sqrt((sum((yfit_1-y_1).^2)./length(yfit_1))));
end
Then use cellfunc
funs{1}=#(x) 10*x.^2+1;
funs{2}=#(x) 5*x.^3+10*x.^2;
funs{3}=#(x) 5*x.^3+10*x.^2;
%as many as you need
t = 0:0.1:100;
conc = rand(size(t));
funs_res = cellfun(#(c) your_complex_operation(c,conc,t),funs);

Creating summation series functions in Matlab with variables for optimization

I have a dataset with 1125 rows and 64 columns. Where first 554 rows belong to one class and the remaining rows belong to the other class. The objective function
is to be minimized in terms of R_1 and R_2 where both are are row vectors(1 x 64). x_i and x_l are the rows from the data matrix. I am trying to minimize this objective function using the optimization toolbox, but I am struggling to get the objective function in the desired form and running into errors. This is how I have coded so far
data = xlsread('data.xlsx');
dat1 = data(1:554,:);
dat2 = data(555:1125,:);
f1 = #(x) 0;
f2 = #(x) 0;
%% for digits labeled 0
for i = 1:554
f1 = #(x) f1 + (dat1(i,:) - x(1)).^2;
end
%% for digits labeled 1
for j = 1:571
f2 = #(x) f2 + (dat2(j,:) - x(2)).^2;
end
%% final objective function
f = #(x) 1/554*f1 + 1/571*f2;
%%
x = fminunc(f);
Please guide me on how to correctly form this type of objective function in Matlab
None of your code makes sense. A few issues
f1 = #(x) 0; and f2 = #(x) 0 define anonymous functions which always return zero. What is the purpose of this?
Every further definition of f1,f2,f is attempting to do arithmetic operations on an anonymous function. It's not clear what you expect this to accomplish.
x = fminunc(f); is missing an argument, it needs an initial guess as well. This isn't just to initialize the algorithm but also so that fminunc knows the dimensions that the input to f should have.
For your case f should be defined so half the values passed to it refer to R1 and the other half refer to R2. For example define
l2_sq = #(x) sum(x.^2,2); % return norm(x,2)^2 for each row of x
f1 = #(R1) sum(l2_sq(bsxfun(#minus, dat1, R1)));
f2 = #(R2) sum(l2_sq(bsxfun(#minus, dat2, R2)));
f3 = #(R1,R2) -10 * norm(R1-R2,1);
f = #(R) f1(R(1:64)) + f2(R(65:128)) + f3(R(1:64), R(65:128));
Since the combined R vector has 128 elements, we need to generate an initial guess that contains 128 elements. In this case we could just use random Gaussian noise
R0 = randn(1,128);
Finally, call fminunc as
Rhat = fminunc(f, R0);
R1 = Rhat(1:64);
R2 = Rhat(65:128);
where R1 and R2 are the optimal values.
Note In MATLAB 2016b and newer, implicit expansion allows you to replace bsxfun(#minus, dat1, R1) with the more efficient dat1 - R1. Similarly for bsxfun(#minus, dat2, R2).

Numerical Integral in MatLab using integral command

I am trying to compute the value of this integral using Matlab
Here the other parameters have been defined or computed in the earlier part of the program as follows
N = 2;
sigma = [0.01 0.1];
l = [15];
meu = 4*pi*10^(-7);
f = logspace ( 1, 6, 500);
w=2*pi.*f;
for j = 1 : length(f)
q2(j)= sqrt(sqrt(-1)*2*pi*f(j)*meu*sigma(2));
q1(j)= sqrt(sqrt(-1)*2*pi*f(j)*meu*sigma(1));
C2(j)= 1/(q2(j));
C1(j)= (q1(j)*C2(j) + tanh(q1(j)*l))/(q1(j)*(1+q1(j)*C2(j)*tanh(q1(j)*l)));
Z(j) = sqrt(-1)*2*pi*f(j)*C1(j);
Apprho(j) = meu*(1/(2*pi*f(j))*(abs(Z(j))^2));
Phi(j) = atan(imag(Z(j))/real(Z(j)));
end
%integration part
c1=w./(2*pi);
rho0=1;
fun = #(x) log(Apprho(x)/rho0)/(x.^2-w^2);
c2= integral(fun,0,Inf);
phin=pi/4-c1.*c2;
I am getting an error like this
could anyone help and tell me where i am going wrong.thanks in advance
Define Apprho in a separate *.m function file, instead of storing it in an array:
function [ result ] = Apprho(x)
%
% Calculate f and Z based on input argument x
%
% ...
%
meu = 4*pi*10^(-7);
result = meu*(1/(2*pi*f)*(abs(Z)^2));
end
How you calculate f and Z is up to you.
MATLAB's integral works by calling the function (in this case, Apprho) repeatedly at many different x values. The x values called by integral don't necessarily correspond to the 1: length(f) values used in your original code, which is why you received errors.

Trouble with anonymous functions in matlab

I am having trouble with printing out h_a_b. I am able to get functions f and g but not this one. I need to use h_a_b function so i can do h(f(x),g(x)) and calculate the sqrt of h(a,b). see equations
I am always getting this error
Undefined function 'h_a_b' for input arguments of type 'function_handle'.
I am suppose to write a program that create 3 anonymous functions representing the function
Equations needed
f(x) = 10*cos x ,
g(x) = 5*sin * x, and
h(a,b) = \sqrt(a^2 + b^2).
Here is my code
f = # (x) 5*sin(x);
g = # (x) 10*cos(x);
h_a_b = # (a,b) sqrt(a.^2 + b.^2);
then I plot it with this function that was given to me.
function plotfunc(fun,points)
%PLOTFUNC Plots a function between the specified points.
% Function PLOTFUNC accepts a function handle, and
% plots the function at the points specified.
% Define variables:
% fun -- Function handle
% msg -- Error message
%
msg = nargchk(2,2,nargin);
error(msg);
% Get function name
fname = func2str(fun);
% Plot the data and label the plot
plot(points,fun(points));
title(['\bfPlot of ' fname '(x) vs x']);
xlabel('\bfx');
ylabel(['\bf' fname '(x)']);
grid on;
end
Because your function (h_a_b) takes a vector as input and gives scalar as output it represents a surface, thus plot cannot be used to visualize it (that is only for 2D, scalar-scalar plots).
Are you looking for something like this?:
f = # (x) 5*sin(x);
g = # (x) 10*cos(x);
h_a_b = # (a,b) sqrt(a.^2 + b.^2);
z = #(a,b) sqrt(h_a_b(f(a),g(b)));
[A, B] = meshgrid(0:0.1:8, 0:0.1:9);
Z = z(A,B);
surfc(A,B,Z)
xlabel('a')
ylabel('b')
figure
contourf(A,B,Z)
xlabel('a')
ylabel('b')
Second option, considering z as scalar-scalar function and using your plotfunc function:
f = # (x) 5*sin(x);
g = # (x) 10*cos(x);
h_a_b = # (a,b) sqrt(a.^2 + b.^2);
z = #(x) sqrt(h_a_b(f(x),g(x)));
points = 0:0.1:8;
plotfunc(z,points)
Which is one slice of the above surface.