Ziel

Im Tutorial 2 von www.pv4ing.ch sind drei Übungen vorgesehen. Die erste Übung erstellt eine Zeitreihe mit fiktiven Daten. Die zweite Übung verwendet Messdaten als Zeitreihe und die dritte Übung führt eine Berechnung der Jahresstrahlungsenergie durch, bei unterschiedlichen Ausrichtungen.

Tutorial 2 - Übung 1: Einstieg

Zuerst machen wir eine einfache Zeitreihenrechnung.

Schritt 1 - Synthetische Messwerte für 1 Tag

Im folgenden Beispiel, nehmen wir keine realen Messwerte, sondern "bauen" uns selbst die Messwerte über die Sinusfunktion. Zuerst erstellen wir einen Array (Zahlenreihe) für die Zeit. Wir nehmen an, dass die Sonne um 6:00 aufgeht und um 18:00 untergeht. Über Mittag erre icht die Strahlung einen Wert von 650 W/m2.

In [7]:
# Bibliotheken Import
import numpy as np
import matplotlib.pyplot as plt
import datetime as dt

# Funktionsdefinition (benötigen wir später)
cos  = lambda arg : np.cos(np.deg2rad(arg))
sin  = lambda arg : np.sin(np.deg2rad(arg))
acos = lambda arg : np.rad2deg(np.arccos(arg))
asin = lambda arg : np.rad2deg(np.arcsin(arg))

t = np.linspace(6,18,1000)
H = 650 * sin((t-6)/(18-6)*180)

Strahlungsarray (Zahlenreihe für die Strahlung in W/m2). Beachte das die Funktion sin() oben mit dem lambda-Operator definiert wurde und in Grad angegeben wird. Dies ist nicht bei der Funktion np.sin() der Fall.

Überprüfe ob der Zeitarray aus lauter Spaltenwerte (Zeile mit vielen Zahlen) oder aus lauter Zeilenwerte (Spalte mit vielen Zahlen) besteht. Spalte = column. Zeile = row.

In [8]:
np.shape(t)
Out[8]:
(1000,)

Stelle den Strahlungsverlauf als figure mit der Linienfarbe grün (g=green) dar.

In [9]:
plt.figure(2, figsize=(8,4))
plt.plot(t,H, 'g')
plt.xlabel('Zeit [h]')
plt.ylabel('Strahlung [W/m2]')
Out[9]:
Text(0, 0.5, 'Strahlung [W/m2]')

Nun können wir die Strahlungsenergie $W_H$ für diesen einen Tag berechnen. Beachte das die Berechung der "Energie = Leistung mal Zeit" ist. Hier ist der Zeitschritt "deltaT".

In [10]:
A = 1 # Fläche 1 m2
deltaT = t[1] - t[0]
wH = np.sum(H)*deltaT*A/1000
print('Strahlungsenergie [kWh/m2/Tag]: ' + str(wH))
Strahlungsenergie [kWh/m2/Tag]: 4.965630132215672

Nun haben wir folgende Punkte gelernt:

  1. Erstellen eines Arrays.
  2. Darstellen von Arrays, inklusiv Beschriftung.
  3. Berechnen eines Flächenintegrals aus diskreten Werten, d.h. Aufsummieren von Werten.

Schritt 2 - Synthetische Messwerte für 7 Tag

Nun wollen wir die Strahlungsenergie von 7 Tagen berechnen, von Stunde 0 bis Stunde 7 x 24. Die Sinusfunktion liefert uns für die Nacht (18:00 bis 6:00) negative Werte. Wir korrigieren die negativen Strahlungswerte zu 0.

In [11]:
H[H<0] = 0

Der Ausdruck "H<0" generiert ein Selektor-Array der Länge von H, bei dem die Positionen mit "1" oder "True" gekennzeichnet sind, bei welchen der Wert < 0 ist. Der Ausdruck H[Selektor-Array] = 0 weisst allen selektierten Positionen eine 0 zu.

Denkbar ist auch "M[N<1] = 2". M und N müssen gleich lange Arrays sein. Im Array M werden alle Stellen auf 2 gesetzt, bei denen der Wert im Array N < 1 ist.

Tutorial 2 - Übung 2: Berechnung Strahlungsenergie von mehreren Tagen mit Messdaten

Nun verwenden wir nicht "künstliche" Strahlungswerte (generiert durch die Sinusfunktion), sondern reale Messwert. Hierzu benötigen wir eine Datendatei. Wir erstellen einen Plot über 7 Tage mit der Globalstrahlung "hGlob", der Diffusstrahlung "hDif" und der Direktstrahlung "hDir".

Bei Energiesimulationen ist es empfehlenswert als Kommentar die Einheit anzugeben, sodass verständlich ist um was es sich handelt, z.B. [grad] oder [radiant] oder [W] oder [kWh].

