1010import numpy as np
1111import pandas as pd
1212from windpowerlib import tools
13+ import os
1314
1415
1516def smooth_power_curve (power_curve_wind_speeds , power_curve_values ,
16- block_width = 0.5 ,
17+ block_width = 0.5 , wind_speed_range = 15.0 ,
1718 standard_deviation_method = 'turbulence_intensity' ,
1819 mean_gauss = 0 , ** kwargs ):
19- # TODO: All functions in this module have to work without pandas
2020 r"""
2121 Smoothes the input power curve values by using a gaussian distribution.
2222
@@ -32,7 +32,7 @@ def smooth_power_curve(power_curve_wind_speeds, power_curve_values,
3232 Width of the moving block. Default: 0.5.
3333 standard_deviation_method : String
3434 Method for calculating the standard deviation for the gaussian
35- distribution. Options: 'turbulence_intensity', 'Norgaard', 'Staffell '.
35+ distribution. Options: 'turbulence_intensity', 'Norgaard', 'Staffell_Pfenninger '.
3636 Default: 'turbulence_intensity'.
3737
3838 Other Parameters
@@ -70,30 +70,28 @@ def smooth_power_curve(power_curve_wind_speeds, power_curve_values,
7070 raise ValueError ("Turbulence intensity must be defined for " +
7171 "using 'turbulence_intensity' as " +
7272 "`standard_deviation_method`" )
73- elif standard_deviation_method == 'Norgaard' :
74- pass # TODO add
75- elif standard_deviation_method == 'Staffell' :
73+ elif standard_deviation_method == 'Staffell_Pfenninger' :
7674 normalized_standard_deviation = 0.2
7775 # Initialize list for power curve values
7876 smoothed_power_curve_values = []
79- # Step of power curve wind speeds
80- step = power_curve_wind_speeds .iloc [- 5 ] - power_curve_wind_speeds .iloc [- 6 ]
81- # Append wind speeds to `power_curve_wind_speeds` until 40 m/s
82- while (power_curve_wind_speeds .values [- 1 ] < 40.0 ):
77+ # Append wind speeds to `power_curve_wind_speeds` until last value + range
78+ maximum_value = power_curve_wind_speeds .values [- 1 ] + wind_speed_range
79+ while (power_curve_wind_speeds .values [- 1 ] < maximum_value ):
8380 power_curve_wind_speeds = power_curve_wind_speeds .append (
84- pd .Series (power_curve_wind_speeds .iloc [- 1 ] + step ,
81+ pd .Series (power_curve_wind_speeds .iloc [- 1 ] + 0.5 ,
8582 index = [power_curve_wind_speeds .index [- 1 ] + 1 ]))
8683 power_curve_values = power_curve_values .append (
8784 pd .Series (0.0 , index = [power_curve_values .index [- 1 ] + 1 ]))
8885 for power_curve_wind_speed in power_curve_wind_speeds :
8986 # Create array of wind speeds for the moving block
90- wind_speeds_block = (
91- np .arange (- 15.0 , 15.0 + block_width , block_width ) +
92- power_curve_wind_speed )
87+ wind_speeds_block = (np .arange (- wind_speed_range ,
88+ wind_speed_range + block_width ,
89+ block_width ) +
90+ power_curve_wind_speed )
9391 # Get standard deviation for gaussian filter
9492 standard_deviation = (
9593 (power_curve_wind_speed * normalized_standard_deviation + 0.6 )
96- if standard_deviation_method is 'Staffell '
94+ if standard_deviation_method is 'Staffell_Pfenninger '
9795 else power_curve_wind_speed * normalized_standard_deviation )
9896 # Get the smoothed value of the power output
9997 smoothed_value = sum (
@@ -113,20 +111,20 @@ def smooth_power_curve(power_curve_wind_speeds, power_curve_values,
113111 smoothed_power_curve_values ]).transpose ()
114112 # Rename columns of DataFrame
115113 smoothed_power_curve_df .columns = ['wind_speed' , 'power' ]
116- # # Plot power curves
117- # fig = plt.figure()
118- # plt.plot(power_curve_wind_speeds.values, power_curve_values.values)
119- # plt.plot(power_curve_wind_speeds.values, smoothed_power_curve_values)
120- # fig.savefig(os.path.abspath(os.path.join(
121- # os.path.dirname(__file__), '../Plots/power_curves',
122- # '{0}_{1}_{2}.png'.format(kwargs['object_name'],
123- # standard_deviation_method, block_width))))
124- # plt.close() # TODO: delete plot later
114+ # # Plot power curves
115+ # fig = plt.figure()
116+ # plt.plot(power_curve_wind_speeds.values, power_curve_values.values)
117+ # plt.plot(power_curve_wind_speeds.values, smoothed_power_curve_values)
118+ # fig.savefig(os.path.abspath(os.path.join(
119+ # os.path.dirname(__file__), '../Plots/power_curves',
120+ # '{0}_{1}_{2}.png'.format(kwargs['object_name'],
121+ # standard_deviation_method, block_width))))
122+ # plt.close() # TODO: delete plot later
125123 return smoothed_power_curve_df
126124
127125
128126def wake_losses_to_power_curve (power_curve_wind_speeds , power_curve_values ,
129- wake_losses_method = 'constant_efficiency ' ,
127+ wake_losses_method = 'wind_efficiency_curve ' ,
130128 wind_farm_efficiency = None ):
131129 r"""
132130 Applies wake losses depending on the method to a power curve.
@@ -141,7 +139,8 @@ def wake_losses_to_power_curve(power_curve_wind_speeds, power_curve_values,
141139 `power_curve_wind_speeds`.
142140 wake_losses_method : String
143141 Defines the method for talking wake losses within the farm into
144- consideration. Default: 'constant_efficiency'.
142+ consideration. Options: 'wind_efficiency_curve', 'constant_efficiency'.
143+ Default: 'wind_efficiency_curve'.
145144 wind_farm_efficiency : Float or pd.DataFrame or Dictionary
146145 Efficiency of the wind farm. Either constant (float) or wind efficiency
147146 curve (pd.DataFrame or Dictionary) contianing 'wind_speed' and
@@ -151,8 +150,9 @@ def wake_losses_to_power_curve(power_curve_wind_speeds, power_curve_values,
151150 Returns
152151 -------
153152 power_curve_df : pd.DataFrame
154- With wind farm efficiency reduced power curve. DataFrame power curve
155- values in W with the corresponding wind speeds in m/s.
153+ With wind farm efficiency reduced power curve. DataFrame has
154+ 'wind_speed' and 'power' columns with wind speeds in m/s and the
155+ corresponding power curve value in W.
156156
157157 Notes
158158 -----
@@ -188,7 +188,85 @@ def wake_losses_to_power_curve(power_curve_wind_speeds, power_curve_values,
188188 power_curve_df .columns = ['wind_speed' , 'power' ]
189189 else :
190190 raise ValueError (
191- "`wake_losses_method` is {0} but should be None, " .format (
191+ "`wake_losses_method` is {0} but should be " .format (
192192 wake_losses_method ) +
193193 "'constant_efficiency' or 'wind_efficiency_curve'" )
194194 return power_curve_df
195+
196+
197+ def density_correct_power_curve (density , power_curve_wind_speeds ,
198+ power_curve_values ):
199+ r"""
200+ Applies a density correction to a power curve.
201+
202+ As site specific density a mean density has to be given as parameter.
203+
204+ Parameters
205+ ----------
206+ density : float
207+ Mean density of air at hub height in kg/m³.
208+ power_curve_wind_speeds : pandas.Series or numpy.array
209+ Wind speeds in m/s for which the power curve values are provided in
210+ `power_curve_values`.
211+ power_curve_values : pandas.Series or numpy.array
212+ Power curve values corresponding to wind speeds in
213+ `power_curve_wind_speeds`.
214+
215+ Returns
216+ -------
217+ power_curve_df : pd.DataFrame
218+ Density corrected power curve. DataFrame has 'wind_speed' and 'power'
219+ columns with wind speeds in m/s and the corresponding power curve
220+ value in W.
221+
222+ Notes
223+ -----
224+ The following equation is used for the site specific power curve wind
225+ speeds [1]_, [2]_, [3]_:
226+
227+ .. math:: v_{site}=v_{std}\cdot\left(\frac{\rho_0}
228+ {\rho_{site}}\right)^{p(v)}
229+
230+ with:
231+ .. math:: p=\begin{cases}
232+ \frac{1}{3} & v_{std} \leq 7.5\text{ m/s}\\
233+ \frac{1}{15}\cdot v_{std}-\frac{1}{6} & 7.5
234+ \text{ m/s}<v_{std}<12.5\text{ m/s}\\
235+ \frac{2}{3} & \geq 12.5 \text{ m/s}
236+ \end{cases},
237+ v: wind speed [m/s], :math:`\rho`: density [kg/m³]
238+
239+ :math:`v_{std}` is the standard wind speed in the power curve
240+ (:math:`v_{std}`, :math:`P_{std}`),
241+ :math:`v_{site}` is the density corrected wind speed for the power curve
242+ (:math:`v_{site}`, :math:`P_{std}`),
243+ :math:`\rho_0` is the ambient density (1.225 kg/m³)
244+ and :math:`\rho_{site}` the density at site conditions (and hub height).
245+
246+ It is assumed that the power output for wind speeds above the maximum
247+ and below the minimum wind speed given in the power curve is zero.
248+
249+ References
250+ ----------
251+ .. [1] Svenningsen, L.: "Power Curve Air Density Correction And Other
252+ Power Curve Options in WindPRO". 1st edition, Aalborg,
253+ EMD International A/S , 2010, p. 4
254+ .. [2] Svenningsen, L.: "Proposal of an Improved Power Curve Correction".
255+ EMD International A/S , 2010
256+ .. [3] Biank, M.: "Methodology, Implementation and Validation of a
257+ Variable Scale Simulation Model for Windpower based on the
258+ Georeferenced Installation Register of Germany". Master's Thesis
259+ at Reiner Lemoine Institute, 2014, p. 13
260+
261+ """
262+ if density is None :
263+ raise TypeError ("`density` is None. For the calculation with a " +
264+ "density corrected power curve mean density at hub " +
265+ "height is needed." )
266+ corrected_power_curve_wind_speeds = (
267+ power_curve_wind_speeds * (1.225 / density ) ** (
268+ np .interp (power_curve_wind_speeds , [7.5 , 12.5 ], [1 / 3 , 2 / 3 ])))
269+ power_curve_df = pd .DataFrame ([corrected_power_curve_wind_speeds ,
270+ power_curve_values ]).transpose ()
271+ power_curve_df .columns = ['wind_speed' , 'power' ]
272+ return power_curve_df
0 commit comments