I have a set of measures of signal received power (p) at a given distance (d) and a model with unknown coefficients n1 and n2. What I have to do is find the values of n1 and n2 which minimizes the RMS error. I've seen solutions using lsqnonlin but not for piecewise defined functions. I'm a real noob in matlab and I'm having lots of trouble, please help!
So far I've defined a model.m script which defines the equation above:
function y = modelo(d,ht,hr,h0,f,data)
y=NaN(size(d));
c=3*10^8;
lambda=c/f;
rbp = 4*(ht-h0)*(hr-h0)/lambda
if d <= rbp
y = 20*log10(4*pi/lambda)+10*@(x)x(1)*log10(d)-data;
else
y =20*log10(4*pi/lambda)+10*@(x)x(1)*log10(d) + 10*@(x)x(2)*log10(d)-data;
end
The d parameter is the distances vector and data is the measured power at that distance. All other parameters are fixed numbers.
Then I'm trying to use lsqnonlin but it's not working. Any ideas on how to solve this?
As it appears that I don't have enough reputation to comment on your question and clarify some things I have gone ahead and tried my best to infer what you are trying to do. So let's start.
Assumptions
Problems with your code
d <= dbp
and d is not a scalar your return will be of the same size as d. The if statement will not work.y = 20*log10(4*pi/lambda)+10*@(x)x(1)*log10(d)-data;
does not work (neither does the other one). What you are doing here is you are trying to add together a number (20*log10(4*pi/lambda)
) and an anonymous function (10*@(x)x(1)*log10(d)-data);My attempt at fixing your modelo function
Below is the matlab function that should work. There are some important implementation details after the end of the file.
function diff = modelo(ns, d, p, lambda, dRef, dBp)
% Extracting n1 and n2 so that code is easier to read.
n1 = ns(1);
n2 = ns(2);
% Preallocating the size of PL
PL = NaN(size(d));
% Indicies for the two sections of the piecewise function
i1 = (dRef <= d) & (d <= dBp);
i2 = (d > dBp);
% Calculating the output value for the d values that fall in the first
% range
PL(i1) = ...
20 .* log10(4 .* pi .* dRef ./ lambda) + ...
10 .* n1 .* log10(d(i1) ./ dRef);
% Calculating the output values for the d values taht fall in the second
% range
PL(i2) = ...
20 .* log10(4 .* pi .* dRef ./ lambda) + ...
10 .* n1 .* log10(dBp ./ dRef) + ...
10 .* n2 + log10(d(i2) ./ dBp);
% Note that by initializing PL to NaN, any values of d outside of the two
% ranges of this function will result in a output of NaN.
% Calculates the difference between the estimated value (PL) and the
% measure value (p).
diff = PL - p;
end
NOTE: lsqnonlin requires the input function to be of the form func(x)
where x is the values that you are fitting for. In this case our modelo function is of the form modelo(ns, d, p, lambda, dRef, dBp)
. In order to make this work, we'll have to make use of an anonymous function. So the file where you call lsqnonlin from will look something like this:
% Initial guesses for n1 and n2, n1 will be the 1st entry and n2 the 2nd.
n0 = ...;
% Distance data, as a vector
D = ...;
% Power data, as a vector
P = ...;
% Value of lambda
LAMBDA = ...;
% Value of dRef
DREF = ...;
% Value of dBp
DBP = ...;
% Calling lsqnonlin
ns = lsqnonlin(@(n) modelo(n, D, P, LAMDA, DREF, DBP), n0);
What's going on inside that call to lsqnonlin is that we're converting wrapping the call to modelo inside an anonymous function. The anonymous function takes in a single variable (n) and therefore it fits the requirements of lsqnonlin. Notice that modelo still requires all the other information to be passed to it, and we do this inside the anonymous function. I have capitalized the variable names that get passed into it to emphasize this fact.