Source code for windpowerlib.basicmodel

import os
import sys
import logging
import numpy as np
import pandas as pd


[docs]class SimpleWindTurbine: r"""Model to determine the output of a wind turbine Parameters ---------- wind_conv_type : string Name of the wind converter type. Use get_wind_pp_types() to see a list of all possible wind converters. h_hub : float Height of the hub of the wind turbine. d_rotor : float Diameter of the rotor. cp_values : pandas.DataFrame The index should be the wind speed and a column should be named 'cp'. nominal_power : float The nominal output of the wind power plant. Attributes ---------- wind_conv_type : string Name of the wind converter type. Use get_wind_pp_types() to see a list of all possible wind converters. h_hub : float Height of the hub of the wind turbine. d_rotor : float Diameter of the rotor. cp_values : pandas.DataFrame The index should be the wind speed and a column should be named 'cp'. nominal_power : float The nominal output of the wind power plant. Examples -------- >>> from windpowerlib import basicmodel >>> enerconE126 = { ... 'h_hub': 135, ... 'd_rotor': 127, ... 'wind_conv_type': 'ENERCON E 126 7500'} >>> e126 = basicmodel.SimpleWindTurbine(**enerconE126) >>> print(e126.d_rotor) 127 """ def __init__(self, wind_conv_type=None, h_hub=None, d_rotor=None, cp_values=None, nominal_power=None): self.h_hub = h_hub self.d_rotor = d_rotor self.wind_conv_type = wind_conv_type self.cp_values = cp_values self.nominal_power = nominal_power if cp_values is None or nominal_power is None: wpp_data = self.fetch_wpp_data() if cp_values is None: self.cp_values = wpp_data[0] if nominal_power is None: self.nominal_power = wpp_data[1]
[docs] def rho_hub(self, weather, data_height): r""" Calculates the density of air in kg/m³ at hub height. (temperature in K, height in m, pressure in Pa) Parameters ---------- weather : DataFrame or Dictionary Containing columns or keys with the timeseries for Temperature (temp_air) and pressure (pressure). data_height : DataFrame or Dictionary Containing columns or keys with the height of the measurement or model data for temperature (temp_air) and pressure (pressure). Returns ------- float density of air in kg/m³ at hub height Notes ----- Assumptions: * Temperature gradient of -6.5 K/km * Pressure gradient of -1/8 hPa/m The following equations are used [22]_: .. math:: T_{hub}=T_{air, data}-0.0065\cdot\left(h_{hub}-h_{T,data} \right) .. math:: p_{hub}=\left(p_{data}/100-\left(h_{hub}-h_{p,data}\right) *\frac{1}{8}\right)/\left(2.8706\cdot T_{hub}\right) with T: temperature [K], h: height [m], p: pressure [Pa] ToDo: Check the equation and add references. References ---------- .. [22] ICAO-Standardatmosphäre (ISA). http://www.deutscher-wetterdienst.de/lexikon/download.php?file=Standardatmosphaere.pdf See Also -------- v_wind_hub """ h_temperature_data = data_height['temp_air'] h_pressure_data = data_height['pressure'] temperature_hub = weather.temp_air - 0.0065 * ( self.h_hub - h_temperature_data) return ( weather.pressure / 100 - (self.h_hub - h_pressure_data) * 1 / 8 ) / (2.8706 * temperature_hub)
[docs] def v_wind_hub(self, weather, data_height): r""" Calculates the wind speed in m/s at hub height. Parameters ---------- weather : DataFrame or Dictionary Containing columns or keys with the timeseries for wind speed (v_wind) and roughness length (z0). data_height : DataFrame or Dictionary Containing columns or keys with the height of the measurement or model data for temperature (temp_air) and pressure (pressure). Returns ------- float wind speed [m/s] at hub height Notes ----- The following equation is used for the logarithmic wind profile [20]_: .. math:: v_{wind,hub}=v_{wind,data}\cdot\frac{\ln\left(\frac{h_{hub}} {z_{0}}\right)}{\ln\left(\frac{h_{data}}{z_{0}}\right)} with: v: wind speed [m/s], h: height [m], z0: roughness length [m] :math:`h_{data}` is the height in which the wind velocity is measured. (height in m, velocity in m/s) ToDo: Check the equation and add references. References ---------- .. [20] Gasch R., Twele J.: "Windkraftanlagen". 6. Auflage, Wiesbaden, Vieweg + Teubner, 2010, page 129 See Also -------- rho_hub """ return (weather.v_wind * np.log(self.h_hub / weather.z0) / np.log(data_height['v_wind'] / weather.z0))
[docs] def fetch_wpp_data(self, **kwargs): r""" Fetch data of the requested wind converter. Returns ------- tuple with pandas.DataFrame and float cp values and the nominal power of the requested wind converter Examples -------- >>> from windpowerlib import basicmodel >>> e126 = basicmodel.SimpleWindTurbine('ENERCON E 126 7500') >>> print(e126.cp_values.cp[5.0]) 0.423 >>> print(e126.nominal_power) 7500000.0 """ df = read_wpp_data(**kwargs) wpp_df = df[df.rli_anlagen_id == self.wind_conv_type] if wpp_df.shape[0] == 0: pd.set_option('display.max_rows', len(df)) logging.info('Possible types: \n{0}'.format(df.rli_anlagen_id)) pd.reset_option('display.max_rows') sys.exit('Cannot find the wind converter typ: {0}'.format( self.wind_conv_type)) ncols = ['rli_anlagen_id', 'p_nenn', 'source', 'modificationtimestamp'] cp_data = np.array([0, 0]) for col in wpp_df.keys(): if col not in ncols: if wpp_df[col].iloc[0] is not None and not np.isnan( float(wpp_df[col].iloc[0])): cp_data = np.vstack((cp_data, np.array( [float(col), float(wpp_df[col])]))) cp_data = np.delete(cp_data, 0, 0) cp_df = pd.DataFrame(cp_data, columns=['v_wind', 'cp']) cp_df.set_index('v_wind', drop=True, inplace=True) nominal_power = wpp_df['p_nenn'].iloc[0] * 1000 return cp_df, nominal_power
[docs] def cp_series(self, v_wind): r""" Interpolates the cp value as a function of the wind velocity between data obtained from the power curve of the specified wind turbine type. Parameters ---------- v_wind : pandas.Series or numpy.array Wind speed at hub height [m/s] Returns ------- numpy.array cp values, wind converter type, installed capacity >>> import numpy >>> from windpowerlib import basicmodel >>> e126 = basicmodel.SimpleWindTurbine('ENERCON E 126 7500') >>> v_wind = numpy.array([1,2,3,4,5,6,7,8]) >>> print(e126.cp_series(v_wind)) [ 0. 0. 0.191 0.352 0.423 0.453 0.47 0.478] """ v_max = self.cp_values.index.max() v_wind[v_wind > v_max] = v_max return np.interp(v_wind, self.cp_values.index, self.cp_values.cp)
[docs] def turbine_power_output(self, weather, data_height): r""" Calculates the power output in W of one wind turbine. Parameters ---------- weather : feedinlib.weather.FeedinWeather object Instance of the feedinlib weather object (see class :py:class:`FeedinWeather<feedinlib.weather.FeedinWeather>` for more details) data_height : dictionary Containing the heights of the weather measurements or weather model in meters with the keys of the data parameter # TODO Move the following parameters to a better place :-) Returns ------- pandas.Series Electrical power of the wind turbine Notes ----- The following equation is used for the power output :math:`P_{wpp}` [21]_: .. math:: P_{wpp}=\frac{1}{8}\cdot\rho_{air,hub}\cdot d_{rotor}^{2} \cdot\pi\cdot v_{wind}^{3}\cdot cp\left(v_{wind}\right) with: v: wind speed [m/s], d: diameter [m], :math:`\rho`: density [kg/m³] ToDo: Check the equation and add references. References ---------- .. [21] Gasch R., Twele J.: "Windkraftanlagen". 6. Auflage, Wiesbaden, Vieweg + Teubner, 2010, pages 35ff, 208 """ if self.h_hub is None: logging.error("Attribute h_hub (hub height) is missing.") exit(0) if self.d_rotor is None: logging.error("Attribute d_rotor (diameter of rotor) is missing.") exit(0) p_wpp = ( (self.rho_hub(weather, data_height) / 2) * (((self.d_rotor / 2) ** 2) * np.pi) * np.power(self.v_wind_hub(weather, data_height), 3) * self.cp_series(self.v_wind_hub(weather, data_height))) p_wpp_series = pd.Series(data=p_wpp, index=weather.index, name='feedin_wind_pp') p_wpp_series.index.names = [''] return p_wpp_series.clip(upper=(float(self.nominal_power)))
[docs]def read_wpp_data(**kwargs): r""" Fetch cp values from a file or download it from a server. The files are located in the data folder of the package root. Returns ------- pandas.DataFrame cp values, wind converter type, installed capacity or the full table if the given wind converter cannot be found in the table. Other Parameters ---------------- datapath : string, optional Path where the cp file is stored. Default: '$PACKAGE_ROOT/data' filename : string, optional Filename of the cp file. """ if 'datapath' not in kwargs: kwargs['datapath'] = os.path.join(os.path.dirname(__file__), 'data') if 'filename' not in kwargs: kwargs['filename'] = 'cp_values.csv' cp_file = os.path.join(kwargs['datapath'], kwargs['filename']) df = pd.read_csv(cp_file, index_col=0) return df
[docs]def get_wind_pp_types(print_out=True): r""" Get the names of all possible wind converter types. Parameters ---------- print_out : boolean (default: True) Directly prints the list of types if set to True. Examples -------- >>> from windpowerlib import basicmodel >>> valid_types_df = basicmodel.get_wind_pp_types(print_out=False) >>> valid_types_df.shape (91, 2) >>> print(valid_types_df.iloc[5]) rli_anlagen_id DEWIND D8 2000 p_nenn 2000 Name: 5, dtype: object """ df = read_wpp_data() if print_out: pd.set_option('display.max_rows', len(df)) print(df[['rli_anlagen_id', 'p_nenn']]) pd.reset_option('display.max_rows') return df[['rli_anlagen_id', 'p_nenn']]
if __name__ == "__main__": import doctest doctest.testmod()