Skip to content

power_curve

Classes:

  • PowerCurve

    Creates a wind turbine's power curve represented by a set of (wind-speed,capacity-factor) pairs.

Functions:

  • compute_specific_power

    Calculates the corresponding specific power for a wind turbine in W/m2 from values of capacity in kW and rotor diameter in m.

  • synthetic_power_curve_data

    Reads the data used for creating a synthetic power curve.

PowerCurve

PowerCurve(wind_speed, capacity_factor)

Creates a wind turbine's power curve represented by a set of (wind-speed,capacity-factor) pairs.

Initialization:

Returns:

  • PowerCurve object

Methods:

  • apply_loss_factor

    Applies a loss factor onto the power curve. It can be a single value, or a function which takes a 'capacity factor' array as input.

  • convolute_by_gaussian

    Convolutes a turbine power curve by a normal distribution function with wind-speed-dependent standard deviation.

  • expected_capacity_factor_from_distribution

    Computes the expected average capacity factor of a wind turbine based on an explicitly-provided wind speed distribution

  • expected_capacity_factor_from_weibull

    Computes the expected average capacity factor of a wind turbine based on a Weibull distribution of wind speeds.

  • from_capacity_and_rotor_diam

    Creates a synthetic wind turbine power curve based on observed relationships between turbine's capacity, rotor diameter and known power curves according to Ryberg et al. [1].

  • from_specific_power

    Creates a synthetic wind turbine power curve based on observed relationships between turbine specific power and known power curves according to Ryberg et al. [1].

  • simulate

    Applies the invoking power curve to the given wind speeds.

Source code in reskit/wind/core/power_curve.py
def __init__(self, wind_speed, capacity_factor):
    self.wind_speed = np.array(wind_speed)
    self.capacity_factor = np.array(capacity_factor)

apply_loss_factor

apply_loss_factor(loss)

Applies a loss factor onto the power curve. It can be a single value, or a function which takes a 'capacity factor' array as input.

Parameters:

  • loss

    (numeric or function) –

    If numeric, the value is applied at all capacity factors with: new_capacity_factors = [1-loss] * previous_capacity_factors If a function, it must take a numpy array representing capacity factor values as input, resulting in the equation: new_capacity_factors = [1-loss(previous_capacity_factors)] * previous_capacity_factors

Returns:

Source code in reskit/wind/core/power_curve.py
def apply_loss_factor(self, loss):
    """
    Applies a loss factor onto the power curve. It can be a single value, or a function which takes a 'capacity factor' array as input.

    Parameters
    ----------
    loss : numeric or function
        If numeric, the value is applied at all capacity factors with:
            new_capacity_factors = [1-loss] * previous_capacity_factors
        If a function, it must take a numpy array representing capacity factor values as input, resulting in the equation:
            new_capacity_factors = [1-loss(previous_capacity_factors)] * previous_capacity_factors

    Returns
    -------
    PowerCurve
        The corrected power curve.

    """
    try:
        cf = self.capacity_factor * (1 - loss)
    except:
        cf = self.capacity_factor * (1 - loss(self.capacity_factor))

    return PowerCurve(self.wind_speed, cf)

convolute_by_gaussian

convolute_by_gaussian(
    scaling=0.06,
    base=0.1,
    extend_beyond_cut_out=True,
    _min_speed=0.01,
    _max_speed=40,
    _steps=4000,
)

Convolutes a turbine power curve by a normal distribution function with wind-speed-dependent standard deviation.

Parameters:

  • scaling

    (float, default: 0.06 ) –

    scaling factor, by default 0.06

  • base

    (float, default: 0.1 ) –

    base value, by default 0.1

  • extend_beyond_cut_out

    (bool, default: True ) –

    extend the estimation beyond the turbine's cut out wind speed, by default True

  • _min_speed

    (float, default: 0.01 ) –

    minimum wind speed value in m/s to be considered, by default 0.01

  • _max_speed

    (int, default: 40 ) –

    maximum wind speed value in m/s to be considered, by default 40

  • _steps

    (int, default: 4000 ) –

    number of steps in between the wind speed range, by default 4000

Returns:

  • PowerCurve

    The resulting convoluted power curve

Notes

The wind-speed-dependent standard deviation is computed with: std = wind_speed * scaling + base

