Compare commits

..

10 Commits

Author SHA1 Message Date
54657cffd5 Lastprofile angepasst, variable Zahl an Producer+Consumer 2025-01-07 21:04:56 +01:00
Patrick Hangl
210a2f9bc3 Einlesen .csv angepasst 2025-01-07 16:02:19 +01:00
Patrick Hangl
ff88aacf4d lastprofile angepasst 2025-01-07 16:01:57 +01:00
MundM99
9c7e5f418a Kleiner Prototyp für Leistungssimulation eingefügt 2025-01-04 08:48:12 +01:00
65a56bb5a2 PV-Ausrichtung angepasst, Neighborhood formatiert 2025-01-03 14:48:00 +01:00
eb130b6be2 Modell funktioniert, Jahr 2019 eingestellt 2025-01-01 12:08:07 +01:00
Patrick Hangl
abe1c9d83d Conversion Skript für stündliche Werte aus csv 2024-12-19 15:26:43 +01:00
Patrick Hangl
f248d74dbe Lastprofile organisiert 2024-12-18 13:23:16 +01:00
Patrick Hangl
1cf5b45563 pv_input auskommentiert 2024-12-16 10:39:59 +01:00
047ee6ee0f Wetterdaten eingebunden 2024-12-15 22:02:41 +01:00
10 changed files with 52787 additions and 92 deletions

3
.gitignore vendored
View File

@@ -1 +1,2 @@
__pycache__/ __pycache__/
production_profile.csv

35042
Lastprofil_SWBT.csv Normal file

File diff suppressed because it is too large Load Diff

BIN
Lastprofil_VDEW.xls Normal file

Binary file not shown.

8762
Lastprofil_final_H0.csv Normal file

File diff suppressed because it is too large Load Diff

8761
Lastprofile_gesamt.csv Normal file

File diff suppressed because it is too large Load Diff

22
Leitungssimulation.py Normal file
View 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
View 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
View File

@@ -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()

View File

@@ -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
import pandas as pd
class Producer:
def __init__(self, quantity, profile_type):
self.quantity = quantity
self.profile_type = profile_type
self.consumption_profile = self.create_consumption_profile()
self.production_profile = self.create_production_profile()
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):
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
# Erzegungsprofil über PV_Input.py erstelln, in .csv schreiben und von dort dann die Leistungs-Series extrahieren
def create_production_profile(self):
production_profile = pv.create_production_profile()
production_profile.to_csv('production_profile.csv', sep=';',header=['Leistung'])
production_profile = pd.read_csv('production_profile.csv',delimiter=';')
return production_profile['Leistung']
# Erzeugungsprofil mit der Anzahl der entsprechenden Haushalte multiplizieren
def calculate_final_production(self):
final_production = self.production_profile.mul(self.quantity)
return final_production
class Consumer: class Consumer:
def __init__(self, quantity, average_consumption): 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.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): def create_consumption_profile(self):
profile = np.zeros(24) if self.profile_type == 'std':
peak_hours = [12] 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.8 elif self.profile_type == 'ea':
return profile consumption_profile = pd.read_csv('Lastprofile_gesamt.csv',delimiter=';')
return consumption_profile['Leistung_EA']*1000
def calculate_daily_consumption(self): # Verbrauchsprofil mit der Anzahl der entsprechenden Haushalte multiplizieren
daily_consumption = self.quantity * self.average_consumption * self.consumption_profile def calculate_final_consumption(self):
return daily_consumption final_consumption = self.consumption_profile.mul(self.quantity)
return final_consumption
class Producer:
def __init__(self, quantity, average_consumption, average_production):
self.quantity = quantity
self.consumption_profile = self.create_consumption_profile()
self.average_consumption = average_consumption
self.production_profile = self.create_production_profile()
self.average_production = average_production
def create_consumption_profile(self):
profile = np.zeros(24)
peak_hours = [8,12,13,18,19,20,21]
for hour in peak_hours:
profile[hour] = 1.5
for hour in range(24):
if hour not in peak_hours:
profile[hour] = 0.5
return profile
def create_production_profile(self):
profile = np.zeros(24)
peak_hours = [8,9,10,11,12,13,14,15,16,17,18,19]
for hour in peak_hours:
profile[hour] = 1.5
for hour in range(24):
if hour not in peak_hours:
profile[hour] = 0
return profile
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()

View File

@@ -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,34 +16,69 @@ 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']
location = Location(latitude, longitude, tz) def create_production_profile():
system = PVSystem(surface_tilt=surface_tilt, surface_azimuth=surface_azimuth, module_parameters=module, # Location + PVSystem-Objekte anlegen und Modelchain damit füttern
inverter_parameters=inverter, temperature_model_parameters=temperature_parameters, location = Location(latitude, longitude, tz)
modules_per_string=modules_per_string, strings_per_inverter=strings_per_inverter) system = PVSystem(surface_tilt=surface_tilt, surface_azimuth=surface_azimuth, module_parameters=module,
inverter_parameters=inverter, temperature_model_parameters=temperature_parameters,
modules_per_string=modules_per_string, strings_per_inverter=strings_per_inverter)
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