Verwende für diese Übung ein neues py-File und importiere wieder die benötigten Bibliotheken (numpy, matplotlib, datetime).

Zum Importieren verwenden wir die Bibliothek pandas. Diese zeichnet sich durch gute Verarbeitung von Daten aus. Das Einlesen geht mittels "read_csv", dabei erhalten wir ein DataFrame (df). Dies ist vergleichbar mit einem Excel-Tabellenblatt mit einem Header, d.h. Überschriftzeile (Header) und Links einem laufenden Index. Mittels "set_index" legen wir den Zeitstempel als Index fest.

Den Anfang desn DateFrames stellen wir mit "df.head()" dar.

Die csv-Datei ist auf github https://github.com/markstaler/pv4ing.

In [12]:
## Daten importieren
import datetime as dt
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

pd.plotting.register_matplotlib_converters() ## Pandas wird das Datum direkt in einem "Timeseries"-Format importieren, 
# weshalb die Defaulteinstellungen von Matplotlib mit diesem Befehl angepasst werden.

df = pd.read_csv('2017_DataExport15min.csv', delimiter=';', header = 0)
df = df.set_index(pd.DatetimeIndex(df['Time'])) 

Für die Sonnenstandsberechnung, später, erzeugen wir nun einen Array mit laufenden Stunden, beginnend mit Stunde 0 bei Jahresamfang.

In [13]:
hGlo  = df['hGlo'].values    # [W/m2] 
hDif  = df['hDif'].values    # [W/m2]
tAmb  = df['Tamb'].values    # [°C]
pVer  = df['Pload'].values   # [W] Verbrauchsprofil
zapf  = df['Zapfung'].values # [l/15min] Profil für Warmwasserbezug
tutc = df.index


lfStd = np.zeros(tutc.size)
for t in range(tutc.size):
    # berechnet laufender Tag im Jahr
    noDay = (tutc[t] - dt.datetime(tutc[0].year, 1, 1, 0)).days 
    # [h] berechnet laufende Stunde im Tag
    noHou = tutc[t].hour + (tutc[t].minute)/60 + (tutc[t].second)/3600 
    lfStd[t] = noDay*24 + noHou
    
deltaT = lfStd[1] - lfStd[0] # [h]

Schritt 1

Es soll die Globalstrahlung in grün, Direktstrahlung in rot und Diffusstrahlung in blau dargestellt werden. Weiter soll in der Plot-Figure eine Legende mit den Kurvennamen dargestellt werden. Als Ausschnitt wollen wir die ersten 7 Tage betrachten, d.h. in der Plotfunktion grenzen wir den Array ein durch tutc[a:e], wobei a für den Anfangsindex und e für den Endindex steht.

Schritt 2

Wenn wir den ersten Tag im Plot ansehen, so fällt auf, dass negative Strahlungswerte vorkommen. Dies entspricht den Messergebnissen aber nicht der Realität. Deshalb sollen die Strahlungsdaten bereinigt werden.  

In [14]:
hDir = hGlo - hDif

hDir[hDir<0] = 0  # wichtig
hDif[hDif<0] = 0  # wichtig
hGlo[hGlo<0] = 0  # wichtig

a=int(0)           # Anfangstag
e=int(7*24/deltaT) # Endtag

t = tutc[a:e]
print(t)
plt.figure(3, figsize=(8,4))# Grösse des Plots (figsize) in Zoll
plt.plot(t,hGlo[a:e],'g', label ='Globalstrahlung')
plt.plot(t,hDir[a:e],'r', label ='Direktstrahlung')
plt.plot(t,hDif[a:e],'b', label ='Diffusstrahlung')
plt.xlabel('Zeit [h]');
plt.ylabel('Strahlung [W/m2]');
plt.legend(loc="upper left")
DatetimeIndex(['2017-01-15 00:00:00', '2017-01-15 00:15:00',
               '2017-01-15 00:30:00', '2017-01-15 00:45:00',
               '2017-01-15 01:00:00', '2017-01-15 01:15:00',
               '2017-01-15 01:30:00', '2017-01-15 01:45:00',
               '2017-01-15 02:00:00', '2017-01-15 02:15:00',
               ...
               '2017-01-21 21:30:00', '2017-01-21 21:45:00',
               '2017-01-21 22:00:00', '2017-01-21 22:15:00',
               '2017-01-21 22:30:00', '2017-01-21 22:45:00',
               '2017-01-21 23:00:00', '2017-01-21 23:15:00',
               '2017-01-21 23:30:00', '2017-01-21 23:45:00'],
              dtype='datetime64[ns]', name='Time', length=672, freq=None)
