Compare commits
56 Commits
ca10254c52
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
f1b2959143 | ||
|
df2f953678 | ||
|
3740136d7c | ||
|
e04e01e943 | ||
|
9f472b4bf4 | ||
|
127f005dcd | ||
|
c5edf456c5 | ||
|
d8ece46e14 | ||
|
566ebca6cd | ||
|
c8c37b756c | ||
|
4f1a47d505 | ||
|
ad9b5e6a19 | ||
|
33871fba77 | ||
|
9d143399ed | ||
|
72d4ce811e | ||
|
060fa5bff1 | ||
|
ebebd2d481 | ||
|
a330946f71 | ||
|
32e8e59c82 | ||
|
c4ec4590c2 | ||
|
cb0bd2c3e0 | ||
|
4364411485 | ||
|
54dc8b744c | ||
|
d4fde202d0 | ||
|
58a7662a8b | ||
|
d791ac481a | ||
|
4b72bc6fa3 | ||
|
eb24361ea3 | ||
|
fd3bbbf212 | ||
|
760cdc9c1f | ||
|
23826aed75 | ||
|
8cf3d6472c | ||
|
c217b6309c | ||
|
f85fcd58f2 | ||
|
cf7a66276f | ||
|
bf74e87ba0 | ||
|
2788aafbf3 | ||
|
30e8d968f2 | ||
|
8d040e64a0 | ||
|
202d313684 | ||
|
da69e7e24a | ||
|
0f49dba47e | ||
|
f9b7af6feb | ||
|
f51921dd06 | ||
|
06808d55a1 | ||
1679831dbd | |||
651833b521 | |||
3bc2478cd9 | |||
b79ffb2416 | |||
c0a7b5beff | |||
ed58e34e7e | |||
88240280ca | |||
09ef44fc21 | |||
f7afee2a64 | |||
90c96a512a | |||
3cc208035a |
191
EnergySystem.py
Normal file
191
EnergySystem.py
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
from config import pv_config, ess_config, grid_config
|
||||||
|
import pandas as pd
|
||||||
|
class EnergySystem:
|
||||||
|
def __init__(self, pv_type: pv_config, ess_type: ess_config, grid_type: grid_config):
|
||||||
|
self.pv = pv_type
|
||||||
|
self.ess = ess_type
|
||||||
|
self.grid = grid_type
|
||||||
|
self.day_generated = []
|
||||||
|
self.generated = 0
|
||||||
|
self.stored = 0
|
||||||
|
self.hour_stored = []
|
||||||
|
self.hour_stored_2 = []
|
||||||
|
self.afford = True
|
||||||
|
self.cost = self.ess.get_cost() + self.pv.get_cost()
|
||||||
|
self.overload_cnt = 0
|
||||||
|
self.spring_week_gen = []
|
||||||
|
self.summer_week_gen = []
|
||||||
|
self.autumn_week_gen = []
|
||||||
|
self.winter_week_gen = []
|
||||||
|
self.spring_week_soc = []
|
||||||
|
self.summer_week_soc = []
|
||||||
|
self.autumn_week_soc = []
|
||||||
|
self.winter_week_soc = []
|
||||||
|
self.factory_demand = []
|
||||||
|
self.buy_price_kWh = []
|
||||||
|
self.sell_price_kWh = []
|
||||||
|
self.pv_generated_kWh = []
|
||||||
|
self.grid_need_power_kW = []
|
||||||
|
self.time = []
|
||||||
|
self.ess_rest = 0
|
||||||
|
self.granularity = 4
|
||||||
|
self.season_step = self.granularity * 24 * 7 * 12
|
||||||
|
self.season_start= self.granularity * 24 * 7 * 2
|
||||||
|
self.week_length = self.granularity * 24 * 7
|
||||||
|
self.unmet = []
|
||||||
|
|
||||||
|
def get_cost(self):
|
||||||
|
return self.ess.get_cost()+self.pv.get_cost()
|
||||||
|
|
||||||
|
def simulate(self, data, time_interval):
|
||||||
|
"""
|
||||||
|
The program will use the PV to supply the factory first. If the PV output can meet the factory's demand, it will be directly powered, and the excess electrical energy will be used to charge the ESS. Program will use the PV to supply the Ess.
|
||||||
|
|
||||||
|
When the PV is insufficient, the ESS is used to supplement. If the PV output is not enough to meet the factory's demand, the required power is first obtained from the ESS.
|
||||||
|
|
||||||
|
If the ESS is also insufficient to meet the demand, it will be obtained from the grid. When the stored power in the ESS is also insufficient to supplement, the remaining required power will be purchased from the grid.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data: pandas.DataFrame
|
||||||
|
The data that contains the factory's demand, PV output, and electricity price.
|
||||||
|
time_interval: float
|
||||||
|
The time interval of the data in hours.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple
|
||||||
|
The total benefit, total netto benefit, and total generated energy.
|
||||||
|
|
||||||
|
"""
|
||||||
|
total_benefit = 0
|
||||||
|
total_netto_benefit = 0
|
||||||
|
total_gen = 0
|
||||||
|
net_grid = 0.
|
||||||
|
for index, row in data.iterrows():
|
||||||
|
time = row['time']
|
||||||
|
self.time.append(time)
|
||||||
|
# sunlight_intensity = row['sunlight']
|
||||||
|
pv_yield = row['PV yield[kW/kWp]']
|
||||||
|
factory_demand = row['demand']
|
||||||
|
electricity_price = row['buy']
|
||||||
|
sell_price = row['sell']
|
||||||
|
# electricity_price = self.grid.get_price_for_time(time)
|
||||||
|
|
||||||
|
# if time == '00:00':
|
||||||
|
# self.day_generated.append(self.generated)
|
||||||
|
# self.generated = 0
|
||||||
|
# if time.endswith('14:00'):
|
||||||
|
# soc = self.ess.storage / self.ess.capacity
|
||||||
|
# self.hour_stored.append(soc)
|
||||||
|
# if time.endswith('08:00'):
|
||||||
|
# soc = self.ess.storage / self.ess.capacity
|
||||||
|
# self.hour_stored_2.append(soc)
|
||||||
|
|
||||||
|
# `generated_pv_power`: the power generated by the PV in kW
|
||||||
|
# `generated_pv_energy`: the energy generated by the PV in kWh
|
||||||
|
generated_pv_power = self.pv.capacity * pv_yield
|
||||||
|
generated_pv_energy = generated_pv_power * time_interval * self.pv.loss
|
||||||
|
|
||||||
|
self.pv_generated_kWh.append(generated_pv_energy)
|
||||||
|
self.factory_demand.append(factory_demand)
|
||||||
|
self.buy_price_kWh.append(electricity_price)
|
||||||
|
self.sell_price_kWh.append(sell_price)
|
||||||
|
|
||||||
|
self.generated += generated_pv_energy
|
||||||
|
# generated_pv_energy is larger than factory_demand energy
|
||||||
|
if generated_pv_energy >= factory_demand * time_interval:
|
||||||
|
"""
|
||||||
|
That means the generated energy is enough to power the factory.
|
||||||
|
The surplus energy will be used to charge the ESS.
|
||||||
|
|
||||||
|
surplus_energy: The energy that is left after powering the factory.
|
||||||
|
formula: generated_pv_energy - factory_demand * time_interval
|
||||||
|
|
||||||
|
charge_to_ess: The energy that will be charged to the ESS.
|
||||||
|
formula: min(surplus_energy, ess.charge_power * time_interval, ess.capacity - ess.storage)
|
||||||
|
|
||||||
|
surplus_after_ess: The energy that is left after charging the ESS.
|
||||||
|
"""
|
||||||
|
surplus_energy = generated_pv_energy - factory_demand * time_interval
|
||||||
|
charge_to_ess = min(surplus_energy, self.ess.charge_power * time_interval, self.ess.capacity - self.ess.storage)
|
||||||
|
self.ess.storage += charge_to_ess
|
||||||
|
surplus_after_ess = surplus_energy - charge_to_ess
|
||||||
|
"""
|
||||||
|
If there is still surplus energy after charging the ESS, and the generated PV power is greater than the sum of the ESS's charge power and the factory's demand power, the surplus energy will be sold to the grid.
|
||||||
|
"""
|
||||||
|
if surplus_after_ess > 0 and generated_pv_power > self.ess.charge_power + factory_demand:
|
||||||
|
sold_to_grid = surplus_after_ess
|
||||||
|
sell_income = sold_to_grid * sell_price
|
||||||
|
total_benefit += sell_income
|
||||||
|
"""
|
||||||
|
Saved energy is the energy that is saved by using the PV to power the factory.
|
||||||
|
"""
|
||||||
|
saved_energy = factory_demand * time_interval
|
||||||
|
self.grid_need_power_kW.append(0)
|
||||||
|
else:
|
||||||
|
"""
|
||||||
|
If the generated energy is not enough to power the factory, the ESS will be used to supplement the energy.
|
||||||
|
|
||||||
|
needed_from_ess: The energy that is needed from the ESS to power the factory.
|
||||||
|
formula: factory_demand * time_interval - generated_pv_energy
|
||||||
|
"""
|
||||||
|
needed_from_ess = factory_demand * time_interval - generated_pv_energy
|
||||||
|
"""
|
||||||
|
If the ESS has enough stored energy to power the factory, the energy will be taken from the ESS.
|
||||||
|
"""
|
||||||
|
if self.ess.storage * self.ess.loss >= needed_from_ess:
|
||||||
|
if self.ess.discharge_power * time_interval * self.ess.loss < needed_from_ess:
|
||||||
|
discharging_power = self.ess.discharge_power * time_interval
|
||||||
|
else:
|
||||||
|
discharging_power = needed_from_ess / self.ess.loss
|
||||||
|
|
||||||
|
self.ess.storage -= discharging_power
|
||||||
|
"""
|
||||||
|
In this case, the energy that is needed from the grid is 0.
|
||||||
|
"""
|
||||||
|
saved_energy = generated_pv_energy + discharging_power * self.ess.loss
|
||||||
|
self.grid_need_power_kW.append(0)
|
||||||
|
else:
|
||||||
|
"""
|
||||||
|
If the ESS does not have enough stored energy to power the factory, the energy will be taken from the grid.
|
||||||
|
"""
|
||||||
|
if self.grid.capacity * time_interval + generated_pv_energy + self.ess.storage * self.ess.loss < factory_demand * time_interval:
|
||||||
|
self.afford = False
|
||||||
|
self.overload_cnt+=1
|
||||||
|
self.unmet.append((index,time,factory_demand,generated_pv_power))
|
||||||
|
saved_energy = generated_pv_energy + self.ess.storage * self.ess.loss
|
||||||
|
self.ess.storage = 0
|
||||||
|
needed_from_grid = factory_demand * time_interval - saved_energy
|
||||||
|
net_grid = min(self.grid.capacity * time_interval, needed_from_grid) * self.grid.loss
|
||||||
|
self.grid_need_power_kW.append(needed_from_grid * 4)
|
||||||
|
total_gen += saved_energy
|
||||||
|
benefit = (saved_energy) * electricity_price
|
||||||
|
cost = net_grid * electricity_price
|
||||||
|
total_netto_benefit += benefit
|
||||||
|
total_benefit += benefit - cost
|
||||||
|
print_season_flag = False
|
||||||
|
if print_season_flag == True:
|
||||||
|
week_start = self.season_start
|
||||||
|
week_end = self.week_length + week_start
|
||||||
|
if index in range(week_start, week_end):
|
||||||
|
self.spring_week_gen.append(generated_pv_power)
|
||||||
|
self.spring_week_soc.append(self.ess.storage / self.ess.capacity)
|
||||||
|
self.ess_rest = self.ess.storage
|
||||||
|
# summer
|
||||||
|
week_start += self.season_step
|
||||||
|
week_end += self.season_step
|
||||||
|
if index in range(week_start, week_end):
|
||||||
|
self.summer_week_gen.append(generated_pv_power)
|
||||||
|
self.summer_week_soc.append(self.ess.storage / self.ess.capacity)
|
||||||
|
# # autumn
|
||||||
|
week_start += self.season_step
|
||||||
|
week_end += self.season_step
|
||||||
|
if index in range(week_start, week_end):
|
||||||
|
self.autumn_week_gen.append(generated_pv_power)
|
||||||
|
self.autumn_week_soc.append(self.ess.storage / self.ess.capacity)
|
||||||
|
week_start += self.season_step
|
||||||
|
week_end += self.season_step
|
||||||
|
if index in range(week_start, week_end):
|
||||||
|
self.winter_week_gen.append(generated_pv_power)
|
||||||
|
self.winter_week_soc.append(self.ess.storage / self.ess.capacity)
|
||||||
|
|
||||||
|
return (total_benefit, total_netto_benefit, total_gen)
|
BIN
PV&PowerConsumptionData.xlsx
Normal file
BIN
PV&PowerConsumptionData.xlsx
Normal file
Binary file not shown.
19
README.md
Normal file
19
README.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Simple PV Simulator
|
||||||
|
|
||||||
|
Feature list:
|
||||||
|
|
||||||
|
- [] Draw the entire year's electricity consumption figure.
|
||||||
|
- [] Draw the entire year's energy generation figure.
|
||||||
|
- [] Draw a heatmap of the system profit in different configurations.
|
||||||
|
~~- []Calculate the probability of a successful run.~~
|
||||||
|
- [] Determine whether the system can run successfully
|
||||||
|
- [] Calculate the ROI.
|
||||||
|
- [] Read the configs from the file, including `time granularity`,
|
||||||
|
- ess: `capacity`, `cost per kW`, `charge power`, `discharge power`, `loss`
|
||||||
|
- pv: `capacity`, `cost per kW`, `loss`
|
||||||
|
- grid: `capacity`, `sell price`
|
||||||
|
- file:
|
||||||
|
- `lightintensity.xlsx`: record the light intensity. Value in the file should be between 0 and 1
|
||||||
|
- `factory_power.xlsx`: record the power consumption in the factory. Default time granularity is `15min`
|
||||||
|
- `combined_data.csv`: This file is generated by the Python script, including the `light` `intensity`, `factory_power`, `time`.
|
||||||
|
- [] GUI.
|
BIN
__pycache__/EnergySystem.cpython-311.pyc
Normal file
BIN
__pycache__/EnergySystem.cpython-311.pyc
Normal file
Binary file not shown.
BIN
__pycache__/config.cpython-311.pyc
Normal file
BIN
__pycache__/config.cpython-311.pyc
Normal file
Binary file not shown.
35041
combined_data.csv
Normal file
35041
combined_data.csv
Normal file
File diff suppressed because it is too large
Load Diff
53
config.json
Normal file
53
config.json
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"pv":{
|
||||||
|
"loss": 0.98,
|
||||||
|
"cost_per_kW": 200,
|
||||||
|
"lifetime": 15
|
||||||
|
},
|
||||||
|
"ess":{
|
||||||
|
"loss": 0.98,
|
||||||
|
"cost_per_kW": 300,
|
||||||
|
"lifetime": 8
|
||||||
|
},
|
||||||
|
"grid":{
|
||||||
|
"loss": 0.98,
|
||||||
|
"sell_price": 0.2 ,
|
||||||
|
"capacity": 5000
|
||||||
|
},
|
||||||
|
"pv_capacities":{
|
||||||
|
"begin": 0,
|
||||||
|
"end": 50000,
|
||||||
|
"groups": 3
|
||||||
|
},
|
||||||
|
"ess_capacities":{
|
||||||
|
"begin": 0,
|
||||||
|
"end": 100000,
|
||||||
|
"groups": 3
|
||||||
|
},
|
||||||
|
"time_interval":{
|
||||||
|
"numerator": 15,
|
||||||
|
"denominator": 60
|
||||||
|
},
|
||||||
|
"annotated": {
|
||||||
|
"unmet_prob": false,
|
||||||
|
"benefit": false,
|
||||||
|
"cost": false,
|
||||||
|
"roi": false
|
||||||
|
},
|
||||||
|
"figure_size":{
|
||||||
|
"height": 9,
|
||||||
|
"length": 10
|
||||||
|
},
|
||||||
|
"plot_title":{
|
||||||
|
"unmet_prob": "Coverage Rate of Factory Electrical Demands",
|
||||||
|
"cost": "Costs of Microgrid system [m-EUR]",
|
||||||
|
"benefit": "Financial Profit Based on Py & Ess Configuration (k-EUR / year)",
|
||||||
|
"roi": "ROI"
|
||||||
|
},
|
||||||
|
"data_path": {
|
||||||
|
"pv_yield": "read_data/Serbia.csv",
|
||||||
|
"demand": "read_data/factory_power1.csv",
|
||||||
|
"sell": "read_data/electricity_price_data_sell.csv",
|
||||||
|
"buy": "read_data/electricity_price_data.csv"
|
||||||
|
}
|
||||||
|
}
|
29
config.py
29
config.py
@@ -1,23 +1,34 @@
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
class pv_config:
|
class pv_config:
|
||||||
def __init__(self, capacity, cost_per_kW, pv_lifetime, pv_loss):
|
def __init__(self, capacity, cost_per_kW, lifetime, loss):
|
||||||
self.capacity = capacity
|
self.capacity = capacity
|
||||||
self.cost_per_kW = cost_per_kW
|
self.cost_per_kW = cost_per_kW
|
||||||
self.pv_lifetime = pv_lifetime
|
self.lifetime = lifetime
|
||||||
self.pv_loss = pv_loss
|
self.loss = loss
|
||||||
|
def get_cost(self):
|
||||||
|
return self.capacity * self.cost_per_kW
|
||||||
|
def get_cost_per_year(self):
|
||||||
|
return self.capacity * self.cost_per_kW / self.lifetime
|
||||||
class ess_config:
|
class ess_config:
|
||||||
def __init__(self, capacity, cost_per_kW, ess_lifetime, ess_loss, charge_power, discharge_power):
|
def __init__(self, capacity, cost_per_kW, lifetime, loss, charge_power, discharge_power, storage=0):
|
||||||
self.capacity = capacity
|
self.capacity = capacity
|
||||||
self.cost_per_kW = cost_per_kW
|
self.cost_per_kW = cost_per_kW
|
||||||
self.ess_lifetime = ess_lifetime
|
self.lifetime = lifetime
|
||||||
self.ess_loss = ess_loss
|
self.loss = loss
|
||||||
self.ess_storage = 0
|
self.storage = storage
|
||||||
self.charge_power = charge_power
|
self.charge_power = charge_power
|
||||||
self.discharge_power = discharge_power
|
self.discharge_power = discharge_power
|
||||||
|
def get_cost(self):
|
||||||
|
return self.capacity * self.cost_per_kW
|
||||||
|
def get_cost_per_year(self):
|
||||||
|
return self.capacity * self.cost_per_kW / self.lifetime
|
||||||
|
|
||||||
class grid_config:
|
class grid_config:
|
||||||
def __init__(self, price_schedule, grid_loss):
|
def __init__(self, capacity, grid_loss, sell_price):
|
||||||
self.price_schedule = price_schedule
|
# self.price_schedule = price_schedule
|
||||||
|
self.loss = grid_loss
|
||||||
|
self.sell_price = sell_price
|
||||||
|
self.capacity = capacity
|
||||||
|
|
||||||
def get_price_for_time(self, time):
|
def get_price_for_time(self, time):
|
||||||
hour, minute = map(int, time.split(':'))
|
hour, minute = map(int, time.split(':'))
|
||||||
|
11
convert.py
Normal file
11
convert.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import nbformat
|
||||||
|
from nbconvert import PythonExporter
|
||||||
|
|
||||||
|
with open('main.ipynb', "r", encoding="utf-8") as f:
|
||||||
|
notebook = nbformat.read(f, as_version = 4)
|
||||||
|
|
||||||
|
exporter = PythonExporter()
|
||||||
|
python_code, _ = exporter.from_notebook_node(notebook)
|
||||||
|
|
||||||
|
with open('main.py', "w", encoding="utf-8") as f:
|
||||||
|
f.write(python_code)
|
209
draw.py
Normal file
209
draw.py
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import matplotlib.ticker as ticker
|
||||||
|
from matplotlib.ticker import FuncFormatter
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
import os
|
||||||
|
import seaborn as sns
|
||||||
|
import json
|
||||||
|
from matplotlib.colors import LinearSegmentedColormap
|
||||||
|
|
||||||
|
def read_data(file_name: str):
|
||||||
|
with open(file_name, 'r') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
for key, value in data.items():
|
||||||
|
for subkey, subvalue in value.items():
|
||||||
|
data[key][subkey] = float(subvalue)
|
||||||
|
df = pd.DataFrame.from_dict(data, orient='index')
|
||||||
|
df = df.T
|
||||||
|
df.index = pd.to_numeric(df.index)
|
||||||
|
df.columns = pd.to_numeric(df.columns)
|
||||||
|
return df
|
||||||
|
|
||||||
|
def draw_results(results, filename, title_benefit, annot_benefit=False, figure_size=(10, 10)):
|
||||||
|
df=results
|
||||||
|
df = df.astype(float)
|
||||||
|
df.index = df.index / 1000
|
||||||
|
df.index = df.index.map(int)
|
||||||
|
df.columns = df.columns / 1000
|
||||||
|
df.columns = df.columns.map(int)
|
||||||
|
min_value = df.min().min()
|
||||||
|
max_value = df.max().max()
|
||||||
|
max_scale = max(abs(min_value/1000), abs(max_value/1000))
|
||||||
|
|
||||||
|
df[df.columns[-1] + 1] = df.iloc[:, -1]
|
||||||
|
new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)
|
||||||
|
for i in df.columns:
|
||||||
|
new_Data[i] = df[i].iloc[-1]
|
||||||
|
df = pd.concat([df, new_Data])
|
||||||
|
|
||||||
|
X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))
|
||||||
|
|
||||||
|
def fmt(x,pos):
|
||||||
|
return '{:.0f}'.format(x/1000)
|
||||||
|
|
||||||
|
cmap = sns.color_palette("coolwarm", as_cmap=True)
|
||||||
|
plt.figure(figsize=figure_size)
|
||||||
|
ax = sns.heatmap(df/1000, fmt=".1f", cmap=cmap, vmin=-max_scale, vmax=max_scale, annot=annot_benefit)
|
||||||
|
CS = ax.contour(X, Y, df, colors='black', alpha=0.5)
|
||||||
|
ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))
|
||||||
|
plt.title(title_benefit)
|
||||||
|
plt.gca().invert_yaxis()
|
||||||
|
plt.xlim(0, df.shape[1] - 1)
|
||||||
|
plt.ylim(0, df.shape[0] - 1)
|
||||||
|
plt.xlabel('ESS Capacity (MWh)')
|
||||||
|
plt.ylabel('PV Capacity (MW)')
|
||||||
|
plt.savefig(filename)
|
||||||
|
|
||||||
|
def draw_cost(costs, filename, title_cost, annot_cost=False, figure_size=(10, 10)):
|
||||||
|
df = costs
|
||||||
|
df = df.astype(int)
|
||||||
|
df.index = df.index / 1000
|
||||||
|
df.index = df.index.map(int)
|
||||||
|
df.columns = df.columns / 1000
|
||||||
|
df.columns = df.columns.map(int)
|
||||||
|
|
||||||
|
df[df.columns[-1] + 1] = df.iloc[:, -1]
|
||||||
|
new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)
|
||||||
|
for i in df.columns:
|
||||||
|
new_Data[i] = df[i].iloc[-1]
|
||||||
|
df = pd.concat([df, new_Data])
|
||||||
|
X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))
|
||||||
|
|
||||||
|
def fmt(x, pos):
|
||||||
|
return '{:.0f}'.format(x / 1000000)
|
||||||
|
|
||||||
|
plt.figure(figsize=figure_size)
|
||||||
|
ax = sns.heatmap(df/1000000, fmt=".1f", cmap='viridis', annot=annot_cost)
|
||||||
|
CS = ax.contour(X, Y, df, colors='black', alpha=0.5)
|
||||||
|
ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))
|
||||||
|
plt.title(title_cost)
|
||||||
|
plt.gca().invert_yaxis()
|
||||||
|
plt.xlim(0, df.shape[1] - 1)
|
||||||
|
plt.ylim(0, df.shape[0] - 1)
|
||||||
|
plt.xlabel('ESS Capacity (MWh)')
|
||||||
|
plt.ylabel('PV Capacity (MW)')
|
||||||
|
plt.savefig(filename)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_overload(overload_cnt, filename, title_unmet, annot_unmet=False, figure_size=(10, 10)):
|
||||||
|
df = overload_cnt
|
||||||
|
df = (4 * 24 * 365 - df) / (4 * 24 * 365)
|
||||||
|
df = df.astype(float)
|
||||||
|
df.index = df.index / 1000
|
||||||
|
df.index = df.index.map(int)
|
||||||
|
df.columns = df.columns / 1000
|
||||||
|
df.columns = df.columns.map(int)
|
||||||
|
min_value = df.min().min()
|
||||||
|
max_value = df.max().max()
|
||||||
|
|
||||||
|
|
||||||
|
df[df.columns[-1] + 1] = df.iloc[:, -1]
|
||||||
|
new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)
|
||||||
|
for i in df.columns:
|
||||||
|
new_Data[i] = df[i].iloc[-1]
|
||||||
|
# print(new_Data)
|
||||||
|
df = pd.concat([df, new_Data])
|
||||||
|
|
||||||
|
|
||||||
|
plt.figure(figsize=figure_size)
|
||||||
|
cmap = LinearSegmentedColormap.from_list("", ["white", "blue"])
|
||||||
|
ax = sns.heatmap(df, fmt=".00%", cmap=cmap, vmin=0, vmax=1, annot=annot_unmet)
|
||||||
|
|
||||||
|
cbar = ax.collections[0].colorbar
|
||||||
|
cbar.set_ticks([0, 0.25, 0.5, 0.75, 1])
|
||||||
|
cbar.set_ticklabels(['0%', '25%', '50%', '75%', '100%'])
|
||||||
|
cbar.ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda x, pos: f'{x:.0%}'))
|
||||||
|
X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))
|
||||||
|
|
||||||
|
def fmt(x, pos):
|
||||||
|
return '{:.0f}%'.format(x * 100)
|
||||||
|
CS = ax.contour(X, Y, df, colors='black', alpha=0.5)
|
||||||
|
|
||||||
|
ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))
|
||||||
|
|
||||||
|
plt.xlim(0, df.shape[1] - 1)
|
||||||
|
plt.ylim(0, df.shape[0] - 1)
|
||||||
|
plt.title(title_unmet)
|
||||||
|
plt.xlabel('ESS Capacity (MWh)')
|
||||||
|
plt.ylabel('PV Capacity (MW)')
|
||||||
|
plt.savefig(filename)
|
||||||
|
|
||||||
|
with open('config.json', 'r') as f:
|
||||||
|
js_data = json.load(f)
|
||||||
|
|
||||||
|
data = pd.read_csv('combined_data.csv')
|
||||||
|
time_interval = js_data["time_interval"]["numerator"] / js_data["time_interval"]["denominator"]
|
||||||
|
|
||||||
|
pv_loss = js_data["pv"]["loss"]
|
||||||
|
pv_cost_per_kW = js_data["pv"]["cost_per_kW"]
|
||||||
|
pv_lifetime = js_data["pv"]["lifetime"]
|
||||||
|
|
||||||
|
ess_loss = js_data["ess"]["loss"]
|
||||||
|
ess_cost_per_kW = js_data["ess"]["cost_per_kW"]
|
||||||
|
ess_lifetime = js_data["ess"]["lifetime"]
|
||||||
|
|
||||||
|
grid_loss = js_data["grid"]["loss"]
|
||||||
|
sell_price = js_data["grid"]["sell_price"]
|
||||||
|
grid_capacity = js_data["grid"]["capacity"]
|
||||||
|
|
||||||
|
pv_begin = js_data["pv_capacities"]["begin"]
|
||||||
|
pv_end = js_data["pv_capacities"]["end"]
|
||||||
|
pv_groups = js_data["pv_capacities"]["groups"]
|
||||||
|
|
||||||
|
ess_begin = js_data["ess_capacities"]["begin"]
|
||||||
|
ess_end = js_data["ess_capacities"]["end"]
|
||||||
|
ess_groups = js_data["ess_capacities"]["groups"]
|
||||||
|
|
||||||
|
annot_unmet = js_data["annotated"]["unmet_prob"]
|
||||||
|
annot_benefit = js_data["annotated"]["benefit"]
|
||||||
|
annot_cost = js_data["annotated"]["cost"]
|
||||||
|
|
||||||
|
title_unmet = js_data["plot_title"]["unmet_prob"]
|
||||||
|
title_cost = js_data["plot_title"]["cost"]
|
||||||
|
title_benefit = js_data["plot_title"]["benefit"]
|
||||||
|
|
||||||
|
figure_size = (js_data["figure_size"]["length"], js_data["figure_size"]["height"])
|
||||||
|
|
||||||
|
directory = 'data/'
|
||||||
|
|
||||||
|
file_list = [f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f))]
|
||||||
|
|
||||||
|
|
||||||
|
split_files = [f.split('-') for f in file_list]
|
||||||
|
|
||||||
|
costs_files = [f for f in split_files if f[-1].endswith('costs.json')]
|
||||||
|
print(f'find costs files: {costs_files}')
|
||||||
|
overload_files = [f for f in split_files if f[-1].endswith('overload_cnt.json')]
|
||||||
|
print(f'find coverage/unmet files: {overload_files}')
|
||||||
|
results_files = [f for f in split_files if f[-1].endswith('results.json')]
|
||||||
|
print(f'find profit/benefit files: {results_files}')
|
||||||
|
|
||||||
|
costs_dfs = [read_data(directory + '-'.join(f)) for f in costs_files]
|
||||||
|
overload_dfs = [read_data(directory + '-'.join(f)) for f in overload_files]
|
||||||
|
results_dfs = [read_data(directory + '-'.join(f)) for f in results_files]
|
||||||
|
|
||||||
|
for costs_df, overload_df, results_df in zip(costs_dfs, overload_dfs, results_dfs):
|
||||||
|
|
||||||
|
draw_cost(costs_df,
|
||||||
|
f'plots/costs-ess-{int(costs_df.columns[0])}-{int(costs_df.columns[-1])}-pv-{int(costs_df.index[0])}-{int(costs_df.index[-1])}.png',
|
||||||
|
title_cost=title_cost,
|
||||||
|
annot_cost=annot_cost)
|
||||||
|
|
||||||
|
draw_overload(overload_df,
|
||||||
|
f'plots/overload-ess-{overload_df.columns[0]}-{overload_df.columns[-1]}-pv-{overload_df.index[0]}-{overload_df.index[-1]}.png',
|
||||||
|
title_unmet=title_unmet,
|
||||||
|
annot_unmet=False)
|
||||||
|
|
||||||
|
draw_results(results_df,
|
||||||
|
f'plots/results-ess-{results_df.columns[0]}-{results_df.columns[-1]}-pv-{results_df.index[0]}-{results_df.index[-1]}.png',
|
||||||
|
title_benefit=title_benefit,
|
||||||
|
annot_benefit=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
BIN
factory_power.xlsx
Normal file
BIN
factory_power.xlsx
Normal file
Binary file not shown.
BIN
factory_power1.xlsx
Normal file
BIN
factory_power1.xlsx
Normal file
Binary file not shown.
BIN
lightintensity.xlsx
Normal file
BIN
lightintensity.xlsx
Normal file
Binary file not shown.
813
main.ipynb
Normal file
813
main.ipynb
Normal file
File diff suppressed because one or more lines are too long
572
main.py
572
main.py
@@ -1 +1,571 @@
|
|||||||
import matplotlib
|
#!/usr/bin/env python
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# In[83]:
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import glob
|
||||||
|
import shutil
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import matplotlib.ticker as ticker
|
||||||
|
from matplotlib.ticker import FuncFormatter
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
import os
|
||||||
|
import seaborn as sns
|
||||||
|
import json
|
||||||
|
from matplotlib.colors import LinearSegmentedColormap
|
||||||
|
|
||||||
|
def clear_folder_make_ess_pv(folder_path):
|
||||||
|
if os.path.isdir(folder_path):
|
||||||
|
shutil.rmtree(folder_path)
|
||||||
|
os.makedirs(folder_path)
|
||||||
|
os.makedirs(os.path.join(folder_path,'ess'))
|
||||||
|
os.makedirs(os.path.join(folder_path,'pv'))
|
||||||
|
|
||||||
|
folder_path = 'plots'
|
||||||
|
clear_folder_make_ess_pv(folder_path)
|
||||||
|
|
||||||
|
|
||||||
|
# In[84]:
|
||||||
|
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import seaborn as sns
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
from EnergySystem import EnergySystem
|
||||||
|
from config import pv_config, grid_config, ess_config
|
||||||
|
|
||||||
|
|
||||||
|
# In[85]:
|
||||||
|
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
print("Version 0.0.7\n")
|
||||||
|
|
||||||
|
with open('config.json', 'r') as f:
|
||||||
|
js_data = json.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
time_interval = js_data["time_interval"]["numerator"] / js_data["time_interval"]["denominator"]
|
||||||
|
# print(time_interval)
|
||||||
|
|
||||||
|
pv_loss = js_data["pv"]["loss"]
|
||||||
|
pv_cost_per_kW = js_data["pv"]["cost_per_kW"]
|
||||||
|
pv_lifetime = js_data["pv"]["lifetime"]
|
||||||
|
|
||||||
|
ess_loss = js_data["ess"]["loss"]
|
||||||
|
ess_cost_per_kW = js_data["ess"]["cost_per_kW"]
|
||||||
|
ess_lifetime = js_data["ess"]["lifetime"]
|
||||||
|
|
||||||
|
grid_loss = js_data["grid"]["loss"]
|
||||||
|
sell_price = js_data["grid"]["sell_price"] #kWh
|
||||||
|
grid_capacity = js_data["grid"]["capacity"] #kWh
|
||||||
|
|
||||||
|
pv_begin = js_data["pv_capacities"]["begin"]
|
||||||
|
pv_end = js_data["pv_capacities"]["end"]
|
||||||
|
pv_groups = js_data["pv_capacities"]["groups"]
|
||||||
|
|
||||||
|
ess_begin = js_data["ess_capacities"]["begin"]
|
||||||
|
ess_end = js_data["ess_capacities"]["end"]
|
||||||
|
ess_groups = js_data["ess_capacities"]["groups"]
|
||||||
|
|
||||||
|
annot_unmet = js_data["annotated"]["unmet_prob"]
|
||||||
|
annot_benefit = js_data["annotated"]["benefit"]
|
||||||
|
annot_cost = js_data["annotated"]["cost"]
|
||||||
|
annot_roi = js_data["annotated"]["roi"]
|
||||||
|
|
||||||
|
title_unmet = js_data["plot_title"]["unmet_prob"]
|
||||||
|
title_cost = js_data["plot_title"]["cost"]
|
||||||
|
title_benefit = js_data["plot_title"]["benefit"]
|
||||||
|
title_roi = js_data["plot_title"]["roi"]
|
||||||
|
|
||||||
|
|
||||||
|
figure_size = (js_data["figure_size"]["length"], js_data["figure_size"]["height"])
|
||||||
|
|
||||||
|
data = pd.read_csv('combined_data.csv')
|
||||||
|
|
||||||
|
granularity = js_data["time_interval"]["numerator"]
|
||||||
|
|
||||||
|
months_days = [31,28,31,30,31,30,31,31,30,31,30,31]
|
||||||
|
def get_month_coe(num, granularity):
|
||||||
|
return 60 / granularity * 24 * months_days[num]
|
||||||
|
|
||||||
|
months_index = [get_month_coe(num, granularity) for num in range(12)]
|
||||||
|
months_data = []
|
||||||
|
for i in range(1,12):
|
||||||
|
months_index[i] += months_index[i-1]
|
||||||
|
for i in range(12):
|
||||||
|
start = 0 if i == 0 else months_index[i-1]
|
||||||
|
end = months_index[i]
|
||||||
|
months_data.append(data.iloc[int(start):int(end)])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pv_capacities = np.linspace(pv_begin, pv_end, pv_groups)
|
||||||
|
ess_capacities = np.linspace(ess_begin, ess_end, ess_groups)
|
||||||
|
# results = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
# affords = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
# costs = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
# overload_cnt = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
|
||||||
|
|
||||||
|
# In[86]:
|
||||||
|
|
||||||
|
|
||||||
|
hour_demand = []
|
||||||
|
for index, row in data.iterrows():
|
||||||
|
time = row['time']
|
||||||
|
demand = row['demand']
|
||||||
|
if time.endswith('00'):
|
||||||
|
hour_demand.append(demand)
|
||||||
|
plt.figure(figsize=(10,8))
|
||||||
|
plt.plot(hour_demand)
|
||||||
|
plt.ylabel('Demand Power / kW')
|
||||||
|
plt.savefig('plots/demand.png')
|
||||||
|
plt.close()
|
||||||
|
|
||||||
|
|
||||||
|
# In[87]:
|
||||||
|
|
||||||
|
|
||||||
|
def draw_results(results, filename, title_benefit, annot_benefit=False, figure_size=(10, 10)):
|
||||||
|
df=results
|
||||||
|
df = df.astype(float)
|
||||||
|
df.index = df.index / 1000
|
||||||
|
df.index = df.index.map(int)
|
||||||
|
df.columns = df.columns / 1000
|
||||||
|
df.columns = df.columns.map(int)
|
||||||
|
min_value = df.min().min()
|
||||||
|
max_value = df.max().max()
|
||||||
|
max_scale = max(abs(min_value/1000), abs(max_value/1000))
|
||||||
|
|
||||||
|
df[df.columns[-1] + 1] = df.iloc[:, -1]
|
||||||
|
new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)
|
||||||
|
for i in df.columns:
|
||||||
|
new_Data[i] = df[i].iloc[-1]
|
||||||
|
df = pd.concat([df, new_Data])
|
||||||
|
|
||||||
|
X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))
|
||||||
|
|
||||||
|
def fmt(x,pos):
|
||||||
|
return '{:.0f}'.format(x/1000)
|
||||||
|
|
||||||
|
cmap = sns.color_palette("coolwarm", as_cmap=True)
|
||||||
|
plt.figure(figsize=figure_size)
|
||||||
|
ax = sns.heatmap(df/1000, fmt=".1f", cmap=cmap, vmin=-max_scale, vmax=max_scale, annot=annot_benefit)
|
||||||
|
CS = ax.contour(X, Y, df, colors='black', alpha=0.5)
|
||||||
|
ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))
|
||||||
|
plt.title(title_benefit)
|
||||||
|
plt.gca().invert_yaxis()
|
||||||
|
plt.xlim(0, df.shape[1] - 1)
|
||||||
|
plt.ylim(0, df.shape[0] - 1)
|
||||||
|
plt.xlabel('ESS Capacity (MWh)')
|
||||||
|
plt.ylabel('PV Capacity (MW)')
|
||||||
|
plt.savefig(filename)
|
||||||
|
|
||||||
|
|
||||||
|
# In[88]:
|
||||||
|
|
||||||
|
|
||||||
|
def draw_roi(costs, results, filename, title_roi, days=365, annot_roi=False, figure_size=(10, 10)):
|
||||||
|
costs = costs.astype(float)
|
||||||
|
costs = costs / 365
|
||||||
|
costs = costs * days
|
||||||
|
|
||||||
|
df = results
|
||||||
|
df = costs / df
|
||||||
|
if 0 in df.index and 0 in df.columns:
|
||||||
|
df.loc[0,0] = 100
|
||||||
|
df[df > 80] = 100
|
||||||
|
# print(df)
|
||||||
|
|
||||||
|
df = df.astype(float)
|
||||||
|
df.index = df.index / 1000
|
||||||
|
df.index = df.index.map(int)
|
||||||
|
df.columns = df.columns / 1000
|
||||||
|
df.columns = df.columns.map(int)
|
||||||
|
min_value = df.min().min()
|
||||||
|
max_value = df.max().max()
|
||||||
|
# print(max_value)
|
||||||
|
max_scale = max(abs(min_value), abs(max_value))
|
||||||
|
|
||||||
|
df[df.columns[-1] + 1] = df.iloc[:, -1]
|
||||||
|
new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)
|
||||||
|
for i in df.columns:
|
||||||
|
new_Data[i] = df[i].iloc[-1]
|
||||||
|
df = pd.concat([df, new_Data])
|
||||||
|
|
||||||
|
X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))
|
||||||
|
|
||||||
|
def fmt(x,pos):
|
||||||
|
return '{:.0f}'.format(x)
|
||||||
|
|
||||||
|
cmap = sns.color_palette("Greys", as_cmap=True)
|
||||||
|
plt.figure(figsize=figure_size)
|
||||||
|
ax = sns.heatmap(df, fmt=".1f", cmap=cmap, vmin=0, vmax=100, annot=annot_benefit)
|
||||||
|
CS = ax.contour(X, Y, df, colors='black', alpha=0.5)
|
||||||
|
ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))
|
||||||
|
plt.title(title_roi)
|
||||||
|
plt.gca().invert_yaxis()
|
||||||
|
plt.xlim(0, df.shape[1] - 1)
|
||||||
|
plt.ylim(0, df.shape[0] - 1)
|
||||||
|
plt.xlabel('ESS Capacity (MWh)')
|
||||||
|
plt.ylabel('PV Capacity (MW)')
|
||||||
|
plt.savefig(filename)
|
||||||
|
plt.close()
|
||||||
|
|
||||||
|
|
||||||
|
# In[89]:
|
||||||
|
|
||||||
|
|
||||||
|
def draw_cost(costs, filename, title_cost, annot_cost=False, figure_size=(10, 10)):
|
||||||
|
df = costs
|
||||||
|
df = df.astype(int)
|
||||||
|
df.index = df.index / 1000
|
||||||
|
df.index = df.index.map(int)
|
||||||
|
df.columns = df.columns / 1000
|
||||||
|
df.columns = df.columns.map(int)
|
||||||
|
|
||||||
|
df[df.columns[-1] + 1] = df.iloc[:, -1]
|
||||||
|
new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)
|
||||||
|
for i in df.columns:
|
||||||
|
new_Data[i] = df[i].iloc[-1]
|
||||||
|
df = pd.concat([df, new_Data])
|
||||||
|
X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))
|
||||||
|
|
||||||
|
def fmt(x, pos):
|
||||||
|
return '{:.0f}'.format(x / 1000000)
|
||||||
|
|
||||||
|
plt.figure(figsize=figure_size)
|
||||||
|
ax = sns.heatmap(df/1000000, fmt=".1f", cmap='viridis', annot=annot_cost)
|
||||||
|
CS = ax.contour(X, Y, df, colors='black', alpha=0.5)
|
||||||
|
ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))
|
||||||
|
plt.title(title_cost)
|
||||||
|
plt.gca().invert_yaxis()
|
||||||
|
plt.xlim(0, df.shape[1] - 1)
|
||||||
|
plt.ylim(0, df.shape[0] - 1)
|
||||||
|
plt.xlabel('ESS Capacity (MWh)')
|
||||||
|
plt.ylabel('PV Capacity (MW)')
|
||||||
|
plt.savefig(filename)
|
||||||
|
plt.close()
|
||||||
|
|
||||||
|
|
||||||
|
# In[90]:
|
||||||
|
|
||||||
|
|
||||||
|
def draw_overload(overload_cnt, filename, title_unmet, annot_unmet=False, figure_size=(10, 10), days=365, granularity=15):
|
||||||
|
df = overload_cnt
|
||||||
|
# print(days, granularity)
|
||||||
|
coef = 60 / granularity * days * 24
|
||||||
|
# print(coef)
|
||||||
|
# print(df)
|
||||||
|
df = ( coef - df) / coef
|
||||||
|
# print(df)
|
||||||
|
|
||||||
|
df = df.astype(float)
|
||||||
|
df.index = df.index / 1000
|
||||||
|
df.index = df.index.map(int)
|
||||||
|
df.columns = df.columns / 1000
|
||||||
|
df.columns = df.columns.map(int)
|
||||||
|
|
||||||
|
|
||||||
|
df[df.columns[-1] + 1] = df.iloc[:, -1]
|
||||||
|
new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)
|
||||||
|
for i in df.columns:
|
||||||
|
new_Data[i] = df[i].iloc[-1]
|
||||||
|
# print(new_Data)
|
||||||
|
df = pd.concat([df, new_Data])
|
||||||
|
|
||||||
|
|
||||||
|
plt.figure(figsize=figure_size)
|
||||||
|
cmap = LinearSegmentedColormap.from_list("", ["white", "blue"])
|
||||||
|
ax = sns.heatmap(df, fmt=".00%", cmap=cmap, vmin=0, vmax=1, annot=annot_unmet)
|
||||||
|
|
||||||
|
cbar = ax.collections[0].colorbar
|
||||||
|
cbar.set_ticks([0, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1])
|
||||||
|
cbar.set_ticklabels(['0%', '10%', '20%', '30%', '40%', '50%', '60%', '70%', '80%', '90%', '100%'])
|
||||||
|
cbar.ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda x, pos: f'{x:.0%}'))
|
||||||
|
X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))
|
||||||
|
|
||||||
|
def fmt(x, pos):
|
||||||
|
return '{:.0f}%'.format(x * 100)
|
||||||
|
CS = ax.contour(X, Y, df, colors='black', alpha=0.5)
|
||||||
|
|
||||||
|
ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))
|
||||||
|
|
||||||
|
plt.xlim(0, df.shape[1] - 1)
|
||||||
|
plt.ylim(0, df.shape[0] - 1)
|
||||||
|
plt.title(title_unmet)
|
||||||
|
plt.xlabel('ESS Capacity (MWh)')
|
||||||
|
plt.ylabel('PV Capacity (MW)')
|
||||||
|
plt.savefig(filename)
|
||||||
|
plt.close()
|
||||||
|
|
||||||
|
|
||||||
|
# In[91]:
|
||||||
|
|
||||||
|
|
||||||
|
def cal_profit(es: EnergySystem, saved_money, days):
|
||||||
|
profit = saved_money - es.ess.get_cost_per_year() / 365 * days - es.pv.get_cost_per_year() / 365 * days
|
||||||
|
return profit
|
||||||
|
|
||||||
|
|
||||||
|
# In[92]:
|
||||||
|
|
||||||
|
|
||||||
|
def generate_data(pv_capacity, pv_cost_per_kW, pv_lifetime, pv_loss, ess_capacity, ess_cost_per_kW, ess_lifetime, ess_loss, grid_capacity, grid_loss, sell_price, time_interval, data, days, storage=0):
|
||||||
|
pv = pv_config(capacity=pv_capacity,
|
||||||
|
cost_per_kW=pv_cost_per_kW,
|
||||||
|
lifetime=pv_lifetime,
|
||||||
|
loss=pv_loss)
|
||||||
|
ess = ess_config(capacity=ess_capacity,
|
||||||
|
cost_per_kW=ess_cost_per_kW,
|
||||||
|
lifetime=ess_lifetime,
|
||||||
|
loss=ess_loss,
|
||||||
|
charge_power=ess_capacity,
|
||||||
|
discharge_power=ess_capacity,
|
||||||
|
storage=storage)
|
||||||
|
grid = grid_config(capacity=grid_capacity,
|
||||||
|
grid_loss=grid_loss,
|
||||||
|
sell_price= sell_price)
|
||||||
|
energySystem = EnergySystem(pv_type=pv,
|
||||||
|
ess_type=ess,
|
||||||
|
grid_type= grid)
|
||||||
|
(benefit, netto_benefit, gen_energy) = energySystem.simulate(data, time_interval)
|
||||||
|
results = cal_profit(energySystem, benefit, days)
|
||||||
|
overload_cnt = energySystem.overload_cnt
|
||||||
|
costs = energySystem.ess.capacity * energySystem.ess.cost_per_kW + energySystem.pv.capacity * energySystem.pv.cost_per_kW
|
||||||
|
return (results,
|
||||||
|
overload_cnt,
|
||||||
|
costs,
|
||||||
|
netto_benefit,
|
||||||
|
gen_energy,
|
||||||
|
energySystem.generated,
|
||||||
|
energySystem.ess_rest,
|
||||||
|
energySystem.factory_demand,
|
||||||
|
energySystem.buy_price_kWh,
|
||||||
|
energySystem.sell_price_kWh,
|
||||||
|
energySystem.pv_generated_kWh,
|
||||||
|
energySystem.grid_need_power_kW,
|
||||||
|
energySystem.time)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# In[93]:
|
||||||
|
|
||||||
|
|
||||||
|
from tqdm import tqdm
|
||||||
|
months_results = []
|
||||||
|
months_costs = []
|
||||||
|
months_overload = []
|
||||||
|
months_nettos = []
|
||||||
|
months_gen_energy = []
|
||||||
|
months_gen_energy2 = []
|
||||||
|
months_ess_rest = pd.DataFrame(30, index=pv_capacities, columns= ess_capacities)
|
||||||
|
months_csv_data = {}
|
||||||
|
for index, month_data in tqdm(enumerate(months_data), total=len(months_data), position=0, leave= True):
|
||||||
|
results = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
costs = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
overload_cnt = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
nettos = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
gen_energies = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
gen_energies2 = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
factory_demands = {}
|
||||||
|
buy_prices= {}
|
||||||
|
sell_prices = {}
|
||||||
|
pv_generates = {}
|
||||||
|
grid_need_powers = {}
|
||||||
|
times = {}
|
||||||
|
for pv_capacity in tqdm(pv_capacities, total=len(pv_capacities), desc=f'generating pv for month {index + 1}',position=1, leave=False):
|
||||||
|
factory_demands[pv_capacity] = {}
|
||||||
|
buy_prices[pv_capacity] = {}
|
||||||
|
sell_prices[pv_capacity] = {}
|
||||||
|
pv_generates[pv_capacity] = {}
|
||||||
|
grid_need_powers[pv_capacity] = {}
|
||||||
|
times[pv_capacity] = {}
|
||||||
|
for ess_capacity in ess_capacities:
|
||||||
|
(result,
|
||||||
|
overload,
|
||||||
|
cost,
|
||||||
|
netto,
|
||||||
|
gen_energy,
|
||||||
|
gen_energy2,
|
||||||
|
ess_rest,
|
||||||
|
factory_demand,
|
||||||
|
buy_price,
|
||||||
|
sell_price,
|
||||||
|
pv_generate,
|
||||||
|
grid_need_power,
|
||||||
|
time) = generate_data(pv_capacity=pv_capacity,
|
||||||
|
pv_cost_per_kW=pv_cost_per_kW,
|
||||||
|
pv_lifetime=pv_lifetime,
|
||||||
|
pv_loss=pv_loss,
|
||||||
|
ess_capacity=ess_capacity,
|
||||||
|
ess_cost_per_kW=ess_cost_per_kW,
|
||||||
|
ess_lifetime=ess_lifetime,
|
||||||
|
ess_loss=ess_loss,
|
||||||
|
grid_capacity=grid_capacity,
|
||||||
|
grid_loss=grid_loss,
|
||||||
|
sell_price=sell_price,
|
||||||
|
time_interval=time_interval,
|
||||||
|
data=month_data,
|
||||||
|
days=months_days[index],
|
||||||
|
storage=months_ess_rest.loc[pv_capacity, ess_capacity])
|
||||||
|
results.loc[pv_capacity,ess_capacity] = result
|
||||||
|
overload_cnt.loc[pv_capacity,ess_capacity] = overload
|
||||||
|
costs.loc[pv_capacity,ess_capacity] = cost
|
||||||
|
nettos.loc[pv_capacity,ess_capacity] = netto
|
||||||
|
gen_energies.loc[pv_capacity, ess_capacity] = gen_energy
|
||||||
|
gen_energies2.loc[pv_capacity, ess_capacity] = gen_energy2
|
||||||
|
months_ess_rest.loc[pv_capacity, ess_capacity] = ess_rest
|
||||||
|
factory_demands[pv_capacity][ess_capacity] = factory_demand
|
||||||
|
buy_prices[pv_capacity][ess_capacity] = buy_price
|
||||||
|
sell_prices[pv_capacity][ess_capacity] = sell_price
|
||||||
|
pv_generates[pv_capacity][ess_capacity] = pv_generate
|
||||||
|
grid_need_powers[pv_capacity][ess_capacity] = grid_need_power
|
||||||
|
times[pv_capacity][ess_capacity] = time
|
||||||
|
months_csv_data[index] = {"factory_demand": factory_demands, "buy_price": buy_prices, "sell_price": sell_prices, "pv_generate": pv_generates, "grid_need_power": grid_need_powers, "time": times}
|
||||||
|
months_results.append(results)
|
||||||
|
months_costs.append(costs)
|
||||||
|
months_overload.append(overload_cnt)
|
||||||
|
months_nettos.append(nettos)
|
||||||
|
months_gen_energy.append(gen_energies)
|
||||||
|
months_gen_energy2.append(gen_energies2)
|
||||||
|
draw_results(results=results,
|
||||||
|
filename=f'plots/pv-{pv_capacity}-ess-{ess_capacity}-month-{index+1}-benefit.png',
|
||||||
|
title_benefit=title_benefit,
|
||||||
|
annot_benefit=annot_benefit,
|
||||||
|
figure_size=figure_size)
|
||||||
|
draw_overload(overload_cnt=overload_cnt,
|
||||||
|
filename=f'plots/pv-{pv_capacity}-ess-{ess_capacity}-month-{index+1}-unmet.png',
|
||||||
|
title_unmet=title_unmet,
|
||||||
|
annot_unmet=annot_unmet,
|
||||||
|
figure_size=figure_size,
|
||||||
|
days=months_days[index],
|
||||||
|
granularity=granularity)
|
||||||
|
annual_result = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
annual_costs = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
annual_overload = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
annual_nettos = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
annual_gen = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
annual_gen2 = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
|
||||||
|
|
||||||
|
# get the yearly results
|
||||||
|
for pv_capacity in pv_capacities:
|
||||||
|
for ess_capacity in ess_capacities:
|
||||||
|
results = 0
|
||||||
|
costs = 0
|
||||||
|
overload_cnt = 0
|
||||||
|
nettos = 0
|
||||||
|
gen = 0
|
||||||
|
gen2 = 0
|
||||||
|
for index, month_data in enumerate(months_data):
|
||||||
|
results += months_results[index].loc[pv_capacity,ess_capacity]
|
||||||
|
costs += months_costs[index].loc[pv_capacity,ess_capacity]
|
||||||
|
overload_cnt += months_overload[index].loc[pv_capacity, ess_capacity]
|
||||||
|
nettos += months_nettos[index].loc[pv_capacity, ess_capacity]
|
||||||
|
gen += months_gen_energy[index].loc[pv_capacity, ess_capacity]
|
||||||
|
gen2 += months_gen_energy[index].loc[pv_capacity, ess_capacity]
|
||||||
|
annual_result.loc[pv_capacity, ess_capacity] = results
|
||||||
|
annual_costs.loc[pv_capacity, ess_capacity] = costs
|
||||||
|
annual_overload.loc[pv_capacity, ess_capacity] = overload_cnt
|
||||||
|
annual_nettos.loc[pv_capacity, ess_capacity] = nettos
|
||||||
|
annual_gen.loc[pv_capacity, ess_capacity] = gen
|
||||||
|
annual_gen2.loc[pv_capacity, ess_capacity] = gen2
|
||||||
|
|
||||||
|
draw_cost(costs=annual_costs,
|
||||||
|
filename='plots/annual_cost.png',
|
||||||
|
title_cost=title_cost,
|
||||||
|
annot_cost=annot_cost,
|
||||||
|
figure_size=figure_size)
|
||||||
|
draw_results(results=annual_result,
|
||||||
|
filename='plots/annual_benefit.png',
|
||||||
|
title_benefit=title_benefit,
|
||||||
|
annot_benefit=annot_benefit,
|
||||||
|
figure_size=figure_size)
|
||||||
|
draw_overload(overload_cnt=annual_overload,
|
||||||
|
filename='plots/annual_unmet.png',
|
||||||
|
title_unmet=title_unmet,
|
||||||
|
annot_unmet=annot_unmet,
|
||||||
|
figure_size=figure_size)
|
||||||
|
|
||||||
|
|
||||||
|
# In[94]:
|
||||||
|
|
||||||
|
|
||||||
|
def collapse_months_csv_data(months_csv_data, column_name,pv_capacies, ess_capacities):
|
||||||
|
data = {}
|
||||||
|
for pv_capacity in pv_capacities:
|
||||||
|
data[pv_capacity] = {}
|
||||||
|
for ess_capacity in ess_capacities:
|
||||||
|
annual_data = []
|
||||||
|
for index, month_data in enumerate(months_data):
|
||||||
|
annual_data.extend(months_csv_data[index][column_name][pv_capacity][ess_capacity])
|
||||||
|
# months_csv_data[index][column_name][pv_capacity][ess_capacity] = months_csv_data[index][column_name][pv_capacity][ess_capacity].tolist()
|
||||||
|
|
||||||
|
data[pv_capacity][ess_capacity] = annual_data
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
# In[102]:
|
||||||
|
|
||||||
|
|
||||||
|
annual_pv_gen = collapse_months_csv_data(months_csv_data, "pv_generate", pv_capacities, ess_capacities)
|
||||||
|
annual_time = collapse_months_csv_data(months_csv_data, "time", pv_capacities, ess_capacities)
|
||||||
|
annual_buy_price = collapse_months_csv_data(months_csv_data, "buy_price",pv_capacities, ess_capacities)
|
||||||
|
annual_sell_price = collapse_months_csv_data(months_csv_data, "sell_price", pv_capacities, ess_capacities)
|
||||||
|
annual_factory_demand = collapse_months_csv_data(months_csv_data, "factory_demand", pv_capacities, ess_capacities)
|
||||||
|
annual_grid_need_power = collapse_months_csv_data(months_csv_data, "grid_need_power", pv_capacities, ess_capacities)
|
||||||
|
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
for pv_capacity in pv_capacities:
|
||||||
|
for ess_capacity in ess_capacities:
|
||||||
|
with open(f'data/annual_data-pv-{pv_capacity}-ess-{ess_capacity}.csv', 'w') as f:
|
||||||
|
f.write("date, time,pv_generate (kW),factory_demand (kW),buy_price (USD/MWh),sell_price (USD/MWh),grid_need_power (kW)\n")
|
||||||
|
start_date = datetime(2023, 1, 1, 0, 0, 0)
|
||||||
|
for i in range(len(annual_time[pv_capacity][ess_capacity])):
|
||||||
|
current_date = start_date + timedelta(hours=i)
|
||||||
|
formate_date = current_date.strftime("%Y-%m-%d")
|
||||||
|
f.write(f"{formate_date},{annual_time[pv_capacity][ess_capacity][i]},{int(annual_pv_gen[pv_capacity][ess_capacity][i])},{int(annual_factory_demand[pv_capacity][ess_capacity][i])},{int(annual_buy_price[pv_capacity][ess_capacity][i]*1000)},{int(annual_sell_price[pv_capacity][ess_capacity][i]*1000)},{int(annual_grid_need_power[pv_capacity][ess_capacity][i])} \n")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# In[96]:
|
||||||
|
|
||||||
|
|
||||||
|
def save_data(data, filename):
|
||||||
|
data.to_csv(filename+'.csv')
|
||||||
|
data.to_json(filename + '.json')
|
||||||
|
|
||||||
|
|
||||||
|
# In[97]:
|
||||||
|
|
||||||
|
|
||||||
|
if not os.path.isdir('data'):
|
||||||
|
os.makedirs('data')
|
||||||
|
|
||||||
|
save_data(annual_result, f'data/{pv_begin}-{pv_end}-{pv_groups}-{ess_begin}-{ess_end}-{ess_groups}-results')
|
||||||
|
save_data(annual_costs, f'data/{pv_begin}-{pv_end}-{pv_groups}-{ess_begin}-{ess_end}-{ess_groups}-costs')
|
||||||
|
save_data(annual_overload, f'data/{pv_begin}-{pv_end}-{pv_groups}-{ess_begin}-{ess_end}-{ess_groups}-overload_cnt')
|
||||||
|
|
||||||
|
|
||||||
|
# In[98]:
|
||||||
|
|
||||||
|
|
||||||
|
draw_results(annual_result, 'plots/test.png', 'test', False)
|
||||||
|
|
||||||
|
|
||||||
|
# In[99]:
|
||||||
|
|
||||||
|
|
||||||
|
draw_roi(annual_costs, annual_nettos, 'plots/annual_roi.png', title_roi, 365, annot_benefit, figure_size)
|
||||||
|
|
||||||
|
19
old/generate_electricity_price.py
Normal file
19
old/generate_electricity_price.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
start_date = '2023-01-01'
|
||||||
|
end_date = '2024-01-01'
|
||||||
|
|
||||||
|
# 创建时间索引
|
||||||
|
time_index = pd.date_range(start=start_date, end=end_date, freq='15min')
|
||||||
|
|
||||||
|
# 生成电价数据,假设电价在0.28到0.32欧元/kWh之间波动
|
||||||
|
price_data = np.random.uniform(0.28, 0.32, len(time_index))
|
||||||
|
|
||||||
|
# 创建DataFrame
|
||||||
|
price_df = pd.DataFrame(data={'Time': time_index, 'ElectricityPrice': price_data})
|
||||||
|
|
||||||
|
# 保存到CSV文件
|
||||||
|
price_df.to_csv('electricity_price_data.csv', index=False)
|
||||||
|
|
||||||
|
print("Electricity price data generated and saved.")
|
56
old/generatedata.py
Normal file
56
old/generatedata.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
# 设置随机种子以重现结果
|
||||||
|
np.random.seed(43)
|
||||||
|
|
||||||
|
def simulate_sunlight(hour, month):
|
||||||
|
# 假设最大日照强度在正午,根据月份调整最大日照强度
|
||||||
|
max_intensity = 1.0 # 夏季最大日照强度
|
||||||
|
if month in [12, 1, 2]: # 冬季
|
||||||
|
max_intensity = 0.6
|
||||||
|
elif month in [3, 4, 10, 11]: # 春秋
|
||||||
|
max_intensity = 0.8
|
||||||
|
|
||||||
|
# 计算日照强度,模拟早晚日照弱,中午日照强
|
||||||
|
intensity = max_intensity * np.sin(np.pi * (hour - 6) / 12)**2 if 6 <= hour <= 18 else 0
|
||||||
|
return intensity
|
||||||
|
|
||||||
|
def simulate_factory_demand(hour, day_of_week):
|
||||||
|
# 周末工厂需求可能减少
|
||||||
|
if day_of_week in [5, 6]: # 周六和周日
|
||||||
|
base_demand = 3000
|
||||||
|
else:
|
||||||
|
base_demand = 6000
|
||||||
|
|
||||||
|
# 日常波动
|
||||||
|
if 8 <= hour <= 20:
|
||||||
|
return base_demand + np.random.randint(100, 200) # 白天需求量大
|
||||||
|
else:
|
||||||
|
return base_demand - np.random.randint(0, 100) # 夜间需求量小
|
||||||
|
|
||||||
|
def generate_data(days=10):
|
||||||
|
records = []
|
||||||
|
month_demand = 0
|
||||||
|
for day in range(days):
|
||||||
|
month = (day % 365) // 30 + 1
|
||||||
|
day_of_week = day % 7
|
||||||
|
day_demand = 0
|
||||||
|
for hour in range(24):
|
||||||
|
for minute in [0, 10, 20, 30, 40, 50]:
|
||||||
|
time = f'{hour:02d}:{minute:02d}'
|
||||||
|
sunlight = simulate_sunlight(hour, month)
|
||||||
|
demand = simulate_factory_demand(hour, day_of_week)
|
||||||
|
day_demand+=demand
|
||||||
|
records.append({'time': time, 'sunlight': sunlight, 'demand': demand})
|
||||||
|
print(f"day:{day}, day_demand: {day_demand}")
|
||||||
|
month_demand += day_demand
|
||||||
|
if day%30 == 0:
|
||||||
|
print(f"month:{month}, month_demand:{month_demand}")
|
||||||
|
month_demand = 0
|
||||||
|
return pd.DataFrame(records)
|
||||||
|
|
||||||
|
# 生成数据
|
||||||
|
data = generate_data(365) # 模拟一年的数据
|
||||||
|
data.to_csv('simulation_data.csv', index=False)
|
||||||
|
print("Data generated and saved to simulation_data.csv.")
|
24
old/generatepriceschedule.py
Normal file
24
old/generatepriceschedule.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
def generate_price_schedule():
|
||||||
|
records = []
|
||||||
|
# 假设一天分为三个时段:谷时、平时、峰时
|
||||||
|
times = [('00:00', '06:00', 0.25),
|
||||||
|
('06:00', '18:00', 0.3),
|
||||||
|
('18:00', '24:00', 0.35)]
|
||||||
|
|
||||||
|
# 随机调整每天的电价以增加现实性
|
||||||
|
for time_start, time_end, base_price in times:
|
||||||
|
# 随机浮动5%以内
|
||||||
|
fluctuation = np.random.uniform(-0.005, 0.005)
|
||||||
|
price = round(base_price + fluctuation, 3)
|
||||||
|
records.append({'time_start': time_start, 'time_end': time_end, 'price': price})
|
||||||
|
|
||||||
|
return pd.DataFrame(records)
|
||||||
|
|
||||||
|
# 生成电价计划
|
||||||
|
price_schedule = generate_price_schedule()
|
||||||
|
price_schedule.to_csv('price_schedule.csv', index=False)
|
||||||
|
print("Price schedule generated and saved to price_schedule.csv.")
|
||||||
|
print(price_schedule)
|
4
old/price_schedule.csv
Normal file
4
old/price_schedule.csv
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
time_start,time_end,price
|
||||||
|
00:00,06:00,0.247
|
||||||
|
06:00,18:00,0.3
|
||||||
|
18:00,24:00,0.349
|
|
52561
old/simulation_data.csv
Normal file
52561
old/simulation_data.csv
Normal file
File diff suppressed because it is too large
Load Diff
47
read_data.py
Normal file
47
read_data.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
import csv
|
||||||
|
import json
|
||||||
|
|
||||||
|
with open('config.json', 'r') as f:
|
||||||
|
js_data = json.load(f)
|
||||||
|
|
||||||
|
pv_yield_file_name = js_data["data_path"]["pv_yield"]
|
||||||
|
print(pv_yield_file_name)
|
||||||
|
# factory_demand_file_name = 'factory_power1.xlsx'
|
||||||
|
factory_demand_file_name = js_data["data_path"]["demand"]
|
||||||
|
print(factory_demand_file_name)
|
||||||
|
electricity_price_data = js_data["data_path"]["buy"]
|
||||||
|
print(electricity_price_data)
|
||||||
|
electricity_price_data_sell = js_data["data_path"]["sell"]
|
||||||
|
print(electricity_price_data_sell)
|
||||||
|
|
||||||
|
pv_df = pd.read_csv(pv_yield_file_name, index_col='Time', usecols=['Time', 'PV yield[kW/kWp]'])
|
||||||
|
pv_df.index = pd.to_datetime(pv_df.index)
|
||||||
|
|
||||||
|
df_power = pd.read_csv(factory_demand_file_name, index_col='Time', usecols=['Time', 'FactoryPower'])
|
||||||
|
df_power.index = pd.to_datetime(df_power.index)
|
||||||
|
df_combined = pv_df.join(df_power)
|
||||||
|
|
||||||
|
price_df = pd.read_csv(electricity_price_data, index_col='Time', usecols=['Time', 'ElectricityBuy'])
|
||||||
|
price_df.index = pd.to_datetime(price_df.index)
|
||||||
|
price_df = price_df.reindex(df_combined.index)
|
||||||
|
df_combined2 = df_combined.join(price_df)
|
||||||
|
|
||||||
|
sell_df = pd.read_csv(electricity_price_data_sell, index_col='Time', usecols=['Time', 'ElectricitySell'])
|
||||||
|
sell_df.index = pd.to_datetime(sell_df.index)
|
||||||
|
sell_df = sell_df.reindex(df_combined.index)
|
||||||
|
df_combined3 = df_combined2.join(sell_df)
|
||||||
|
|
||||||
|
with open('combined_data.csv', 'w', newline='') as file:
|
||||||
|
writer = csv.writer(file)
|
||||||
|
writer.writerow(['time', 'PV yield[kW/kWp]', 'demand','buy', 'sell'])
|
||||||
|
cnt = 0
|
||||||
|
for index, row in df_combined3.iterrows():
|
||||||
|
time_formatted = index.strftime('%H:%M')
|
||||||
|
writer.writerow([time_formatted, row['PV yield[kW/kWp]'], row['FactoryPower'],row['ElectricityBuy'], row['ElectricitySell']])
|
||||||
|
|
||||||
|
print('The file is written to combined_data.csv')
|
||||||
|
|
||||||
|
|
||||||
|
print("Simulation data with electricity prices has been updated and saved.")
|
35041
read_data/Berlin.csv
Normal file
35041
read_data/Berlin.csv
Normal file
File diff suppressed because it is too large
Load Diff
35041
read_data/Cambodge.csv
Normal file
35041
read_data/Cambodge.csv
Normal file
File diff suppressed because it is too large
Load Diff
35041
read_data/Marcedonia.csv
Normal file
35041
read_data/Marcedonia.csv
Normal file
File diff suppressed because it is too large
Load Diff
35041
read_data/Riyahd.csv
Normal file
35041
read_data/Riyahd.csv
Normal file
File diff suppressed because it is too large
Load Diff
35041
read_data/Serbia.csv
Normal file
35041
read_data/Serbia.csv
Normal file
File diff suppressed because it is too large
Load Diff
372
read_data/convert_data.ipynb
Normal file
372
read_data/convert_data.ipynb
Normal file
@@ -0,0 +1,372 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 85,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import matplotlib.pyplot as plt\n",
|
||||||
|
"import pandas as pd\n",
|
||||||
|
"import numpy as np\n",
|
||||||
|
"import os\n",
|
||||||
|
"import csv"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 86,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def read_csv(filename):\n",
|
||||||
|
" skip_rows = list(range(1, 17))\n",
|
||||||
|
" data = pd.read_csv(filename, sep=';', skiprows=skip_rows)\n",
|
||||||
|
" return data"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 87,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stderr",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"/tmp/ipykernel_3075037/3659192646.py:3: DtypeWarning: Columns (32,33,35) have mixed types. Specify dtype option on import or set low_memory=False.\n",
|
||||||
|
" data = pd.read_csv(filename, sep=';', skiprows=skip_rows)\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"Index(['Time', 'Irradiance onto horizontal plane ',\n",
|
||||||
|
" 'Diffuse Irradiation onto Horizontal Plane ', 'Outside Temperature ',\n",
|
||||||
|
" 'Module Area 1: Height of Sun ',\n",
|
||||||
|
" 'Module Area 1: Irradiance onto tilted surface ',\n",
|
||||||
|
" 'Module Area 1: Module Temperature ', 'Grid Export ',\n",
|
||||||
|
" 'Energy from Grid ', 'Global radiation - horizontal ',\n",
|
||||||
|
" 'Deviation from standard spectrum ', 'Ground Reflection (Albedo) ',\n",
|
||||||
|
" 'Orientation and inclination of the module surface ', 'Shading ',\n",
|
||||||
|
" 'Reflection on the Module Surface ',\n",
|
||||||
|
" 'Irradiance on the rear side of the module ',\n",
|
||||||
|
" 'Global Radiation at the Module ',\n",
|
||||||
|
" 'Module Area 1: Reflection on the Module Surface ',\n",
|
||||||
|
" 'Module Area 1: Global Radiation at the Module ',\n",
|
||||||
|
" 'Global PV Radiation ', 'Bifaciality ', 'Soiling ',\n",
|
||||||
|
" 'STC Conversion (Rated Efficiency of Module) ', 'Rated PV Energy ',\n",
|
||||||
|
" 'Low-light performance ', 'Module-specific Partial Shading ',\n",
|
||||||
|
" 'Deviation from the nominal module temperature ', 'Diodes ',\n",
|
||||||
|
" 'Mismatch (Manufacturer Information) ',\n",
|
||||||
|
" 'Mismatch (Configuration/Shading) ',\n",
|
||||||
|
" 'Power optimizer (DC conversion/clipping) ',\n",
|
||||||
|
" 'PV Energy (DC) without inverter clipping ',\n",
|
||||||
|
" 'Failing to reach the DC start output ',\n",
|
||||||
|
" 'Clipping on account of the MPP Voltage Range ',\n",
|
||||||
|
" 'Clipping on account of the max. DC Current ',\n",
|
||||||
|
" 'Clipping on account of the max. DC Power ',\n",
|
||||||
|
" 'Clipping on account of the max. AC Power/cos phi ', 'MPP Matching ',\n",
|
||||||
|
" 'PV energy (DC) ',\n",
|
||||||
|
" 'Inverter 1 - MPP 1 - to Module Area 1: PV energy (DC) ',\n",
|
||||||
|
" 'Inverter 1 - MPP 2 - to Module Area 1: PV energy (DC) ',\n",
|
||||||
|
" 'Inverter 1 - MPP 3 - to Module Area 1: PV energy (DC) ',\n",
|
||||||
|
" 'Inverter 1 - MPP 4 - to Module Area 1: PV energy (DC) ',\n",
|
||||||
|
" 'Inverter 1 - MPP 5 - to Module Area 1: PV energy (DC) ',\n",
|
||||||
|
" 'Inverter 1 - MPP 6 - to Module Area 1: PV energy (DC) ',\n",
|
||||||
|
" 'Inverter 2 - MPP 1 - to Module Area 1: PV energy (DC) ',\n",
|
||||||
|
" 'Inverter 2 - MPP 2 - to Module Area 1: PV energy (DC) ',\n",
|
||||||
|
" 'Energy at the Inverter Input ',\n",
|
||||||
|
" 'Input voltage deviates from rated voltage ', 'DC/AC Conversion ',\n",
|
||||||
|
" 'Own Consumption (Standby or Night) ', 'Total Cable Losses ',\n",
|
||||||
|
" 'PV energy (AC) minus standby use ', 'Feed-in energy ',\n",
|
||||||
|
" 'Inverter 1 to Module Area 1: Own Consumption (Standby or Night) ',\n",
|
||||||
|
" 'Inverter 1 to Module Area 1: PV energy (AC) minus standby use ',\n",
|
||||||
|
" 'Inverter 2 to Module Area 1: Own Consumption (Standby or Night) ',\n",
|
||||||
|
" 'Inverter 2 to Module Area 1: PV energy (AC) minus standby use ',\n",
|
||||||
|
" 'Unnamed: 58'],\n",
|
||||||
|
" dtype='object')"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 87,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"\n",
|
||||||
|
"file_name = 'Riyahd_raw.csv'\n",
|
||||||
|
"df = read_csv(file_name)\n",
|
||||||
|
"df.columns"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 88,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"remain_column = ['Time','PV energy (AC) minus standby use ']\n",
|
||||||
|
"energy_row_name = remain_column[1]\n",
|
||||||
|
"\n",
|
||||||
|
"df = df[remain_column]\n",
|
||||||
|
"df[energy_row_name] = df[energy_row_name].str.replace(',','.').astype(float)\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 89,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"770594.226863267"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 89,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"sum_energy = df[energy_row_name].sum()\n",
|
||||||
|
"sum_energy"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 90,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"1975.882632982736"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 90,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"sum_energy / 390"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 91,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"group_size = 15\n",
|
||||||
|
"df['group_id'] = df.index // group_size\n",
|
||||||
|
"\n",
|
||||||
|
"sums = df.groupby('group_id')[energy_row_name].sum()\n",
|
||||||
|
"sums_df = sums.reset_index(drop=True).to_frame(name = 'Energy')"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 92,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"<bound method NDFrame.head of Energy\n",
|
||||||
|
"0 0.0\n",
|
||||||
|
"1 0.0\n",
|
||||||
|
"2 0.0\n",
|
||||||
|
"3 0.0\n",
|
||||||
|
"4 0.0\n",
|
||||||
|
"... ...\n",
|
||||||
|
"35035 0.0\n",
|
||||||
|
"35036 0.0\n",
|
||||||
|
"35037 0.0\n",
|
||||||
|
"35038 0.0\n",
|
||||||
|
"35039 0.0\n",
|
||||||
|
"\n",
|
||||||
|
"[35040 rows x 1 columns]>"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 92,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"sums_df.head"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 93,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
" Time\n",
|
||||||
|
"0 2023-01-01 00:00:00\n",
|
||||||
|
"1 2023-01-01 00:15:00\n",
|
||||||
|
"2 2023-01-01 00:30:00\n",
|
||||||
|
"3 2023-01-01 00:45:00\n",
|
||||||
|
"4 2023-01-01 01:00:00\n",
|
||||||
|
" Time\n",
|
||||||
|
"35035 2023-12-31 22:45:00\n",
|
||||||
|
"35036 2023-12-31 23:00:00\n",
|
||||||
|
"35037 2023-12-31 23:15:00\n",
|
||||||
|
"35038 2023-12-31 23:30:00\n",
|
||||||
|
"35039 2023-12-31 23:45:00\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"\n",
|
||||||
|
"start_date = '2023-01-01'\n",
|
||||||
|
"end_date = '2023-12-31'\n",
|
||||||
|
"\n",
|
||||||
|
"# 生成每天的15分钟间隔时间\n",
|
||||||
|
"all_dates = pd.date_range(start=start_date, end=end_date, freq='D')\n",
|
||||||
|
"all_times = pd.timedelta_range(start='0 min', end='1435 min', freq='15 min')\n",
|
||||||
|
"\n",
|
||||||
|
"# 生成完整的时间标签\n",
|
||||||
|
"date_times = [pd.Timestamp(date) + time for date in all_dates for time in all_times]\n",
|
||||||
|
"\n",
|
||||||
|
"# 创建DataFrame\n",
|
||||||
|
"time_frame = pd.DataFrame({\n",
|
||||||
|
" 'Time': date_times\n",
|
||||||
|
"})\n",
|
||||||
|
"\n",
|
||||||
|
"# 查看生成的DataFrame\n",
|
||||||
|
"print(time_frame.head())\n",
|
||||||
|
"print(time_frame.tail())\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 94,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"(35040, 1)\n",
|
||||||
|
"(35040, 1)\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"print(sums_df.shape)\n",
|
||||||
|
"print(time_frame.shape)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 95,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"# sums_df['Time'] = time_frame['Time']\n",
|
||||||
|
"sums_df = pd.concat([time_frame, sums_df], axis=1)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 96,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
" Energy\n",
|
||||||
|
"Time \n",
|
||||||
|
"2023-01-01 00:00:00 0.0\n",
|
||||||
|
"2023-01-01 00:15:00 0.0\n",
|
||||||
|
"2023-01-01 00:30:00 0.0\n",
|
||||||
|
"2023-01-01 00:45:00 0.0\n",
|
||||||
|
"2023-01-01 01:00:00 0.0\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"sums_df.set_index('Time', inplace=True)\n",
|
||||||
|
"print(sums_df.head())"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 97,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"max_value = sums_df['Energy'].max()\n",
|
||||||
|
"sums_df['Energy'] = sums_df['Energy'] / max_value\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 98,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def save_csv(df, filename, columns):\n",
|
||||||
|
" tmp_df = df.copy()\n",
|
||||||
|
" tmp_df[columns[1]] = tmp_df[columns[1]].round(4)\n",
|
||||||
|
" with open(filename, 'w', newline='') as file:\n",
|
||||||
|
" writer = csv.writer(file)\n",
|
||||||
|
" writer.writerow(columns)\n",
|
||||||
|
" for index, row in tmp_df.iterrows():\n",
|
||||||
|
" time_formatted = index.strftime('%H:%M')\n",
|
||||||
|
" writer.writerow([time_formatted, row[columns[1]]])\n",
|
||||||
|
" \n",
|
||||||
|
" print(f'The file is written to {filename}')\n",
|
||||||
|
" \n",
|
||||||
|
"\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 99,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"The file is written to Riyahd.csv\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"save_csv(sums_df, 'Riyahd.csv', ['Time', 'Energy'])"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "pv",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.11.9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 2
|
||||||
|
}
|
79
read_data/convert_data.py
Normal file
79
read_data/convert_data.py
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
import os
|
||||||
|
import csv
|
||||||
|
|
||||||
|
def generate_min_df(mins = 15):
|
||||||
|
end = 60/mins * 24
|
||||||
|
start_date = '2023-01-01'
|
||||||
|
end_date = '2023-12-31'
|
||||||
|
|
||||||
|
all_dates = pd.date_range(start=start_date, end=end_date, freq='D')
|
||||||
|
all_times = pd.timedelta_range(start='0 min', end=f'1435 min', freq=f'{mins} min')
|
||||||
|
|
||||||
|
date_times = [pd.Timestamp(date) + time for date in all_dates for time in all_times]
|
||||||
|
|
||||||
|
time_frame = pd.DataFrame({
|
||||||
|
'Time': date_times
|
||||||
|
})
|
||||||
|
return time_frame
|
||||||
|
|
||||||
|
def save_csv(df, filename, columns):
|
||||||
|
with open(filename, 'w', newline='') as file:
|
||||||
|
writer = csv.writer(file)
|
||||||
|
writer.writerow(['Time', 'PV yield[kW/kWp]'])
|
||||||
|
for index, row in df.iterrows():
|
||||||
|
time_formatted = index.strftime('%H:%M')
|
||||||
|
writer.writerow([time_formatted, row[columns[1]]])
|
||||||
|
|
||||||
|
print(f'The file is written to {filename}')
|
||||||
|
|
||||||
|
def read_csv(filename):
|
||||||
|
skip_rows = list(range(1, 17))
|
||||||
|
data = pd.read_csv(filename, sep=';', skiprows=skip_rows)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def process(file_name):
|
||||||
|
df = read_csv(file_name)
|
||||||
|
city = file_name.split('_')[0]
|
||||||
|
|
||||||
|
remain_column = ['Time','PV energy (AC) minus standby use ']
|
||||||
|
energy_row_name = remain_column[1]
|
||||||
|
|
||||||
|
df = df[remain_column]
|
||||||
|
df[energy_row_name] = df[energy_row_name].str.replace(',','.').astype(float)
|
||||||
|
|
||||||
|
sum_energy = df[energy_row_name].sum()
|
||||||
|
group_size = 15
|
||||||
|
df['group_id'] = df.index // group_size
|
||||||
|
|
||||||
|
sums = df.groupby('group_id')[energy_row_name].sum()
|
||||||
|
sums_df = sums.reset_index(drop=True).to_frame(name = 'Energy')
|
||||||
|
|
||||||
|
pv_energy_column_name = 'PV yield[kW/kWp]'
|
||||||
|
sums_df = sums_df.rename(columns={'Energy': pv_energy_column_name})
|
||||||
|
|
||||||
|
time_frame = generate_min_df(15)
|
||||||
|
sums_df = pd.concat([time_frame, sums_df], axis=1)
|
||||||
|
# sums_df.set_index('Time', inplace=True)
|
||||||
|
# max_value = sums_df[pv_energy_column_name].max()
|
||||||
|
sums_df[pv_energy_column_name] = sums_df[pv_energy_column_name] / 390.
|
||||||
|
sums_df[pv_energy_column_name] = sums_df[pv_energy_column_name].round(4)
|
||||||
|
sums_df[pv_energy_column_name].replace(0.0, -0.0)
|
||||||
|
|
||||||
|
sums_df.to_csv(f'{city}.csv')
|
||||||
|
# save_csv(sums_df, f'{city}.csv', ['Time', 'Energy'])
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
city_list = ['Riyahd', 'Cambodge', 'Berlin', 'Serbia']
|
||||||
|
for city in city_list:
|
||||||
|
print(f'Processing {city}')
|
||||||
|
file_name = f'{city}_raw.csv'
|
||||||
|
process(file_name)
|
||||||
|
print(f'Processing {city} is done\n')
|
||||||
|
|
35041
read_data/electricity_price_data.csv
Normal file
35041
read_data/electricity_price_data.csv
Normal file
File diff suppressed because it is too large
Load Diff
35041
read_data/electricity_price_data_sell.csv
Normal file
35041
read_data/electricity_price_data_sell.csv
Normal file
File diff suppressed because it is too large
Load Diff
35041
read_data/factory_power1.csv
Normal file
35041
read_data/factory_power1.csv
Normal file
File diff suppressed because it is too large
Load Diff
16
xlsx2csv.py
Normal file
16
xlsx2csv.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
excel_file = 'factory_power1.xlsx'
|
||||||
|
sheet_name = 'Sheet1'
|
||||||
|
|
||||||
|
df = pd.read_excel(excel_file, sheet_name=sheet_name)
|
||||||
|
|
||||||
|
start_date = '2023-01-01'
|
||||||
|
df_power = pd.read_excel(excel_file,
|
||||||
|
header=None,
|
||||||
|
names=['FactoryPower'],
|
||||||
|
dtype={'FactoryPower': float})
|
||||||
|
times = pd.date_range(start=start_date, periods=len(df_power), freq='15min')
|
||||||
|
df_power['Time'] = times
|
||||||
|
df_power = df_power[['Time', 'FactoryPower']]
|
||||||
|
df_power.to_csv('factory_power1.csv', index=True)
|
Reference in New Issue
Block a user