Model/backend/ml_models/AnnualBillSavings.py
2024-04-04 16:35:14 +01:00

117 lines
4.1 KiB
Python

class AnnualBillSavings:
"""
This is a simple class which will estimate the annual bill savings, based on the kwh savings.
This class uses data from Ofgem, including their price caps, to provide us with an estimate for
1KWH of energy.
"""
# These gas an electricity consumption figures are based off of figures presented by Ofgem
# https://www.ofgem.gov.uk/information-consumers/energy-advice-households/average-gas-and-electricity-use-explained
AVERAGE_ELECTRICITY_CONSUMPTION = 2700
AVERAGE_GAS_CONSUMPTION = 11500
# Latest price cap figures from Ofgem are for April 2024
# https://www.ofgem.gov.uk/publications/new-energy-price-cap-level-april-june-2024-starts-today
ELECTRICITY_PRICE_CAP = 0.245
GAS_PRICE_CAP = 0.0604
# This is a weighted mean of the price caps, using the consumption figures above as weights
PRICE_FACTOR = 0.09549999999999999
# Daily standard charge, based on average across England, Scotland and Wales, and includes VAT
DAILY_STANDARD_CHARGE_GAS = 0.3143
DAILY_STANDARD_CHARGE_ELECTRICITY = 0.601
EPC_BANDS = ["G", "F", "E", "D", "C", "B", "A"]
@classmethod
def estimate(cls, kwh: float):
"""
Estimate the annual bill savings based on the kwh savings
:param kwh: The kwh savings
:return: An estimate for annual bill savings
"""
return cls.PRICE_FACTOR * kwh
@classmethod
def estimate_electric(cls, kwh: float):
"""
Estimate the annual bill savings based on the kwh savings
:param kwh: The kwh savings
:return: An estimate for annual bill savings
"""
return cls.ELECTRICITY_PRICE_CAP * kwh
@classmethod
def calculate_annual_bill(cls, kwh):
"""
This method will estimate the total annual bill for a property
It assumed gas & electricity are used
:param kwh: The total kwh consumption
:return: An estimate for annual bill
"""
return cls.PRICE_FACTOR * kwh + (cls.DAILY_STANDARD_CHARGE_GAS + cls.DAILY_STANDARD_CHARGE_ELECTRICITY * 365)
@classmethod
def adjust_energy_to_metered(cls, epc_energy_consumption, current_epc_rating):
"""
The over-prediction of energy use by EPCs in Great Britain: A comparison
of EPC-modelled and metered primary energy use intensity
Which can be found here: https://www.sciencedirect.com/science/article/pii/S0378778823002542
We implement the results on page 10
:return:
"""
gradients = {
"A": -0.1,
"B": -0.1,
"C": -0.43,
"D": -0.52,
"E": -0.7,
"F": -0.76,
"G": -0.76
}
intercepts = {
"A": 28,
"B": 28,
"C": 97,
"D": 119,
"E": 160,
"F": 157,
"G": 157
}
gradient = gradients[current_epc_rating]
intercept = intercepts[current_epc_rating]
# This should be negative
consumption_difference = gradient * epc_energy_consumption + intercept
adjusted_consumption = (epc_energy_consumption + consumption_difference)
if adjusted_consumption < 0:
raise ValueError("consumption_difference should be negative")
return adjusted_consumption
@classmethod
def adjust_expected_band(cls, expected_epc_rating, current_epc_rating):
"""
Because of the differing intercepts and intercepts when adjusting, it's possible for
expected_adjusted_energy to be bigger than current_adjusted_energy. In this case, we'll
adjust, against at most 1 EPC band above the curent. This function performs the EPC adjustment
:param expected_epc_rating: The expected EPC rating
:param current_epc_rating: The current EPC rating
"""
# Find index of expected EPC rating
expected_index = cls.EPC_BANDS.index(expected_epc_rating)
current_index = cls.EPC_BANDS.index(current_epc_rating)
if expected_index - 1 < current_index:
return current_epc_rating
return cls.EPC_BANDS[expected_index - 1]