Compare commits
10 Commits
3ad2e47361
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 54657cffd5 | |||
|
|
210a2f9bc3 | ||
|
|
ff88aacf4d | ||
|
|
9c7e5f418a | ||
| 65a56bb5a2 | |||
| eb130b6be2 | |||
|
|
abe1c9d83d | ||
|
|
f248d74dbe | ||
|
|
1cf5b45563 | ||
| 047ee6ee0f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
__pycache__/
|
__pycache__/
|
||||||
|
production_profile.csv
|
||||||
35042
Lastprofil_SWBT.csv
Normal file
35042
Lastprofil_SWBT.csv
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Lastprofil_VDEW.xls
Normal file
BIN
Lastprofil_VDEW.xls
Normal file
Binary file not shown.
8762
Lastprofil_final_H0.csv
Normal file
8762
Lastprofil_final_H0.csv
Normal file
File diff suppressed because it is too large
Load Diff
8761
Lastprofile_gesamt.csv
Normal file
8761
Lastprofile_gesamt.csv
Normal file
File diff suppressed because it is too large
Load Diff
22
Leitungssimulation.py
Normal file
22
Leitungssimulation.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import numpy as np
|
||||||
|
import math
|
||||||
|
import matplotlib as plt
|
||||||
|
|
||||||
|
#Units are SI-Units except for cable cross-section
|
||||||
|
|
||||||
|
def distance(x1,y1,x2,y2):
|
||||||
|
distance = math.sqrt(((x2-x1)^2)*((y2-y1)^2))
|
||||||
|
return distance
|
||||||
|
|
||||||
|
def resistance(l,a,rho):
|
||||||
|
#Calculate the resistance between 2 coordinates
|
||||||
|
#Add 10% of length for various factors such as transitions and hanging lines
|
||||||
|
r = l*a*rho
|
||||||
|
return r
|
||||||
|
|
||||||
|
def power_loss(resitance,voltage,power):
|
||||||
|
loss = (voltage^2)/resistance
|
||||||
|
return loss
|
||||||
|
|
||||||
|
def run():
|
||||||
|
distance(1,2,3,4)
|
||||||
18
conversion.py
Normal file
18
conversion.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import csv
|
||||||
|
|
||||||
|
def process_csv(input_file, output_file):
|
||||||
|
n = -2
|
||||||
|
with open(input_file, mode='r', newline='') as infile:
|
||||||
|
reader = csv.reader(infile)
|
||||||
|
with open(output_file, mode='w', newline='') as outfile:
|
||||||
|
writer = csv.writer(outfile)
|
||||||
|
for row in reader:
|
||||||
|
n = n + 1
|
||||||
|
if n==4:
|
||||||
|
writer.writerow(row)
|
||||||
|
n = 0
|
||||||
|
|
||||||
|
# Beispielhafte Verwendung
|
||||||
|
input_file = 'Lastprofil_SWBT.csv'
|
||||||
|
output_file = 'Lastprofil_final_H0.csv'
|
||||||
|
process_csv(input_file, output_file)
|
||||||
20
main.py
20
main.py
@@ -1,17 +1,17 @@
|
|||||||
from neighborhood import Producer, Consumer, Neighborhood
|
from neighborhood import Producer, Consumer, Neighborhood
|
||||||
|
|
||||||
# Anzahl Haushalte ohne PV-Anlagen
|
# Consumer-Instanzen anlegen
|
||||||
num_consumer = 50
|
standard_consumer = Consumer(quantity=10, profile_type='std')
|
||||||
avg_consumption_per_consumer = 10
|
wp_consumer = Consumer(quantity=0, profile_type='wp')
|
||||||
|
ea_consumer = Consumer(quantity=0, profile_type='ea')
|
||||||
|
|
||||||
# Anzahl Haushalte mit PV-Anlagen
|
|
||||||
num_producer = 10
|
|
||||||
avg_production_per_producer = 20
|
|
||||||
|
|
||||||
# Instanzen für Erzeuger und Verbraucher anlegen
|
# Producer-Instanz anlegen
|
||||||
consumer = Consumer(num_consumer, avg_consumption_per_consumer)
|
standard_producer = Producer(quantity=0, profile_type='std')
|
||||||
producer = Producer(num_producer, avg_consumption_per_consumer, avg_production_per_producer)
|
wp_producer = Producer(quantity=0, profile_type='wp')
|
||||||
|
ea_producer = Producer(quantity=0, profile_type='ea')
|
||||||
|
|
||||||
|
|
||||||
# Instanz für Nachbarschaft anlegen und Ergebnis plotten
|
# Instanz für Nachbarschaft anlegen und Ergebnis plotten
|
||||||
neighborhood = Neighborhood(producer, consumer)
|
neighborhood = Neighborhood(producers=[standard_producer, wp_producer, ea_producer], consumers=[standard_consumer, wp_consumer, ea_consumer])
|
||||||
neighborhood.plot_consumption()
|
neighborhood.plot_consumption()
|
||||||
170
neighborhood.py
170
neighborhood.py
@@ -1,90 +1,134 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
|
import pv_input as pv
|
||||||
class Consumer:
|
import pandas as pd
|
||||||
def __init__(self, quantity, average_consumption):
|
|
||||||
self.quantity = quantity
|
|
||||||
self.consumption_profile = self.create_consumption_profile()
|
|
||||||
self.average_consumption = average_consumption
|
|
||||||
|
|
||||||
def create_consumption_profile(self):
|
|
||||||
profile = np.zeros(24)
|
|
||||||
peak_hours = [12]
|
|
||||||
for hour in peak_hours:
|
|
||||||
profile[hour] = 1.5
|
|
||||||
for hour in range(24):
|
|
||||||
if hour not in peak_hours:
|
|
||||||
profile[hour] = 0.8
|
|
||||||
return profile
|
|
||||||
|
|
||||||
def calculate_daily_consumption(self):
|
|
||||||
daily_consumption = self.quantity * self.average_consumption * self.consumption_profile
|
|
||||||
return daily_consumption
|
|
||||||
|
|
||||||
class Producer:
|
class Producer:
|
||||||
def __init__(self, quantity, average_consumption, average_production):
|
def __init__(self, quantity, profile_type):
|
||||||
self.quantity = quantity
|
self.quantity = quantity
|
||||||
|
self.profile_type = profile_type
|
||||||
self.consumption_profile = self.create_consumption_profile()
|
self.consumption_profile = self.create_consumption_profile()
|
||||||
self.average_consumption = average_consumption
|
|
||||||
self.production_profile = self.create_production_profile()
|
self.production_profile = self.create_production_profile()
|
||||||
self.average_production = average_production
|
self.final_consumption = self.calculate_final_consumption()
|
||||||
|
self.final_production = self.calculate_final_production()
|
||||||
|
|
||||||
|
# Vebrauchsprofile aus CSV-Datei in Dataframe einlesen und je nach profile_type die entsprechende Leistungs-Series extrahieren
|
||||||
def create_consumption_profile(self):
|
def create_consumption_profile(self):
|
||||||
profile = np.zeros(24)
|
if self.profile_type == 'std':
|
||||||
peak_hours = [8,12,13,18,19,20,21]
|
consumption_profile = pd.read_csv('Lastprofile_gesamt.csv',delimiter=';')
|
||||||
for hour in peak_hours:
|
return consumption_profile['Leistung']*1000
|
||||||
profile[hour] = 1.5
|
elif self.profile_type == 'wp':
|
||||||
for hour in range(24):
|
consumption_profile = pd.read_csv('Lastprofile_gesamt.csv',delimiter=';')
|
||||||
if hour not in peak_hours:
|
return consumption_profile['Leistung_WP']*1000
|
||||||
profile[hour] = 0.5
|
elif self.profile_type == 'ea':
|
||||||
return profile
|
consumption_profile = pd.read_csv('Lastprofile_gesamt.csv',delimiter=';')
|
||||||
|
return consumption_profile['Leistung_EA']*1000
|
||||||
|
|
||||||
|
# Verbrauchsprofil mit der Anzahl der entsprechenden Haushalte multiplizieren
|
||||||
|
def calculate_final_consumption(self):
|
||||||
|
final_consumption = self.consumption_profile.mul(self.quantity)
|
||||||
|
return final_consumption
|
||||||
|
|
||||||
|
# Erzegungsprofil über PV_Input.py erstelln, in .csv schreiben und von dort dann die Leistungs-Series extrahieren
|
||||||
def create_production_profile(self):
|
def create_production_profile(self):
|
||||||
profile = np.zeros(24)
|
production_profile = pv.create_production_profile()
|
||||||
peak_hours = [8,9,10,11,12,13,14,15,16,17,18,19]
|
production_profile.to_csv('production_profile.csv', sep=';',header=['Leistung'])
|
||||||
for hour in peak_hours:
|
production_profile = pd.read_csv('production_profile.csv',delimiter=';')
|
||||||
profile[hour] = 1.5
|
return production_profile['Leistung']
|
||||||
for hour in range(24):
|
|
||||||
if hour not in peak_hours:
|
# Erzeugungsprofil mit der Anzahl der entsprechenden Haushalte multiplizieren
|
||||||
profile[hour] = 0
|
def calculate_final_production(self):
|
||||||
return profile
|
final_production = self.production_profile.mul(self.quantity)
|
||||||
|
return final_production
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Consumer:
|
||||||
|
def __init__(self, quantity, profile_type):
|
||||||
|
self.quantity = quantity
|
||||||
|
self.profile_type = profile_type
|
||||||
|
self.consumption_profile = self.create_consumption_profile()
|
||||||
|
self.final_consumption = self.calculate_final_consumption()
|
||||||
|
|
||||||
|
# Vebrauchsprofile aus CSV-Datei in Dataframe einlesen und je nach profile_type die entsprechende Leistungs-Series extrahieren
|
||||||
|
def create_consumption_profile(self):
|
||||||
|
if self.profile_type == 'std':
|
||||||
|
consumption_profile = pd.read_csv('Lastprofile_gesamt.csv',delimiter=';')
|
||||||
|
return consumption_profile['Leistung']*1000
|
||||||
|
elif self.profile_type == 'wp':
|
||||||
|
consumption_profile = pd.read_csv('Lastprofile_gesamt.csv',delimiter=';')
|
||||||
|
return consumption_profile['Leistung_WP']*1000
|
||||||
|
elif self.profile_type == 'ea':
|
||||||
|
consumption_profile = pd.read_csv('Lastprofile_gesamt.csv',delimiter=';')
|
||||||
|
return consumption_profile['Leistung_EA']*1000
|
||||||
|
|
||||||
|
|
||||||
|
# Verbrauchsprofil mit der Anzahl der entsprechenden Haushalte multiplizieren
|
||||||
|
def calculate_final_consumption(self):
|
||||||
|
final_consumption = self.consumption_profile.mul(self.quantity)
|
||||||
|
return final_consumption
|
||||||
|
|
||||||
def calculate_daily_consumption(self):
|
|
||||||
daily_consumption = self.quantity * self.average_consumption * self.consumption_profile
|
|
||||||
return daily_consumption
|
|
||||||
|
|
||||||
def calculate_daily_production(self):
|
|
||||||
daily_production = self.quantity * self.average_production * self.production_profile
|
|
||||||
return daily_production
|
|
||||||
|
|
||||||
class Neighborhood:
|
class Neighborhood:
|
||||||
def __init__(self, producer, consumer):
|
def __init__(self, producers, consumers):
|
||||||
self.producer = producer
|
self.producers = producers if isinstance(producers, list) else [producers]
|
||||||
self.consumer = consumer
|
self.consumers = consumers if isinstance(consumers, list) else [consumers]
|
||||||
|
|
||||||
|
# Gesamterzeugung, Gesamtverbrauch und Nettoverbrauch plotten
|
||||||
def plot_consumption(self):
|
def plot_consumption(self):
|
||||||
total_consumption = -1*(self.consumer.calculate_daily_consumption() + self.producer.calculate_daily_consumption())
|
total_consumption = 0
|
||||||
total_production = self.producer.calculate_daily_production()
|
total_production = 0
|
||||||
|
# Verbrauch der Consumer subtrahieren
|
||||||
|
for consumer in self.consumers:
|
||||||
|
total_consumption -= consumer.final_consumption
|
||||||
|
# Zusätzlich Verbrauch der Producer subtrahieren
|
||||||
|
for producer in self.producers:
|
||||||
|
total_consumption -= producer.final_consumption
|
||||||
|
# Produktion der Producer addieren
|
||||||
|
for producer in self.producers:
|
||||||
|
total_production += producer.final_production
|
||||||
|
# Netto-Erzeugnis ausrechnen
|
||||||
net_value = total_consumption + total_production
|
net_value = total_consumption + total_production
|
||||||
|
# Rollendes Mittel des netto-Erzeugnisses ausrechnen
|
||||||
|
net_value_mean = net_value.rolling(24).mean()
|
||||||
|
|
||||||
|
|
||||||
|
# X-Werte anlegen, einen Wert löschen da 8761 Werte vorhanden sind, aber nur 8760 benötigt werden
|
||||||
|
x = pd.date_range(start='2018-12-31', end ='2019-12-31', freq='1h')
|
||||||
|
x = x[:-1]
|
||||||
|
|
||||||
# X-Werte anlegen
|
|
||||||
x = range(24)
|
|
||||||
x_labels = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24']
|
|
||||||
# Plot dimensionieren
|
# Plot dimensionieren
|
||||||
plt.figure(figsize=(10, 6))
|
plt.figure(figsize=(15, 9))
|
||||||
# y-Werte den x-Werten zuordnen
|
|
||||||
plt.plot(x, total_consumption, '--', x, total_production, '--', x, net_value, '-')
|
# Barplots anlegen
|
||||||
# Titel und Achsenbeschriftungen anlegen
|
plt.bar(x, total_consumption)
|
||||||
plt.xlabel('Stunde')
|
plt.bar(x, total_production,color='orange')
|
||||||
plt.ylabel('Strom (kWh)')
|
|
||||||
plt.title('Produktion/Verbrauch Nachbarschaft')
|
# Linienplot anlegen
|
||||||
# X-Werten die Labels zuordnen
|
#plt.plot(x, net_value,'-',color='darkgreen')
|
||||||
plt.xticks(x, x_labels)
|
plt.plot(x, net_value_mean,'-',color='darkgreen')
|
||||||
|
|
||||||
|
# Achsenbeschriftungen anlegen
|
||||||
|
plt.xlabel('Kalendertag')
|
||||||
|
plt.ylabel('Leistung (W)')
|
||||||
|
|
||||||
|
# Titel anlegen
|
||||||
|
#plt.title('Netto-leistung Nachbarschaft - Fall XXX')
|
||||||
|
plt.title('Erzeugung, Verbrauch und Netto-Leistung (Rollendes Mittel 24h) - Fall XXX')
|
||||||
|
|
||||||
|
# X-Ticks nur monatlich plotten
|
||||||
|
monthly_ticks = pd.date_range(start='2018-12-31', end ='2019-12-31', freq='1MS')
|
||||||
|
plt.xticks(monthly_ticks)
|
||||||
|
|
||||||
# Legende anlegen
|
# Legende anlegen
|
||||||
plt.legend(['Verbrauch', 'Produktion', 'Netto-Wert'], loc='upper right')
|
plt.legend(['Netto-Leistung', 'Leistung Verbrauch', 'Leistung Erzeugung'], loc='upper right')
|
||||||
|
|
||||||
# X-Labels rotieren
|
# X-Labels rotieren
|
||||||
plt.xticks(rotation=45)
|
plt.xticks(rotation=45)
|
||||||
|
|
||||||
# Grid anlegen
|
# Grid anlegen
|
||||||
|
plt.axhline(linewidth=1, color='black')
|
||||||
plt.grid(color='black', axis='y', linestyle='--', linewidth=0.5)
|
plt.grid(color='black', axis='y', linestyle='--', linewidth=0.5)
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|
||||||
|
|||||||
63
pv_input.py
63
pv_input.py
@@ -1,3 +1,13 @@
|
|||||||
|
# 3 Möglichkeiten für Ertragsberechnung: Clear Sky Modell, TMY oder POA-Data
|
||||||
|
# Clear Sky: Strahlungsmodell, welches theoretische Strahlungsdaten an bestimmten Standpunkt enthält welche eine flache Oberfläche treffen - vewerndet g(i)-Strahlungsdaten
|
||||||
|
# TMY = Typical Meteorolical Year - reale Strahlungsdaten welche eine flache Oberfläche treffen - vewerndet g(i)-Strahlungsdaten
|
||||||
|
# POA = Plane of Array - was das PV-Modul (und dessen Ausrichtung) wirklich trifft - verwendet POA-Strahlungsdaten
|
||||||
|
|
||||||
|
# G(i), poa_global = Global irradiance on inclined plane (W/m^2)
|
||||||
|
# Gb(i), poa_direct = Beam (direct) irradiance on inclined plane (W/m^2)
|
||||||
|
# Gd(i), poa_sky_diffuse = Diffuse irradiance on inclined plane (W/m^2)
|
||||||
|
# Gr(i), poa_ground_diffuse = Reflected irradiance on inclined plane (W/m^2)
|
||||||
|
|
||||||
import pvlib
|
import pvlib
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
@@ -6,22 +16,29 @@ from pvlib.location import Location
|
|||||||
from pvlib.pvsystem import PVSystem
|
from pvlib.pvsystem import PVSystem
|
||||||
from pvlib.temperature import TEMPERATURE_MODEL_PARAMETERS
|
from pvlib.temperature import TEMPERATURE_MODEL_PARAMETERS
|
||||||
|
|
||||||
|
# Daten Standort
|
||||||
latitude = 47.2675
|
latitude = 47.2675
|
||||||
longitude = 11.3910
|
longitude = 11.3910
|
||||||
tz = 'Europe/Vienna'
|
tz = 'Europe/Vienna'
|
||||||
surface_tilt = 0
|
year = 2019
|
||||||
surface_azimuth = 180
|
|
||||||
|
|
||||||
|
# Daten für Datenbank -> Module + WR
|
||||||
database_module = pvlib.pvsystem.retrieve_sam('SandiaMod')
|
database_module = pvlib.pvsystem.retrieve_sam('SandiaMod')
|
||||||
database_inverter = pvlib.pvsystem.retrieve_sam('CECInverter')
|
database_inverter = pvlib.pvsystem.retrieve_sam('CECInverter')
|
||||||
|
|
||||||
module = database_module['Canadian_Solar_CS5P_220M___2009_']
|
module = database_module['Canadian_Solar_CS5P_220M___2009_']
|
||||||
inverter = database_inverter['ABB__PVI_4_2_OUTD_US__208V_']
|
inverter = database_inverter['ABB__PVI_4_2_OUTD_US__208V_']
|
||||||
|
|
||||||
|
# PV-Anlage definieren
|
||||||
modules_per_string = 10
|
modules_per_string = 10
|
||||||
strings_per_inverter = 2
|
strings_per_inverter = 2
|
||||||
|
surface_tilt = 20
|
||||||
|
surface_azimuth = 150
|
||||||
|
|
||||||
|
# Temperaturparameter definieren
|
||||||
temperature_parameters = TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_glass']
|
temperature_parameters = TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_glass']
|
||||||
|
|
||||||
|
def create_production_profile():
|
||||||
|
# Location + PVSystem-Objekte anlegen und Modelchain damit füttern
|
||||||
location = Location(latitude, longitude, tz)
|
location = Location(latitude, longitude, tz)
|
||||||
system = PVSystem(surface_tilt=surface_tilt, surface_azimuth=surface_azimuth, module_parameters=module,
|
system = PVSystem(surface_tilt=surface_tilt, surface_azimuth=surface_azimuth, module_parameters=module,
|
||||||
inverter_parameters=inverter, temperature_model_parameters=temperature_parameters,
|
inverter_parameters=inverter, temperature_model_parameters=temperature_parameters,
|
||||||
@@ -29,11 +46,39 @@ system = PVSystem(surface_tilt=surface_tilt, surface_azimuth=surface_azimuth, mo
|
|||||||
|
|
||||||
modelchain = ModelChain(system, location)
|
modelchain = ModelChain(system, location)
|
||||||
|
|
||||||
times = pd.date_range(start='2021-07-01', end ='2021-07-07', freq='1min', tz=location.tz)
|
# Ertragssimulation mit Clear-Sky Modell
|
||||||
|
|
||||||
clear_sky = location.get_clearsky(times)
|
# Index-Spalte mit Zeiten für clear-sky Dataset anlegen
|
||||||
#clear_sky.plot(figsize=(16,9))
|
# times = pd.date_range(start='2020-01-01', end ='2020-12-31', freq='1h', tz=location.tz)
|
||||||
|
|
||||||
modelchain.run_model(clear_sky)
|
# clear_sky = location.get_clearsky(times)
|
||||||
modelchain.results.ac.plot(figsize=(16,9))
|
# #clear_sky.plot(figsize=(16,9))
|
||||||
plt.show()
|
|
||||||
|
# modelchain.run_model(clear_sky)
|
||||||
|
|
||||||
|
# Ertragssimulation mit realen Strahlungsdaten aus Wetterjahr
|
||||||
|
|
||||||
|
# Hier ist Süden Azimuth = 0°, bei PVLib ist es 180°
|
||||||
|
poa_data, meta, inputs = pvlib.iotools.get_pvgis_hourly(latitude=latitude, longitude=longitude, start=year, end=year, raddatabase='PVGIS-SARAH3', components=True, surface_tilt=surface_tilt,
|
||||||
|
surface_azimuth=surface_azimuth-150, outputformat='json', usehorizon=True, userhorizon=None, pvcalculation=False, peakpower=None,
|
||||||
|
pvtechchoice='crystSi', mountingplace='free', loss=0, trackingtype=0, optimal_surface_tilt=False, optimalangles=False,
|
||||||
|
url='https://re.jrc.ec.europa.eu/api/', map_variables=True, timeout=30)
|
||||||
|
|
||||||
|
# Notwendige Spalten ausrechnen und hinzufügen, sodass Modelchain sie verwenden kann
|
||||||
|
poa_data['poa_diffuse'] = poa_data['poa_sky_diffuse'] + poa_data['poa_ground_diffuse']
|
||||||
|
poa_data['poa_global'] = poa_data['poa_diffuse'] + poa_data['poa_direct']
|
||||||
|
|
||||||
|
# Daten in csv exportieren
|
||||||
|
#poa_data.to_csv('poa_data.csv')
|
||||||
|
|
||||||
|
# Index des Dataframe mit datetime-Index von Pandas überschreiben
|
||||||
|
poa_data.index = pd.to_datetime((poa_data.index))
|
||||||
|
# Diese Funktion benötigt POA-Daten anstatt g(i)-Daten -> DOKU
|
||||||
|
modelchain.run_model_from_poa(poa_data)
|
||||||
|
|
||||||
|
# Ergebnis plotten
|
||||||
|
#modelchain.results.ac.plot(figsize=(16,9))
|
||||||
|
#plt.show()
|
||||||
|
|
||||||
|
# Rückgabewert
|
||||||
|
return modelchain.results.ac
|
||||||
Reference in New Issue
Block a user