WindCurves: A Tool to Fit Wind Turbine Power Curves

Neeraj Bokde ([email protected]) and Andres Feijoo ([email protected])

2018-02-07

Introduction:

This is a Vignettes of R package, WindCurves. The package WindCurves is a tool used to fit the wind turbine power curves. It can be useful for researchers, data analysts/scientist, practitioners, statistians and students working on wind turbine power curves. The salient features of WindCurves package are:

Instructions to Use:

library(WindCurves)
data(pcurves)
s <- pcurves$Speed
p <- pcurves$`Nordex N90`
da <- data.frame(s,p)
x <- fitcurve(da)
#>    Weibull CDF model
#>    -----------------
#>    P = 1 - exp[-(S/C)^k]
#>    where P -> Power and S -> Speed 
#> 
#>     Shape (k) = 4.242446 
#>     Scale (C) = 9.564993 
#>    ===================================
#> 
#>    Logistic Function model
#>    -----------------------
#>    P = phi1/(1+exp((phi2-S)/phi3))
#>    where P -> Power and S -> Speed 
#> 
#>     phi 1 = 2318.242 
#>     phi 2 = 8.65861 
#>     phi 3 = 1.366053 
#>    ===================================
x
#> $Speed
#>  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
#> [24] 24 25
#> 
#> $Power
#>  [1]    0    0    0   35  175  352  580  870 1237 1623 2012 2230 2300 2300
#> [15] 2300 2300 2300 2300 2300 2300 2300 2300 2300 2300 2300
#> 
#> $`Weibull CDF`
#>  [1]    0.0000    0.0000    0.0000   90.3871  175.0000  327.5161  563.9085
#>  [8]  882.3965 1253.7489 1623.0000 1929.1254 2134.6685 2242.6251 2285.2438
#> [15] 2297.3355 2299.6816 2299.9764 2299.9990 2300.0000 2300.0000 2300.0000
#> [22] 2300.0000 2300.0000 2300.0000 2300.0000
#> 
#> $`Logistic Function`
#>  [1]    0.00000    0.00000    0.00000   74.12813  148.99331  289.70713
#>  [7]  530.79720  884.98933 1303.20985 1686.50765 1964.36723 2133.40810
#> [13] 2225.51236 2272.70005 2296.11389 2307.54694 2313.08606 2315.75946
#> [19] 2317.04738 2317.66729 2317.96554 2318.10900 2318.17801 2318.21119
#> [25] 2318.22715
#> 
#> attr(,"row.names")
#>  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
#> [24] 24 25
#> attr(,"class")
#> [1] "fitcurve"
validate.curve(x)
#>   Metrics Weibull CDF Logistic Function
#> 1    RMSE  30.8761687        38.8753476
#> 2     MAE  15.1381094        29.3213484
#> 3    MAPE   3.9292946         5.9183795
#> 4      R2   0.9989322         0.9983073
#> 5     COR   0.9995413         0.9991591
plot(x)

random <- function(x)
{
  data_y <- sort(sample(1:1500, size = 25, replace = TRUE))
  d <- data.frame(data_y)
  return(d)
}
dump("random")
rm(random)
library(WindCurves)
data(pcurves)
s <- pcurves$Speed
p <- pcurves$`Nordex N90`
da <- data.frame(s,p)
x <- fitcurve(data = da, MethodPath = "source('dumpdata.R')", MethodName = "Random values")
#>    Weibull CDF model
#>    -----------------
#>    P = 1 - exp[-(S/C)^k]
#>    where P -> Power and S -> Speed 
#> 
#>     Shape (k) = 4.242446 
#>     Scale (C) = 9.564993 
#>    ===================================
#> 
#>    Logistic Function model
#>    -----------------------
#>    P = phi1/(1+exp((phi2-S)/phi3))
#>    where P -> Power and S -> Speed 
#> 
#>     phi 1 = 2318.242 
#>     phi 2 = 8.65861 
#>     phi 3 = 1.366053 
#>    ===================================

## The user can specify .R files from other locations as:
# x <- fitcurve(data = da, MethodPath = "source('~/WindCurves/R/random.R')", MethodName = "Random values")
validate.curve(x)
#>   Metrics Weibull CDF Logistic Function Random values
#> 1    RMSE  30.8761687        38.8753476  919.51241427
#> 2     MAE  15.1381094        29.3213484  789.88000000
#> 3    MAPE   3.9292946         5.9183795   95.19981384
#> 4      R2   0.9989322         0.9983073    0.05300599
#> 5     COR   0.9995413         0.9991591    0.94035415
plot(x)

