pq / data_processing.py
Daniel Varga
uploadable data files doing something, flaky yet
d58b6ea
from dataclasses import dataclass
import numpy as np
import pandas as pd
from scipy.interpolate import interp1d
START = f"2021-01-01"
END = f"2022-01-01"
def read_datasets(met_filename, cons_filename, old_dataset=False):
# old_dataset mode is needed if we plug this into interpolate_and_join()
# rather than join_consumption_meteorology().
# Preprocessing meteorologic data
met_data = pd.read_csv(met_filename, compression='gzip', sep=';', skipinitialspace=True, na_values='n/a', skiprows=[0, 1, 2, 3, 4])
met_data['Time'] = met_data['Time'].astype(str)
date_time = met_data['Time'] = pd.to_datetime(met_data['Time'], format='%Y%m%d%H%M')
met_data = met_data.set_index('Time')
# Preprocessing consumption data
cons_data = pd.read_csv(cons_filename, sep='\t', skipinitialspace=True, na_values='n/a', decimal=',')
cons_data['Time'] = pd.to_datetime(cons_data['Korrigált időpont'], format='%m/%d/%y %H:%M')
cons_data = cons_data.set_index('Time')
cons_data['Consumption'] = cons_data['Hatásos teljesítmény [kW]']
if old_dataset:
# consumption data is at 14 29 44 59 minutes, we move it by 1 minute
# to sync it with production data:
cons_data.index = cons_data.index + pd.DateOffset(minutes=1)
met_2021_data = met_data[(met_data.index >= START) & (met_data.index < END)]
cons_2021_data = cons_data[(cons_data.index >= START) & (cons_data.index < END)]
return met_2021_data, cons_2021_data
else:
return met_data, cons_data
def interpolate(df, target_idx):
return (df # 1. start with your data
.reindex(target_idx) # 2. align to the desired timestamps
.interpolate(method="time") # 3. interpolate *within* the range
.ffill().bfill() # 4. forward- and backward-fill anything still missing
)
def join_consumption_meteorology(
met_data: pd.DataFrame,
cons_data: pd.DataFrame,
target_freq: str = "5min",
) -> pd.DataFrame:
interp_method = "time"
met = met_data[["Production", "sr", "r", "t", "fs"]]
cons = cons_data[["Consumption"]]
cons.index = cons.index + pd.DateOffset(minutes=1)
start = max(cons.index.min(), met.index.min())
end = min(cons.index.max(), met.index.max())
cons = cons.loc[start:end].copy()
met = met .loc[start:end].copy()
# there are dupes because of daylight savings time.
cons = cons[~cons.index.duplicated(keep="last")]
common_idx = pd.date_range(start, end, freq=target_freq)[:-2]
cons_interp = interpolate(cons, common_idx)
met_interp = interpolate(met, common_idx)
# stitch together
# joined = pd.concat([cons_interp["Consumption"], met_interp["Production"]], axis=1)
joined = pd.concat([cons_interp, met_interp], axis=1)
return joined
# BESS parameters are now in BatteryModel
@dataclass
class SolarParameters:
solar_cell_num: float = 1140 # units
solar_efficiency: float = 0.93 * 0.96 # [dimensionless]
panel_power_at_NOCT: float = 280 # [W]
# this is the SR (solar radiation) level where panel_power_at_NOCT is produced:
NOCT_irradiation: float = 800 # [W/m^2]
# mutates met_2021_data
def add_production_field(met_2021_data, parameters):
# sr has dimension W/m^2.
sr = met_2021_data['sr']
# TODO use something a bit more fancy nonlinear if we have the temperature anyway.
nop_total = sr * parameters.solar_cell_num * parameters.solar_efficiency * parameters.panel_power_at_NOCT / parameters.NOCT_irradiation / 1e3
nop_total = nop_total.clip(0)
met_2021_data['Production'] = nop_total
def interpolate_and_join(met_2021_data, cons_2021_data):
print("this is obsoleted by join_consumption_meteorology(), do not use")
applicable = 24*60*365 - 15 + 5
demand_f = interp1d(range(0, 365*24*60, 15), cons_2021_data['Consumption'])
#demand_f = interp1d(range(0, 6*24*60, 15), cons_2021_data['Consumption'])
demand_interp = demand_f(range(0, applicable, 5))
production_f = interp1d(range(0, 365*24*60, 10), met_2021_data['Production'])
#production_f = interp1d(range(0, 6*24*60, 10), met_2021_data['Production'])
production_interp = production_f(range(0, applicable, 5))
all_2021_datetimeindex = pd.date_range(start=START, end=END, freq='5min')[:len(production_interp)]
all_2021_data = pd.DataFrame({'Consumption': demand_interp, 'Production': production_interp})
all_2021_data = all_2021_data.set_index(all_2021_datetimeindex)
return all_2021_data
# TODO build a dataframe instead
def monthly_analysis(results):
consumptions = []
for month in range(1, 13):
start = f"2021-{month:02}-01"
end = f"2021-{month+1:02}-01"
if month == 12:
end = "2022-01-01"
results_in_month = results[(results.index >= start) & (results.index < end)]
total = results_in_month['Consumption'].sum()
network = results_in_month['consumption_from_network'].sum()
solar = results_in_month['consumption_from_solar'].sum()
bess = results_in_month['consumption_from_bess'].sum()
consumptions.append([network, solar, bess])
consumptions = np.array(consumptions)
step_in_minutes = results.index.freq.n
# consumption is given in kW. each tick is step_in_minutes long (5mins, in fact)
# we get consumption in kWh if we multiply sum by step_in_minutes/60
consumptions_in_mwh = consumptions * (step_in_minutes / 60) / 1000
return consumptions_in_mwh