Source code in reskit/wind/core/power_curve.py
def convolute_by_gaussian(
    self,
    scaling=0.06,
    base=0.1,
    extend_beyond_cut_out=True,
    _min_speed=0.01,
    _max_speed=40,
    _steps=4000,
):
    """
    Convolutes a turbine power curve by a normal distribution function with wind-speed-dependent standard deviation.

    Parameters
    ----------
    scaling : float, optional
        scaling factor, by default 0.06

    base : float, optional
        base value, by default 0.1

    extend_beyond_cut_out : bool, optional
        extend the estimation beyond the turbine's cut out wind speed, by default True

    _min_speed : float, optional
        minimum wind speed value in m/s to be considered, by default 0.01

    _max_speed : int, optional
        maximum wind speed value in m/s to be considered, by default 40

    _steps : int, optional
        number of steps in between the wind speed range, by default 4000

    Returns
    -------
    PowerCurve
        The resulting convoluted power curve

    Notes
    -----
    The wind-speed-dependent standard deviation is computed with: std = wind_speed * scaling + base

    """
    # Initialize windspeed axis
    ws = np.linspace(_min_speed, _max_speed, _steps)
    dws = ws[1] - ws[0]

    # check if we have enough resolution
    tmp = (scaling * 5 + base) / dws
    if tmp < 1.0:  # manually checked threshold
        if tmp < 0.25:  # manually checked threshold
            raise ResError("Insufficient number of 'steps'")
        else:
            print(
                "WARNING: 'steps' may not be high enough to properly compute the convoluted power curve. Check results or use a higher number of steps"
            )

    # Initialize vanilla power curve
    selfInterp = splrep(ws, np.interp(ws, self.wind_speed, self.capacity_factor))

    cf = np.zeros(_steps)
    sel = ws < self.wind_speed.max()
    cf[sel] = splev(ws[sel], selfInterp)

    # set all windspeed less than cut-in speed to 0
    cf[ws < self.wind_speed.min()] = 0
    # set all windspeed greater than cut-out speed to 0 (just in case)
    cf[ws > self.wind_speed.max()] = 0
    cf[cf < 0] = 0  # force a floor of 0
    # cf[cf>self[:,1].max()] = self[:,1].max() # force a ceiling of the max capacity

    # Begin convolution
    convolutedCF = np.zeros(_steps)
    for i, ws_ in enumerate(ws):
        convolutedCF[i] = (norm.pdf(ws, loc=ws_, scale=scaling * ws_ + base) * cf).sum() * dws

    # Correct cutoff, maybe
    if not extend_beyond_cut_out:
        convolutedCF[ws > self.wind_speed[-1]] = 0

    # Done!
    ws = ws[::40]
    convolutedCF = convolutedCF[::40]
    return PowerCurve(ws, convolutedCF)

expected_capacity_factor_from_distribution

expected_capacity_factor_from_distribution(
    wind_speed_values, wind_speed_counts
)

Computes the expected average capacity factor of a wind turbine based on an explicitly-provided wind speed distribution

Parameters:

  • wind_speed_values

    (numeric or array - like) –

    wind speed values in m/s

  • wind_speed_counts

    (numeric or array - like) –

    corresponding counts (number of occurrence) of the given wind speed values. Counts will be normalized within the function

Example
pc.expected_capacity_factor_from_distribution(
    wind_speed_values=[  1,   2,   3,   4,   5,      6], # Units of m/s
    wind_speed_counts=[0.1, 0.3, 0.5, 0.3, 0.1, 0.025 ]  # Units of "counts"
    )

Returns:

  • numeric

    Average capacity factor

See Also
PowerCurve.expected_capacity_factor_from_weibull
Source code in reskit/wind/core/power_curve.py
def expected_capacity_factor_from_distribution(self, wind_speed_values, wind_speed_counts):
    """
    Computes the expected average capacity factor of a wind turbine based on an explicitly-provided wind speed distribution

    Parameters
    ----------
    wind_speed_values : numeric or array-like
        wind speed values in m/s

    wind_speed_counts : numeric or array-like
        corresponding counts (number of occurrence) of the given wind speed values.
        Counts will be normalized within the function

    Example
    -------
        pc.expected_capacity_factor_from_distribution(
            wind_speed_values=[  1,   2,   3,   4,   5,      6], # Units of m/s
            wind_speed_counts=[0.1, 0.3, 0.5, 0.3, 0.1, 0.025 ]  # Units of "counts"
            )

    Returns
    -------
    numeric
        Average capacity factor

    See Also
    --------
        PowerCurve.expected_capacity_factor_from_weibull

    """
    wind_speed_values = np.array(wind_speed_values)
    wind_speed_counts = np.array(wind_speed_counts)

    if not len(wind_speed_values.shape) == 1:
        raise ResError("wind_speed_values must be 1-dimensional")

    # Handle 2 dimensional counts with 1 dimensional wind speeds
    if len(wind_speed_counts.shape) > 1:
        if not wind_speed_counts.shape[0] == wind_speed_values.shape[0]:
            raise ResError("Dimensional incompatibility")

        wind_speed_values = np.reshape(wind_speed_values, (wind_speed_counts.shape[0], 1))

    # Estimate generation distribution
    gen = (
        np.interp(
            wind_speed_values,
            self.wind_speed,
            self.capacity_factor,
            left=0,
            right=0,
        )
        * wind_speed_counts
    )

    meanGen = gen.sum(0) / wind_speed_counts.sum(0)

    # Done
    return meanGen

