1

I'm trying to get some coeficients with nls and some basic data to be able to transform rssi in distance.

So far I've been able to get the fit from 'nls' function but I'm unable to use the 'predict' function to see if the fit is correct. Maybe I'm just misunderstanding something....

This is my code:

ydata = c(0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2)
xdata = c(-57, -57, -60, -65, -66, -68, -70, -73)
xdataratio <- sapply(xdata, function(e){return(e/-59)})

plot(ydata, xdata, pch=19)

p1 = 0.1
p2 = 1
p3 = 1

nlsFunction <- function(x, a, b, c) { a * 10^(b*x + c)}
propModel <- function(rssi, a, b, c) {(log(rssi/a) - c) / b}
powerFunction <- function(x, b0, b1, b2) {b0 + b1*(x^b2)}

fit = nls(ydata ~ powerFunction(xdataratio, p1, p2, p3), start=list(p1=p1, p2=p2, p3=p3))

summary(fit)

new = data.frame(xdata = seq(min(xdata), max(xdata), len=200))      
lines(new$xdata, predict(fit, newdata=new))

But, in the last line, I get a logic error:

Error in xy.coords(x, y, xlabel, ylabel, log) : 'x' and 'y' lengths differ

The problem is that the predict function is returning just 8 results, while the new$xdata is of length 200. Any help on using or understanding the predict function in this scenario?

Edit: I have changed the code to this as suggested (maybe I've understood it wrong..). Now the problem is that the predict is always returning NAN values.

ydata = c(0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2)
xdata = c(-57, -57, -60, -65, -66, -68, -70, -73)
xdataratio <- xdata/-59

data = data.frame(ydata=ydata, xdata=xdataratio)

plot(ydata, xdata, pch=19)

p1 = 0
p2 = 1
p3 = 2

powerFunction <- function(x, b0, b1, b2) {b0 + b1*(x^b2)}

new = data.frame(xdata = seq(min(xdata), max(xdata), len=200))
fit = nls(ydata ~ powerFunction(xdata, p1, p2, p3), start=list(p1=p1, p2=p2, p3=p3), data=data, trace=T)
lines(new$xdata, predict(fit, newdata=new))

Working

This is the final working code. The problem was with the data in new (I wasn't using same type of data)

ydata = c(0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2)
xdata = c(-57, -57, -60, -65, -66, -68, -70, -73)
xdataratio <- xdata/-59 #sapply(xdata, function(e){return(e/-59)})

data = data.frame(xdata=xdataratio)

plot(ydata, xdata, pch=19)

p1 = 0
p2 = 1
p3 = 2

powerFunction <- function(x, b0, b1, b2) {b0 + b1*(x^b2)}

new = data.frame(xdata = seq(min(xdata), max(xdata), len=200)/-59)
fit = nls(ydata ~ powerFunction(xdata, p1, p2, p3), start=list(p1=p1, p2=p2, p3=p3), data=data, trace=T)

summary(fit)

plot(type="lines",new$xdata, predict(fit, newdata=new))
Eylen
  • 2,617
  • 4
  • 27
  • 42
  • You need to (i) put `xdataratio` into a data.frame, (ii) use the `data` parameter of `nls` and (iii) use the same column name in `new` as in the data.frame passed as `data`. – Roland Feb 02 '17 at 08:03
  • Btw., why do you use a loop instead of the vectorized opertion `xdataratio <- xdata/-59`? – Roland Feb 02 '17 at 08:05
  • Didn't know I could do that XD I'm just starting with R so... expect lots of that things... I'll try the other steps also and let you know – Eylen Feb 02 '17 at 08:35
  • @Roland I have tried your suggestion, but I think I'm still missing something as now it returns NAN values – Eylen Feb 02 '17 at 08:54
  • Your `new` is missing at least `xdataratio`. – Roman Luštrik Feb 02 '17 at 09:01
  • ok, got it. Thanks! – Eylen Feb 02 '17 at 09:01
  • Please make your last edit into an answer. Good work on the plot, too. I was about to suggest a different plot which would be in line with the model you are fitting (based on ratio, not raw values). – Roman Luštrik Feb 02 '17 at 09:11

1 Answers1

0

This is the final working code. The problem was with the data in new (I wasn't using same type of data)

ydata = c(0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2)
xdata = c(-57, -57, -60, -65, -66, -68, -70, -73)
xdataratio <- xdata/-59 #sapply(xdata, function(e){return(e/-59)})

data = data.frame(xdata=xdataratio)

plot(ydata, xdata, pch=19)

p1 = 0
p2 = 1
p3 = 2

powerFunction <- function(x, b0, b1, b2) {b0 + b1*(x^b2)}

new = data.frame(xdata = seq(min(xdata), max(xdata), len=200)/-59)
fit = nls(ydata ~ powerFunction(xdata, p1, p2, p3), start=list(p1=p1, p2=p2, p3=p3), data=data, trace=T)

summary(fit)

plot(type="lines",new$xdata, predict(fit, newdata=new))

As pointed by @Roland, this plot seems better:

plot(distance ~ ratio, pch=19, data=data)
curve(predict(fit, newdata = data.frame(ratio = x)), add=TRUE)
Eylen
  • 2,617
  • 4
  • 27
  • 42
  • 1
    Plotting is easier with `plot(ydata ~ xdata, pch=19, data = data); curve(predict(fit, newdata = data.frame(xdata = x)), add = TRUE)`. (Note that this plots the transformed `data$xdata` and indeed `data` should contain `ydata` too.) – Roland Feb 02 '17 at 09:54
  • Great! That's exactly what I wanted! :D – Eylen Feb 02 '17 at 10:16