Out[14]:
<matplotlib.legend.Legend at 0x1d760c7ae88>
In [15]:
hGlo[hGlo>1000]=1000
hGloM = np.reshape(tAmb, (365,24*4))
hour = np.linspace(0,24,24*4)
day  = np.linspace(0,365,365)

fig = plt.figure(4, figsize=(8,6))
X, Y = np.meshgrid(hour, day)
CS = plt.contourf(X, Y, hGloM, 15) # 15 Linien
plt.title('Umgebungstemperatur übers Jahr')
plt.xlabel('Tagesstunde')
plt.ylabel('Tag im Jahr')
plt.grid(which='both', linestyle='--')
plt.show()
plt.plot(tAmb)
Out[15]:
[<matplotlib.lines.Line2D at 0x1d7610c7e88>]

Dynamische Diagramme mit Bokeh

Für eine Visalisierung eines Strahlungsverlauf übers Jahr, wäre es nützlich wenn in die Daten "gezoomt" werden könnte. Dies ist möglich mit dem Paket "bokeh". Es funktionert ähnlich wie Matplotlib. Es wird eine html-Datei erzeugt (mittels "output_file('filename.html')"), welche das Diagramm enthält und Werkzeuge zum Verschieben, Zommen, usw.

In [16]:
from bokeh.io import show  
from bokeh.plotting import figure 

x = np.linspace(0,7,100)
y = np.sin(x)

p1 = figure()
p1.line(x,y)

show(p1)

Nun zur Maximalvariante einer Darstellung. Zuerst noch die nützliche Funktion von pandas "resample", mit welcher eine Zeitreihe mit neuen Zeitschritte umgerechnet werden kann. Anschliessend werden die Daten mit "describe" dargestellt.

Die Übergabe der Daten erfolgt direkt als Dataframe (kann auch als Array erfolgen, wie bei Matplotlib). Im Dataframe erfänzen wir noch die Direktstrahlung und die Uhrzeit als String ("tutcStr") in einem, durch un, definierbaren Format.

Es werden die einzelnen Werkzeuge parametriert. "pan, box_zoom, reset, save" verstehen sich von selbst. Mit "hover" kann ein Tooltip ein/ausgeschalten werden. Tooltip heisst das die Daten der Kennlinie ausgegeben werden an der Position wo die Maus über der Kennlinie ist. Die Daten können die Messwerte sein mit Zugriff "@hGlo" oder der Wert aus der Kennlinie mit $y", welcher interpoliert wird.

Bei der Erzeugung des Diagramm-Objekt kann die Grösse eingestellt werden und die Parameter für Werkzeuge (tools) und Datenausgabe (tooltips).

Sehr schöne Funktion ist p1.legend.click_policy="hide" dabei können die Kurven ausgeblendet werden, wenn die jeweilige Legende angeklickt wird.

In [17]:
from bokeh.io import output_file, output_notebook, show  # Bokeh is for making charts in a browser
from bokeh.plotting import figure 
from bokeh.embed import components

## Daten importieren
df = pd.read_csv('2017_DataExport15min.csv', delimiter=';', header = 0)
df = df.set_index(pd.DatetimeIndex(df['Time'])) # erzeugt Datetime-Index welcher später für resampling notwendig ist
df = df.resample('30T').mean() # Die Daten werden "resampled" zu 30 min Werte. Dabei wird Mittelwertbildung durchgefürht
# print(df.describe()) # Erstellt Übersicht über die Zahlenwerte

# zum Dateframe ergänzen wir die Uhrzeit als Text
tutc    = df.index 
tmez = tutc - pd.Timedelta('1 hours') # Zeit in der Datei ist UTC und wird in MEZ umgewandelt (+1)
tmezStr = tmez.strftime("%d.%m.%Y %H:%M")
 
df['tmez'] = tmez    
df['tmezStr'] = tmezStr
df['hDir'] = df['hGlo'].values - df['hDif'].values

output_file('myHTML.html') # das Diagramm wird in einem separaten html-File exportiert
output_notebook()   # das Diagramm wirm unten im JupyterNotebook dargestellt

werkzeuge =  "pan, box_zoom, reset, save, hover"
tt = [
      ('Zeit MEZ:', '@tmezStr'),
      ('Globalstrahlung Diagramm:', '$y'),
      ('Globalstragkzbg Messwert:', '@hGlo'),
      ]

p1 = figure(title='Strahlungsverlauf', plot_width=800, plot_height=600, 
            tooltips = tt, 
            tools = werkzeuge, 
            x_axis_type='datetime')
p1.line(x='tmez',y='hGlo', source=df, legend = 'Global', color="green")
p1.xaxis.axis_label = 'Zeit [MEZ]'
p1.yaxis.axis_label = 'Strahlung [W/m²]'
p1.legend.location = 'top_right'
p1.legend.click_policy="hide" # Kurve ein/ausschaltbar
show(p1)
Loading BokehJS ...