expected_capacity_factor_from_weibull

expected_capacity_factor_from_weibull(
    mean_wind_speed=5, weibull_shape=2
)

Computes the expected average capacity factor of a wind turbine based on a Weibull distribution of wind speeds.

Parameters:

  • mean_wind_speed

    (int, default: 5 ) –

    mean wind speed at the location in m/s, by default 5

  • weibull_shape

    (int, default: 2 ) –

    Weibull shape parameter, by default 2

Returns:

  • numeric

    Average capacity factor

See Also
PowerCurve.expected_capacity_factor_from_distribution
Source code in reskit/wind/core/power_curve.py
def expected_capacity_factor_from_weibull(self, mean_wind_speed=5, weibull_shape=2):
    """
    Computes the expected average capacity factor of a wind turbine based on a Weibull distribution of wind speeds.

    Parameters
    ----------
    mean_wind_speed : int, optional
        mean wind speed at the location in m/s, by default 5

    weibull_shape : int, optional
        Weibull shape parameter, by default 2

    Returns
    -------
    numeric
        Average capacity factor

    See Also
    --------
        PowerCurve.expected_capacity_factor_from_distribution

    """
    from scipy.special import gamma
    from scipy.stats import exponweib

    # Get windspeed distribution
    lam = mean_wind_speed / gamma(1 + 1 / weibull_shape)
    dws = 0.001
    ws = np.arange(0, 40, dws)
    pdf = exponweib.pdf(ws, 1, weibull_shape, scale=lam)

    # Estimate generation
    power_curveInterp = splrep(self.wind_speed, self.capacity_factor)
    gen = splev(ws, power_curveInterp)

    # Do some "just in case" clean-up
    cutin = self.wind_speed.min()  # use the first defined windspeed as the cut in
    cutout = self.wind_speed.max()  # use the last defined windspeed as the cut out

    gen[gen < 0] = 0  # floor to zero

    gen[ws < cutin] = 0  # Drop power to zero before cutin
    gen[ws > cutout] = 0  # Drop power to zero after cutout

    # Done
    meanCapFac = (gen * pdf).sum() * dws
    return meanCapFac

from_capacity_and_rotor_diam staticmethod

from_capacity_and_rotor_diam(
    capacity, rotor_diam, cutout=25
)

Creates a synthetic wind turbine power curve based on observed relationships between turbine's capacity, rotor diameter and known power curves according to Ryberg et al. [1].

Parameters:

  • capacity

    (numeric) –

    Baseline turbine capacity in kW.

  • rotor_diam

    (numeric) –

    turbine rotor diameter in m

  • cutout

    (int, default: 25 ) –

    Cut out wind speed in m/s, by default 25

Returns:

Sources

[1] Ryberg, D. S., Caglayan, D. G., Schmitt, S., Linßen, J., Stolten, D., & Robinius, M. (2019). The future of European onshore wind energy potential: Detailed distribution and simulation of advanced turbine designs. Energy. https://doi.org/10.1016/j.energy.2019.06.052

See Also
PowerCurve.from_specific_power( <turbine specific power> )
Source code in reskit/wind/core/power_curve.py
@staticmethod
def from_capacity_and_rotor_diam(capacity, rotor_diam, cutout=25):
    """
    Creates a synthetic wind turbine power curve based on observed relationships between turbine's capacity, rotor diameter and known power curves according to Ryberg et al. [1].

    Parameters
    ----------
    capacity : numeric
        Baseline turbine capacity in kW.

    rotor_diam : numeric
        turbine rotor diameter in m

    cutout : int, optional
        Cut out wind speed in m/s, by default 25

    Returns
    -------
    PowerCurve

    Sources
    -------
    [1] Ryberg, D. S., Caglayan, D. G., Schmitt, S., Linßen, J., Stolten, D., & Robinius, M. (2019). The future of European onshore wind energy potential: Detailed distribution and simulation of advanced turbine designs. Energy. https://doi.org/10.1016/j.energy.2019.06.052

    See Also
    --------
        PowerCurve.from_specific_power( <turbine specific power> )
    """
    return PowerCurve.from_specific_power(compute_specific_power(capacity, rotor_diam))

from_specific_power staticmethod

from_specific_power(specific_power, cutout=25)

Creates a synthetic wind turbine power curve based on observed relationships between turbine specific power and known power curves according to Ryberg et al. [1].

