knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
lapply(c('data.table'), library, character.only = TRUE)

meterDT <- fread('vignetteData.csv')
#source('C:/Users/Andrew/Dropbox/Res-Intel Model/R_Packages/ebase/ebase/R/functions.R')

The primary purpose of the ebase package is to estimate a baseline model of metered energy consumption and to predict metered consumption over a user-specified time period. It is designed to estimate savings attributed to an energy conservation measure (ECM), adhering to the energy modeling and validatation guidelines established by ASHRAE 2014; but it is also suited to any other modeling application that involves hourly metered energy data. Each function in the package is optimized to interpret data.table objects that contain data for multiple meters. Working exclusively with data.table objects is beneficial because it greatly improves overall performance, making it feasible to scale ebase to data for thousands or even millions of meters.

Modeling and Predicting Enery Consumption

The baselineModel() function processes metered energy data from 1 or more meters, estimates a predictive model for each meter and returns model predictions. Typically the user will specify a date in which an energy conservation measure (ECM) was installed at each meter, estimate the model from a baseline period prior to the ECM date and predict consumption after the ECM date. Subracting predicted from actual consumption after the ECM date yields total energy savings from the ECM. Although this vignette focuses on examples that evaluate savings from an ECM, baselineModel() does not require ECM date and can be used for other purposes.

The predictions generated by baselineModel() come from a linear regression with hour-of-week and month-of-year fixed effects. Regressions are estimated using the lm and lfe packages. When temperature data is provided, the regression includes indicator variables assigned to 5-degree temperature bins ranging from 50 degrees farenheight (and below) to 95 degrees (and above). The regression may also include indicator variables controlling for non-routine adjustments and year-over-year trends if the user specifies them using the nra.start.var, nra.end.var and yoy.adjust arguments.

Example

In order to use baselineModel() to calculate ECM savings, the user needs to begin with a data.table that contains columns specifying (1) meter labels (2) dates (3) hour of day (4) energy conumption (5) and ECM installation dates. In many cases, there will also be a column that reports the average outside air temperature for each hour. The example data.table meterDT lists data for three meters J, I and L:

# meterDT

Each meter reports consumption data from 2016 through 2017 and the ECM installation date is specified by the "install_date" column. The user can feed this data into baselineModel() assigning the appropriate column label to each function argument:

# x <- baselineModel(dt = meterDT,
#                    id.var = meter,
#                    date.var = date,
#                    use.var = electricity,
#                    hour.var = hour,
#                    temp.var = temperature,
#                    install.date.var = install_date)
# names(x)

The function returns four objects $predictions, $thermal, $trend and $NRAdjust. The $predictions object is a data.table containing hourly model predictions for energy consumption, given by the "pElct" column:

# x$predictions

The user can now plot daily consumption and model predictions using the plot() function. The plot below illustrates our data and model predictions for meter L.

# y <- plot(x)
# y$L

The vertical dashed line indicates the ECM installation date, March 27th 2017. By default the model is estimated using a 12-month baseline period prior to the ECM installation date, but number of months included in the baseline period can be adjusted using the base.length argument. Notice that the model predictions closely track actual consumption for the entire baseline period. After the date of the ECM installation, actual consumption dips lower, mostly falling below predicted consumption for the remainder of 2017. This gap between predicted and actual consumption indicates the level of savings produced by the ECM.

Savings

Calculating ECM savings for a specific meter is a straightforward exercise. The example below calculates total savings (kWh) and the percent of energy saved during the recorded period after meter L's ECM was installed.

# actual_kWh <- sum(x$predictions[meterID == 'L' & postECM == 1, elct])
# predicted_kWh <- sum(x$predictions[meterID == 'L' & postECM == 1, pElct])
# saved_kWh <- actual_kWh - predicted_kWh 
# saved_percent <- 100*saved_kWh/predicted_kWh
# 
# saved_kWh
# saved_percent

Our model shows that the ECM saved 439,625 kWh between March 27th and December 31st 2017, representing a 7% drop in consumption. It is easy to calculate program-level savings in this framework because doing so requires only that the user substitute a broader meterID subset in the code above or omit the subsetting entirely.

Model Evaluation

