0

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!

The given model is:
model

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?

Jason Aller
  • 3,541
  • 28
  • 38
  • 38

1 Answers1

1

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

  1. lsqnonlinfit minimizes the SSE of the function you pass in. Therefore the function that you'll give to it will have to output difference values (measured - predicted).

Problems with your code

  1. Your if statements do not check to ensure that the conditions of the piecewise function are met. Your if checks that d <= dbp, but not that dref <= d.
  2. The if statement will not function the way you think it will. when you do something like d <= dbp and d is not a scalar your return will be of the same size as d. The if statement will not work.
  3. This line of code 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);
  4. Your modelo function does not have n1 and n2 as parameters that get passed into it.

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.

user9985
  • 168
  • 15
  • Thank you so much! now I was able to calculate n1 and n2. I had to modify the first if condition because it gave me an error (Operands to the || and && operators must be convertible to logical scalar values.) So I deleted the first condition (dRef <= d) because dRef is equal to 1 and every di on d is greater than 1, there is no need to test for that. I didn't gave you those values so I understand you couldn't know. I did the test with my data and it gave me n1=2.2261 and n2=-3.2028. Then I tried to calculate the values for the model with the above coefficients but it gave me very – Roni Berezin Jun 23 '17 at 23:33
  • @RoniBerezin I'm glad that it work. As for the && that's actually a mistake on my part (I fixed it in the file). I was supposed to use & and not && since I am comparing two matricies. [Reasoning](https://stackoverflow.com/questions/1379415/whats-the-difference-between-and-in-matlab) – user9985 Jun 23 '17 at 23:36
  • ... distant values compared to the data I have. I think i might be calculating it wrong. Do you know how to calculate de values for every di on d for that model with the given n1 and n2? Thank you for your help – Roni Berezin Jun 23 '17 at 23:39
  • @RoniBerezin. I am not sure what you mean. I updated my code. I had some typos in the way that PL(i2) was calculated, the formula should be correct now. – user9985 Jun 23 '17 at 23:48