Consider error() is a function which uses two vectors as input and returns a error value with a specific error measure, such as RMSE or MAPE as shown below:

# PCV as an error metric
error <- function(a,b)
{
d <- (var(a) - var(b)) * 100/ var(a)
d <- as.numeric(d)
return(d)
}
dump("error")
rm(error)

The effect of this function can be seen in the results obtained with Validate.curve() function as:

library(WindCurves)
data(pcurves)
s <- pcurves$Speed
p <- pcurves$`Nordex N90`
da <- data.frame(s,p)
x <- fitcurve(da)
#>    Weibull CDF model
#>    -----------------
#>    P = 1 - exp[-(S/C)^k]
#>    where P -> Power and S -> Speed 
#> 
#>     Shape (k) = 4.242446 
#>     Scale (C) = 9.564993 
#>    ===================================
#> 
#>    Logistic Function model
#>    -----------------------
#>    P = phi1/(1+exp((phi2-S)/phi3))
#>    where P -> Power and S -> Speed 
#> 
#>     phi 1 = 2318.242 
#>     phi 2 = 8.65861 
#>     phi 3 = 1.366053 
#>    ===================================
validate.curve(x = x, MethodPath = "source('dumpdata.R')", MethodName = "New Error")
#>     Metrics Weibull CDF Logistic Function
#> 1      RMSE  30.8761687        38.8753476
#> 2       MAE  15.1381094        29.3213484
#> 3      MAPE   3.9292946         5.9183795
#> 4        R2   0.9989322         0.9983073
#> 5       COR   0.9995413         0.9991591
#> 6 New Error  -1.8141636         0.4127479
plot(x)

Similarly, user can compare various techniques used for wind turbine power curve fitting.

data(pcurves)
pcurves
#>    Speed Vestad V80 Vestad V164 Siemens 82 Siemens 107 Repower 82
#> 1      1          0           0          0           0          0
#> 2      2          0           0          0           0          0
#> 3      3          0           0          0           0          0
#> 4      4          2         101         42          80         64
#> 5      5         97         461        136         238        159
#> 6      6        255         902        276         474        314
#> 7      7        459        1595        470         802        511
#> 8      8        726        2513        727        1234        767
#> 9      9       1004        3737       1043        1773       1096
#> 10    10       1330        4988       1394        2379       1439
#> 11    11       1627        5987       1738        2948       1700
#> 12    12       1772        6698       2015        3334       1912
#> 13    13       1797        6984       2183        3515       2000
#> 14    14       1802        6985       2260        3577       2040
#> 15    15       1802        6995       2288        3594       2050
#> 16    16       1802        6995       2297        3599       2050
#> 17    17       1802        6995       2299        3600       2050
#> 18    18       1802        6995       2300        3600       2050
#> 19    19       1802        6995       2300        3600       2050
#> 20    20       1802        6995       2300        3600       2050
#> 21    21       1802        6995       2300        3600       2050
#> 22    22       1802        6995       2300        3600       2050
#> 23    23       1802        6995       2300        3600       2050
#> 24    24       1800        6995       2300        3600       2050
#> 25    25       1800        6995       2300        3600       2050
#>    Nordex N90
#> 1           0
#> 2           0
#> 3           0
#> 4          35
#> 5         175
#> 6         352
#> 7         580
#> 8         870
#> 9        1237
#> 10       1623
#> 11       2012
#> 12       2230
#> 13       2300
#> 14       2300
#> 15       2300
#> 16       2300
#> 17       2300
#> 18       2300
#> 19       2300
#> 20       2300
#> 21       2300
#> 22       2300
#> 23       2300
#> 24       2300
#> 25       2300
#img2points("image.jpeg")

where, image.jpeg is the name of power curve image from which discrete points are to extracted. The procedure of extraction is as follows:

References

[1] D. Villanueva and A. E. Feij´oo, “Reformulation of parameters of the logistic function applied to power curves of wind turbines,” Electric Power Systems Research, vol. 137, pp. 51–58, 2016.(via)

[2] Iain Staffell, “Wind turbine power curves, 2012” (via)