Modeling uncertainty is an important consideration when interpreting a baseline model's consumption and savings predictions. Following guidelines from ASHRAE 2014 ebase evaluates the fractional savings uncertainty of each model using the function fUncertainty(). Fractional savings uncertainty (FSU) is the ratio of baseline model uncertainty (given by its coefficient of variation of root mean squared error, or CVRMSE) to the expected program savings. When calculating fractional uncertainty, the user can specify the expected savings from the ECM (fSavings) and the confidence-level of the estimate (tstat). The fUncertainty() function then produces a table and plot of FSU estimates as a function of the number of days the meter is observed after the ECM installation. The example below illustrates the FSU attributed to the meter L model under three different expecations of expect fractional savings: 5%, 10% and 15%.

# z <- fUncertainty(dt = x$predictions, fSavings = c(0.05, 0.1, 0.15))
# names(z)
# z$plots$L

The horizontal dashed line represents the ASHRAE recommended maximum FSU level of 50%. Meter L's baseline model appears to uniformly satisfy this requirement for all levels of expected savings.

Consumption vs. Temperature

For meters that are assigned temperature data, the regressions estimated in baselineModel() map the relationship between outside air temperature and metered consumption. The regressions control for hour-of-week and month-of-year effects, so estimates are unlikely to be spurius correlations. In a commercial building, for example, a simple positive correlation between temperature and metered consumption might exist only because business hours correspond to warmer hours of the day. The regression, however, controls for these scheduling effects and therefore provides a better causal estimate of the relationship between temperature and metered consumption compared to simple correlational analysis. The $thermal object from the prediction output provides a list of the effect of temperature on consumption using 70-75 degrees as a reference point. The user can plot this object using the print_thermalSensitivity() function. The plots below show relationship between temperature and consumption for meters J and L.

# Deprecated
# p <- print_thermalSensitivity(x$thermal, print = TRUE)
# p$J
# p$L

These plots show that consumption for both meters is reponsive to outside air temperature. Meter J is more responsive to lower temperatures, reducing usage by 20% at temperatures 50 degrees and below and increasing consumption 5% for temperatures 95 and above. Meter L, however, is more responsive to higher temperatures (increasing by up to 15%) than to low temperatures (decreasing up to 11%). Percentage changes are calculated by taking the log of the dependent variable in the regression models and then transforming the coefficients yielded by estimation. Standard errors (used to generate the dashed 95 percent confidence intervals in the graph) are calculated using the delta method.

Non-Routine Adjustments

The regressions estimated in baselineModel() can accomadate for temporary shifts in consumption, or "non-routine adjustments." To do this, the user must create a column in the starting data.table that indicates the adjustment start date and end date (if any), and then assign these columns to the appropriate function arguments. In the example dataset, meter J experiences a non-routine drop in consumption starting in February 2017 and ending at the start of July 2017. This might be caused by equipment failure or a temporary change in business operations if meter J is a commercial meter. The user must first add variable(s) that report the dates of this event:

meterDT[meter == 'J', eventStart:= '2/1/2017']
meterDT[meter == 'J', eventEnd:= '7/1/2017']

We can now estimate a new baseline model that adjusts for this non-routine shift in consumption using the arguments nra.star.var and nra.end.var:

# x2 <- baselineModel(dt = meterDT,
#                    id.var = meter,
#                    date.var = date,
#                    use.var = electricity,
#                    hour.var = hour,
#                    temp.var = temperature,
#                    install.date.var = install_date,
#                    nra.start.var = eventStart,
#                    nra.end.var = eventEnd)

It is illustrative to compare model predictions based on whether they adjusts for a non-routine event. The first plot below shows meter J's predicted consumption without the adjustment and the second plot shows predictions with the adjustment. Notice that the first plot overpredicts consumption during the non-routine event compared to the second plot that adjusts for the non-routine reduction in metered consumption that takes place between February and July. If the model did not adjust for the non-routine event it would overestimate energy savings following the ECM in April of 2017. Including non-routine events in baseline model estimation can therefore be critical when calculating ECM savings.

# Without non-routine adjustment
# y$J

# With non-routine adjustment
# y2 <- plot(x2)
# y2$J


aroyal641/ebase documentation built on Oct. 3, 2020, 4:03 a.m.