Skip to content

Commit 4831e0b

Browse files
committed
Merge branch 'features/wind_farms_and_clusters' into dev
2 parents 1ec47ab + cd1f0c9 commit 4831e0b

File tree

6 files changed

+460
-281
lines changed

6 files changed

+460
-281
lines changed

windpowerlib/cluster.py

Lines changed: 0 additions & 35 deletions
This file was deleted.

windpowerlib/power_curve.py

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
"""
2+
The ``power_curves`` module contains functions apply calculations to the power
3+
curve of a wind turbine, wind farm or wind turbine cluster.
4+
5+
"""
6+
7+
__copyright__ = "Copyright oemof developer group"
8+
__license__ = "GPLv3"
9+
10+
import numpy as np
11+
import pandas as pd
12+
from windpowerlib import tools
13+
from matplotlib import pyplot as plt
14+
import os
15+
16+
17+
def smooth_power_curve(power_curve_wind_speeds, power_curve_values,
18+
block_width=0.5,
19+
standard_deviation_method='turbulence_intensity',
20+
mean_gauss=0, **kwargs):
21+
# TODO: All functions in this module have to work without pandas
22+
r"""
23+
Smoothes the input power curve values by using a gaussian distribution.
24+
25+
Parameters
26+
----------
27+
power_curve_wind_speeds : pandas.Series
28+
Wind speeds in m/s for which the power curve values are provided in
29+
`power_curve_values`.
30+
power_curve_values : pandas.Series or numpy.array
31+
Power curve values corresponding to wind speeds in
32+
`power_curve_wind_speeds`.
33+
block_width : Float
34+
Width of the moving block. Default: 0.5.
35+
standard_deviation_method : String
36+
Method for calculating the standard deviation for the gaussian
37+
distribution. Options: 'turbulence_intensity', 'Norgaard', 'Staffell'.
38+
Default: 'turbulence_intensity'.
39+
40+
Other Parameters
41+
----------------
42+
turbulence intensity : Float, optional
43+
Turbulence intensity at hub height of the wind turbine the power curve
44+
is smoothed for.
45+
46+
Returns
47+
-------
48+
smoothed_power_curve_df : pd.DataFrame
49+
Smoothed power curve. DataFrame has 'wind_speed' and
50+
'power' columns with wind speeds in m/s and the corresponding power
51+
curve value in W.
52+
53+
Notes
54+
-----
55+
The following equation is used [1]_:
56+
# TODO: add equation
57+
58+
References
59+
----------
60+
.. [1] Knorr, K.: "Modellierung von raum-zeitlichen Eigenschaften der
61+
Windenergieeinspeisung für wetterdatenbasierte
62+
Windleistungssimulationen". Universität Kassel, Diss., 2016,
63+
p. 106
64+
65+
# TODO: add references
66+
"""
67+
# Specify normalized standard deviation
68+
if standard_deviation_method == 'turbulence_intensity':
69+
if 'turbulence_intensity' in kwargs:
70+
normalized_standard_deviation = kwargs['turbulence_intensity']
71+
else:
72+
raise ValueError("Turbulence intensity must be defined for " +
73+
"using 'turbulence_intensity' as " +
74+
"`standard_deviation_method`")
75+
elif standard_deviation_method == 'Norgaard':
76+
pass # TODO add
77+
elif standard_deviation_method == 'Staffell':
78+
normalized_standard_deviation = 0.2
79+
# Initialize list for power curve values
80+
smoothed_power_curve_values = []
81+
# Step of power curve wind speeds
82+
step = power_curve_wind_speeds.iloc[-5] - power_curve_wind_speeds.iloc[-6]
83+
# Append wind speeds to `power_curve_wind_speeds` until 40 m/s
84+
while (power_curve_wind_speeds.values[-1] < 40.0):
85+
power_curve_wind_speeds = power_curve_wind_speeds.append(
86+
pd.Series(power_curve_wind_speeds.iloc[-1] + step,
87+
index=[power_curve_wind_speeds.index[-1] + 1]))
88+
power_curve_values = power_curve_values.append(
89+
pd.Series(0.0, index=[power_curve_values.index[-1] + 1]))
90+
for power_curve_wind_speed in power_curve_wind_speeds:
91+
# Create array of wind speeds for the moving block
92+
wind_speeds_block = (
93+
np.arange(-15.0, 15.0 + block_width, block_width) +
94+
power_curve_wind_speed)
95+
# Get standard deviation for gaussian filter
96+
standard_deviation = (
97+
(power_curve_wind_speed * normalized_standard_deviation + 0.6)
98+
if standard_deviation_method is 'Staffell'
99+
else power_curve_wind_speed * normalized_standard_deviation)
100+
# Get the smoothed value of the power output
101+
smoothed_value = sum(
102+
block_width * np.interp(wind_speed, power_curve_wind_speeds,
103+
power_curve_values, left=0, right=0) *
104+
tools.gaussian_distribution(
105+
power_curve_wind_speed - wind_speed,
106+
standard_deviation, mean_gauss)
107+
for wind_speed in wind_speeds_block)
108+
# Add value to list - add 0 if `smoothed_value` is nan. This occurs
109+
# because the gaussian distribution is not defined for 0.
110+
smoothed_power_curve_values.append(0 if np.isnan(smoothed_value)
111+
else smoothed_value)
112+
# Create smoothed power curve DataFrame
113+
smoothed_power_curve_df = pd.DataFrame(
114+
data=[list(power_curve_wind_speeds.values),
115+
smoothed_power_curve_values]).transpose()
116+
# Rename columns of DataFrame
117+
smoothed_power_curve_df.columns = ['wind_speed', 'power']
118+
# # Plot power curves
119+
# fig = plt.figure()
120+
# plt.plot(power_curve_wind_speeds.values, power_curve_values.values)
121+
# plt.plot(power_curve_wind_speeds.values, smoothed_power_curve_values)
122+
# fig.savefig(os.path.abspath(os.path.join(
123+
# os.path.dirname(__file__), '../Plots/power_curves',
124+
# '{0}_{1}_{2}.png'.format(kwargs['object_name'],
125+
# standard_deviation_method, block_width))))
126+
# plt.close() # TODO: delete plot later
127+
return smoothed_power_curve_df
128+
129+
130+
def wake_losses_to_power_curve(power_curve_wind_speeds, power_curve_values,
131+
wake_losses_method='constant_efficiency',
132+
wind_farm_efficiency=None):
133+
r"""
134+
Applies wake losses depending on the method to a power curve.
135+
136+
Parameters
137+
----------
138+
power_curve_wind_speeds : pandas.Series
139+
Wind speeds in m/s for which the power curve values are provided in
140+
`power_curve_values`.
141+
power_curve_values : pandas.Series or numpy.array
142+
Power curve values corresponding to wind speeds in
143+
`power_curve_wind_speeds`.
144+
wake_losses_method : String
145+
Defines the method for talking wake losses within the farm into
146+
consideration. Default: 'constant_efficiency'.
147+
wind_farm_efficiency : Float or pd.DataFrame or Dictionary
148+
Efficiency of the wind farm. Either constant (float) or wind efficiency
149+
curve (pd.DataFrame or Dictionary) contianing 'wind_speed' and
150+
'efficiency' columns/keys with wind speeds in m/s and the
151+
corresponding dimensionless wind farm efficiency. Default: None.
152+
153+
Returns
154+
-------
155+
power_curve_df : pd.DataFrame
156+
With wind farm efficiency reduced power curve. DataFrame power curve
157+
values in W with the corresponding wind speeds in m/s.
158+
159+
Notes
160+
-----
161+
TODO add
162+
163+
"""
164+
# Create power curve DataFrame
165+
power_curve_df = pd.DataFrame(
166+
data=[list(power_curve_wind_speeds),
167+
list(power_curve_values)]).transpose()
168+
# Rename columns of DataFrame
169+
power_curve_df.columns = ['wind_speed', 'power']
170+
if wake_losses_method == 'constant_efficiency':
171+
if not isinstance(wind_farm_efficiency, float):
172+
raise TypeError("'wind_farm_efficiency' must be float if " +
173+
"`wake_losses_method´ is '{0}'")
174+
power_curve_df['power'] = power_curve_values * wind_farm_efficiency
175+
elif wake_losses_method == 'wind_efficiency_curve':
176+
if (not isinstance(wind_farm_efficiency, dict) and
177+
not isinstance(wind_farm_efficiency, pd.DataFrame)):
178+
raise TypeError(
179+
"'wind_farm_efficiency' must be a dictionary or " +
180+
"pd.DataFrame if `wake_losses_method´ is '{0}'")
181+
df = pd.concat([power_curve_df.set_index('wind_speed'),
182+
wind_farm_efficiency.set_index('wind_speed')], axis=1)
183+
# Add by efficiency reduced power column (nan values of efficiency
184+
# are interpolated)
185+
df['reduced_power'] = df['power'] * df['efficiency'].interpolate(
186+
method='index')
187+
reduced_power = df['reduced_power'].dropna()
188+
power_curve_df = pd.DataFrame([reduced_power.index,
189+
reduced_power.values]).transpose()
190+
power_curve_df.columns = ['wind_speed', 'power']
191+
else:
192+
raise ValueError(
193+
"`wake_losses_method` is {0} but should be None, ".format(
194+
wake_losses_method) +
195+
"'constant_efficiency' or 'wind_efficiency_curve'")
196+
return power_curve_df

0 commit comments

Comments
 (0)