Parameters:

  • specific_power

    (float) –

    Turbines's specific power in m/s

  • cutout

    (int, default: 25 ) –

    Cut out wind speed in m/s, by default 25

Returns:

Sources

[1] Ryberg, D. S., Caglayan, D. G., Schmitt, S., Linßen, J., Stolten, D., & Robinius, M. (2019). The future of European onshore wind energy potential: Detailed distribution and simulation of advanced turbine designs. Energy. https://doi.org/10.1016/j.energy.2019.06.052

See Also
PowerCurve.from_capacity_and_rotor_diam( <turbine capacity>, <turbine rotor diameter> )
Source code in reskit/wind/core/power_curve.py
@staticmethod
def from_specific_power(specific_power, cutout=25):
    """
    Creates a synthetic wind turbine power curve based on observed relationships between turbine specific power and known power curves according to Ryberg et al. [1].

    Parameters
    ----------
    specific_power : float
        Turbines's specific power in m/s

    cutout : int, optional
        Cut out wind speed in m/s, by default 25

    Returns
    -------
    PowerCurve

    Sources
    -------
    [1] Ryberg, D. S., Caglayan, D. G., Schmitt, S., Linßen, J., Stolten, D., & Robinius, M. (2019). The future of European onshore wind energy potential: Detailed distribution and simulation of advanced turbine designs. Energy. https://doi.org/10.1016/j.energy.2019.06.052

    See Also
    --------
        PowerCurve.from_capacity_and_rotor_diam( <turbine capacity>, <turbine rotor diameter> )
    """
    # Create ws
    ws = [
        0,
    ]

    spcd = synthetic_power_curve_data()

    ws.extend(np.exp(spcd.const + spcd.scale * np.log(specific_power)))
    ws.extend(np.linspace(ws[-1], cutout, 20)[1:])
    ws = np.array(ws)

    # create capacity factor output
    cf = [
        0,
    ]
    cf.extend(spcd.perc_capacity / 100)
    cf.extend([1] * 19)
    cf = np.array(cf)

    # Done!
    return PowerCurve(ws, cf)

simulate

simulate(wind_speed)

Applies the invoking power curve to the given wind speeds.

Parameters:

  • wind_speed

    (array_like) –

    Local average wind speed close to or at the hub height.

Returns:

  • array_like

    CorrespongDing capacity fators for the given wind speeds

Source code in reskit/wind/core/power_curve.py
def simulate(self, wind_speed):
    """
    Applies the invoking power curve to the given wind speeds.

    Parameters
    ----------
    wind_speed : array_like
        Local average wind speed close to or at the hub height.

    Returns
    -------
    array_like
        CorrespongDing capacity fators for the given wind speeds

    """
    powerCurveInterp = PchipInterpolator(self.wind_speed, self.capacity_factor)
    output = powerCurveInterp(wind_speed)

    if isinstance(wind_speed, pd.DataFrame):
        output = pd.DataFrame(output, index=wind_speed.index, columns=wind_speed.columns)

    return output

compute_specific_power

compute_specific_power(capacity, rotor_diam, **k)

Calculates the corresponding specific power for a wind turbine in W/m2 from values of capacity in kW and rotor diameter in m.

Parameters:

  • capacity

    (float or array - like) –

    Turbine's nominal capacity in kW.

  • rotor_diam

    (float or array - like) –

    Turbine's hub height in m.

Returns:

  • float or array - like

    Specific power in W/m2

Source code in reskit/wind/core/power_curve.py
def compute_specific_power(capacity, rotor_diam, **k):
    """
    Calculates the corresponding specific power for a wind turbine in W/m2 from values of capacity in kW and rotor diameter in m.

    Parameters
    ----------
    capacity : float or array-like
        Turbine's nominal capacity in kW.

    rotor_diam : float or array-like
        Turbine's hub height in m.

    Returns
    -------
    float or array-like
        Specific power in W/m2

    """
    return capacity * 1000 / rotor_diam**2 / np.pi * 4

synthetic_power_curve_data

synthetic_power_curve_data() -> DataFrame

Reads the data used for creating a synthetic power curve.

Returns:

  • pandas DataFrame

    DataFrame with the data to create a synthetic power curve.

Source code in reskit/wind/core/power_curve.py
def synthetic_power_curve_data() -> pd.DataFrame:
    """
    Reads the data used for creating a synthetic power curve.

    Returns
    -------
    pandas DataFrame
        DataFrame with the data to create a synthetic power curve.

    """
    global _synthetic_power_curve_data

    if _synthetic_power_curve_data is None:
        _synthetic_power_curve_data = pd.read_csv(
            join(dirname(__file__), "data", "synthetic_turbine_params.csv"), header=1
        )

    return _synthetic_power_curve_data