|
1 | 1 | """
|
2 | 2 | The ``atmosphere`` module contains methods to calculate relative and
|
3 |
| -absolute airmass and to determine pressure from altitude or vice versa. |
| 3 | +absolute airmass, determine pressure from altitude or vice versa, and wind |
| 4 | +speed at different heights. |
4 | 5 | """
|
5 | 6 |
|
6 | 7 | import numpy as np
|
@@ -533,3 +534,158 @@ def angstrom_alpha(aod1, lambda1, aod2, lambda2):
|
533 | 534 | pvlib.atmosphere.angstrom_aod_at_lambda
|
534 | 535 | """
|
535 | 536 | return - np.log(aod1 / aod2) / np.log(lambda1 / lambda2)
|
| 537 | + |
| 538 | + |
| 539 | +# Values of the Hellmann exponent |
| 540 | +HELLMANN_SURFACE_EXPONENTS = { |
| 541 | + 'unstable_air_above_open_water_surface': 0.06, |
| 542 | + 'neutral_air_above_open_water_surface': 0.10, |
| 543 | + 'stable_air_above_open_water_surface': 0.27, |
| 544 | + 'unstable_air_above_flat_open_coast': 0.11, |
| 545 | + 'neutral_air_above_flat_open_coast': 0.16, |
| 546 | + 'stable_air_above_flat_open_coast': 0.40, |
| 547 | + 'unstable_air_above_human_inhabited_areas': 0.27, |
| 548 | + 'neutral_air_above_human_inhabited_areas': 0.34, |
| 549 | + 'stable_air_above_human_inhabited_areas': 0.60, |
| 550 | +} |
| 551 | + |
| 552 | + |
| 553 | +def windspeed_powerlaw(wind_speed_reference, height_reference, |
| 554 | + height_desired, exponent=None, |
| 555 | + surface_type=None): |
| 556 | + r""" |
| 557 | + Estimate wind speed for different heights. |
| 558 | +
|
| 559 | + The model is based on the power law equation by Hellmann [1]_ [2]_. |
| 560 | +
|
| 561 | + Parameters |
| 562 | + ---------- |
| 563 | + wind_speed_reference : numeric |
| 564 | + Measured wind speed. [m/s] |
| 565 | +
|
| 566 | + height_reference : float |
| 567 | + The height above ground at which the wind speed is measured. [m] |
| 568 | +
|
| 569 | + height_desired : float |
| 570 | + The height above ground at which the wind speed will be estimated. [m] |
| 571 | +
|
| 572 | + exponent : float, optional |
| 573 | + Exponent based on the surface type. [unitless] |
| 574 | +
|
| 575 | + surface_type : string, optional |
| 576 | + If supplied, overrides ``exponent``. Can be one of the following |
| 577 | + (see [1]_): |
| 578 | +
|
| 579 | + * ``'unstable_air_above_open_water_surface'`` |
| 580 | + * ``'neutral_air_above_open_water_surface'`` |
| 581 | + * ``'stable_air_above_open_water_surface'`` |
| 582 | + * ``'unstable_air_above_flat_open_coast'`` |
| 583 | + * ``'neutral_air_above_flat_open_coast'`` |
| 584 | + * ``'stable_air_above_flat_open_coast'`` |
| 585 | + * ``'unstable_air_above_human_inhabited_areas'`` |
| 586 | + * ``'neutral_air_above_human_inhabited_areas'`` |
| 587 | + * ``'stable_air_above_human_inhabited_areas'`` |
| 588 | +
|
| 589 | + Returns |
| 590 | + ------- |
| 591 | + wind_speed : numeric |
| 592 | + Adjusted wind speed for the desired height. [m/s] |
| 593 | +
|
| 594 | + Raises |
| 595 | + ------ |
| 596 | + ValueError |
| 597 | + If neither of ``exponent`` nor a ``surface_type`` is given. |
| 598 | + If both ``exponent`` and a ``surface_type`` is given. These parameters |
| 599 | + are mutually exclusive. |
| 600 | +
|
| 601 | + KeyError |
| 602 | + If the specified ``surface_type`` is invalid. |
| 603 | +
|
| 604 | + Notes |
| 605 | + ----- |
| 606 | + Module temperature functions often require wind speeds at a height of 10 m |
| 607 | + and not the wind speed at the module height. |
| 608 | +
|
| 609 | + For example, the following temperature functions require the input wind |
| 610 | + speed to be 10 m: :py:func:`~pvlib.temperature.sapm_cell`, and |
| 611 | + :py:func:`~pvlib.temperature.sapm_module` whereas the |
| 612 | + :py:func:`~pvlib.temperature.fuentes` model requires wind speed at 9.144 m. |
| 613 | +
|
| 614 | + Additionally, the heat loss coefficients of some models have been developed |
| 615 | + for wind speed measurements at 10 m (e.g., |
| 616 | + :py:func:`~pvlib.temperature.pvsyst_cell`, |
| 617 | + :py:func:`~pvlib.temperature.faiman`, and |
| 618 | + :py:func:`~pvlib.temperature.faiman_rad`). |
| 619 | +
|
| 620 | + The equation for calculating the wind speed at a height of :math:`h` is |
| 621 | + given by the following power law equation [1]_ [2]_: |
| 622 | +
|
| 623 | + .. math:: |
| 624 | + :label: wind speed |
| 625 | +
|
| 626 | + WS_{h} = WS_{ref} \cdot \left( \frac{h}{h_{ref}} \right)^a |
| 627 | +
|
| 628 | + where :math:`h` [m] is the height at which we would like to calculate the |
| 629 | + wind speed, :math:`h_{ref}` [m] is the reference height at which the wind |
| 630 | + speed is known, and :math:`WS_{h}` [m/s] and :math:`WS_{ref}` |
| 631 | + [m/s] are the corresponding wind speeds at these heights. The exponent |
| 632 | + :math:`a` [unitless] depends on the surface type. Some values found in the |
| 633 | + literature [1]_ for :math:`a` are: |
| 634 | +
|
| 635 | + .. table:: Values for the Hellmann-exponent |
| 636 | +
|
| 637 | + +-----------+--------------------+------------------+------------------+ |
| 638 | + | Stability | Open water surface | Flat, open coast | Cities, villages | |
| 639 | + +===========+====================+==================+==================+ |
| 640 | + | Unstable | 0.06 | 0.10 | 0.27 | |
| 641 | + +-----------+--------------------+------------------+------------------+ |
| 642 | + | Neutral | 0.11 | 0.16 | 0.40 | |
| 643 | + +-----------+--------------------+------------------+------------------+ |
| 644 | + | Stable | 0.27 | 0.34 | 0.60 | |
| 645 | + +-----------+--------------------+------------------+------------------+ |
| 646 | +
|
| 647 | + In a report by Sandia [3]_, the equation was experimentally tested for a |
| 648 | + height of 30 ft (:math:`h_{ref} = 9.144` [m]) at their test site in |
| 649 | + Albuquerque for a period of six weeks where a coefficient of |
| 650 | + :math:`a = 0.219` was calculated. |
| 651 | +
|
| 652 | + It should be noted that the equation returns a value of NaN if the |
| 653 | + reference heights or wind speed are negative. |
| 654 | +
|
| 655 | + References |
| 656 | + ---------- |
| 657 | + .. [1] Kaltschmitt M., Streicher W., Wiese A. (2007). "Renewable Energy: |
| 658 | + Technology, Economics and Environment." Springer, |
| 659 | + :doi:`10.1007/3-540-70949-5`. |
| 660 | +
|
| 661 | + .. [2] Hellmann G. (1915). "Über die Bewegung der Luft in den untersten |
| 662 | + Schichten der Atmosphäre." Meteorologische Zeitschrift, 32 |
| 663 | +
|
| 664 | + .. [3] Menicucci D.F., Hall I.J. (1985). "Estimating wind speed as a |
| 665 | + function of height above ground: An analysis of data obtained at the |
| 666 | + southwest residential experiment station, Las Cruses, New Mexico." |
| 667 | + SAND84-2530, Sandia National Laboratories. |
| 668 | + Accessed at: |
| 669 | + https://web.archive.org/web/20230418202422/https://www2.jpl.nasa.gov/adv_tech/photovol/2016CTR/SNL%20-%20Est%20Wind%20Speed%20vs%20Height_1985.pdf |
| 670 | + """ # noqa:E501 |
| 671 | + if surface_type is not None and exponent is None: |
| 672 | + # use the Hellmann exponent from dictionary |
| 673 | + exponent = HELLMANN_SURFACE_EXPONENTS[surface_type] |
| 674 | + elif surface_type is None and exponent is not None: |
| 675 | + # use the provided exponent |
| 676 | + pass |
| 677 | + else: |
| 678 | + raise ValueError( |
| 679 | + "Either a 'surface_type' or an 'exponent' parameter must be given") |
| 680 | + |
| 681 | + wind_speed = wind_speed_reference * ( |
| 682 | + (height_desired / height_reference) ** exponent) |
| 683 | + |
| 684 | + # if wind speed is negative or complex return NaN |
| 685 | + wind_speed = np.where(np.iscomplex(wind_speed) | (wind_speed < 0), |
| 686 | + np.nan, wind_speed) |
| 687 | + |
| 688 | + if isinstance(wind_speed_reference, pd.Series): |
| 689 | + wind_speed = pd.Series(wind_speed, index=wind_speed_reference.index) |
| 690 | + |
| 691 | + return wind_speed |
0 commit comments