Skip to content

Solar Irradiance

Simulating horizontal irradiance

We can simulate solar irradiance components using PVGIS!

To start with, let us check the interface of the irradiance commands :

pvgis-prototype irradiance
 Usage: pvgis-prototype irradiance [OPTIONS] COMMAND [ARGS]...                                                                                                  

 ⸾ Calculate the solar irradiance incident on a solar surface                                                                                                   

╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --help          Show this message and exit.                                                                                                                  │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Introduction ────────────────────────────────╮
│ introduction       Primer on solar irradiance │
╰───────────────────────────────────────────────╯
╭─ Solar irradiance time series ──────────────────────────────────────╮
│ global             ⤋ Calculate the global irradiance                │
│ direct             ⇣ Calculate the direct irradiance                │
│ diffuse            🗤 Calculate the diffuse sky-reflected irradiance │
│ extraterrestrial   ⍖ Estimate the extraterrestrial irradiance       │
╰─────────────────────────────────────────────────────────────────────╯
╭─ Toolbox ────────────────────────────────────────────────────────────────────────╮
│ kato-bands         [⸾] Kato spectral bands limits and center wavelengths         │
│ reflectivity       ⭜⋅ Calculate the reflectivity effect factor Yet not complete! │
│ limits             [⸾] Calculate physically possible irradiance limits           │
╰──────────────────────────────────────────────────────────────────────────────────╯

We can simulate all components of solar radiation : direct, diffuse, reflected and global. Let us begin, however, with the global and direct components. These are, after all, the ones we will compare against the SARAH3 satellite-based observations.

Global horizontal irradiance

As a first step, we can simulate the global horizontal irradiance over our location of interest and moment in time :

pvgis-prototype irradiance global horizontal \
    8.628 45.812 214 \
    '2010-01-27 12:00:00'
459.1726
Consult the help text!

It's always a good idea to consult the help for a command. While effort has been given to keep the same order for the input parameters, not all commands share the exact same required positional parameters!

For the above command, we can get the help via

pvgis-prototype irradiance global horizontal
 Usage: pvgis-prototype irradiance global horizontal [OPTIONS] LONGITUDE                                                                                        
                                                     LATITUDE ELEVATION                                                                                         
                                                     [TIMESTAMPS]                                                                                               

 Calculate the broadband global horizontal irradiance over a time series                                                                                        

╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ *    longitude      FLOAT RANGE  Longitude in decimal degrees ranging in [-180, 360]. If ranging in [0, 360], consider the `--convert-longitude-360` option. │
│                                  [required]                                                                                                                  │
│ *    latitude       FLOAT RANGE  Latitude in decimal degrees ranging in [-90, 90] [required]                                                                 │
│ *    elevation      FLOAT RANGE  Topographical elevation [required]                                                                                          │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Timestamps ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│   timestamps      [TIMESTAMPS]  Quoted date-time strings of data to extract from series, example: '2112-12-21, 2112-12-21 12:21:21, 2112-12-21 21:12:12''    │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --resample-large-series      --no-resample-large-series             [default: no-resample-large-series]                                                      │
│ --log                    -l                                INTEGER  Enable logging [default: 0]                                                              │
│ --help                                                              Show this message and exit.                                                              │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Timestamps ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --start-time,--st                                   PARSE_TIMESTAMP  Start timestamp of the period. Overrides the `timestamps` parameter! [default: None]    │
│ --periods                                           INTEGER          Number of timestamps to generate [default: None]                                        │
│ --frequency                                         TEXT             A common date/time frequency unit optionally with a multiples number, such as           │
│                                                                      H(hourly), min(utely), S(econdly), D(aily), W(eekly), M(onth end), Y(early) or 30min.   │
│                                                                      See Pandas time series offset aliases.                                                  │
│                                                                      [default: None]                                                                         │
│ --end-time,--et                                     PARSE_TIMESTAMP  End timestamp of the period. Overrides the `timestamps` parameter! [default: None]      │
│ --timezone,--tz,--zone                              PARSE_TIMEZONE   Timezone (e.g., 'Europe/Athens'). Use the system's time zone via the `--local` option.  │
│                                                                      [default: None]                                                                         │
│ --random-timestamps       --no-random-timestamps                     Generate a random date, time and timezone to demonstrate calculation                    │
│                                                                      [default: no-random-timestamps]                                                         │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Atmospheric properties ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --linke-turbidity-factor-series                                                  PARSE_LINKE_TURBIDITY_FACTOR_SERIES  Ratio of total to Rayleigh optical     │
│                                                                                                                       depth measuring atmospheric turbidity  │
│                                                                                                                       [default: name=None title='Linke       │
│                                                                                                                       Turbidity' description='The Linke      │
│                                                                                                                       Turbidity Factor describes the         │
│                                                                                                                       attenuation of the extraterrestrial    │
│                                                                                                                       solar radiation by solid and liquid    │
│                                                                                                                       particles under cloudless sky          │
│                                                                                                                       conditions. It indicates the optical   │
│                                                                                                                       density of hazy and humid atmosphere   │
│                                                                                                                       in relation to a clean and dry         │
│                                                                                                                       atmosphere. In other words TLK is the  │
│                                                                                                                       number of clean dry air masses that    │
│                                                                                                                       would result in the same extinction    │
│                                                                                                                       then real hazy and humid air. Due to a │
│                                                                                                                       dynamic nature of the turbidity        │
│                                                                                                                       factor, its calculation and subsequent │
│                                                                                                                       averaging leads to a certain degree of │
│                                                                                                                       generalisation. There are clear        │
│                                                                                                                       seasonal changes of the turbidity      │
│                                                                                                                       (lowest values in winter, highest in   │
│                                                                                                                       summer), the values of turbidity       │
│                                                                                                                       factor always differ from place to     │
│                                                                                                                       place in a similar degree of magnitude │
│                                                                                                                       and these differences are also         │
│                                                                                                                       correlated with the terrain elevation. │
│                                                                                                                       It increases with an intensity of      │
│                                                                                                                       industrialisation and urbanisation.    │
│                                                                                                                       The values of Linke turbidity for      │
│                                                                                                                       different landscapes or world regions  │
│                                                                                                                       can be found in literature [e.g. 16,   │
│                                                                                                                       19, 30] or in http://www.soda-is.com/  │
│                                                                                                                       [20]).' symbol='⋅' value=2             │
│                                                                                                                       unit='unitless' minimum=0 maximum=8]   │
│ --adjust-for-atmospheric-refraction    --no-adjust-for-atmospheric-refraction                                         Correct solar azimuth and altitude     │
│                                                                                                                       angles for atmospheric refraction      │
│                                                                                                                       [default:                              │
│                                                                                                                       adjust-for-atmospheric-refraction]     │
│ --refracted-solar-zenith                                                         FLOAT                                Refracted solar zenith angle (in       │
│                                                                                                                       radians) for sun -rise and -set events │
│                                                                                                                       [default: 1.5853349194640094]          │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Advanced ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --apply-reflectivity-factor    --no-apply-reflectivity-factor      Apply angular loss function [default: apply-reflectivity-factor]                          │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Solar position ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --solar-position-model,--position-model,--positi…        [all|NOAA|Hofierka|Jenco|pvlib|Skyfield|suncalc]  Model to calculate solar position [default: NOAA] │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Solar time ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --solar-time-model        [all|Milne1921|NOAA|PVGIS|pvlib|Skyfield]  Model to calculate solar time [default: NOAA]                                           │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Earth orbit ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --solar-constant                   FLOAT RANGE [x>=1360]  Top-of-Atmosphere mean solar electromagnetic radiation (W/m-2) 1 au (astronomical unit) away from  │
│                                                           the Sun.                                                                                           │
│                                                           [default: 1360.8]                                                                                  │
│ --eccentricity-phase-offset        FLOAT                  Eccentricity phase offset (in radians) aligning the eccentricity correction with Earth's           │
│                                                           perihelion position in its orbit, part of calculation of the solar declination angle.              │
│                                                           [default: 0.048869]                                                                                │
│ --eccentricity-amplitude           FLOAT                  Amplitude of the Earth's orbital eccentricity effect on solar irradiance variation throughout the  │
│                                                           year, part of the calculation of the solar declination angle.                                      │
│                                                           [default: 0.03344]                                                                                 │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ > Input : < Output ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --angle-output-units  -aou      TEXT     Angular units for solar geometry calculations (degrees or radians) [default: radians]                               │
│ --rounding-places     -r        INTEGER  Number of digits to round results to [default: 3]                                                                   │
│ --csv                           PATH     CSV output filename [default: None]                                                                                 │
│ --verbose             -v        INTEGER  Show details while executing commands [default: 0]                                                                  │
│ --index,--idx         -i                 Index rows in output table (meaningful with at least 1x -v)                                                         │
│ --quiet                                  Do not print out the output                                                                                         │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Data processing ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --dtype                TEXT  Data type [default: float32]                                                                                                    │
│ --array-backend        TEXT  Array backend [default: numpy]                                                                                                  │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Statistics ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --statistics    --no-statistics          Calculate and display summary statistics [default: no-statistics]                                                   │
│ --groupby                          TEXT  Group statistics, ex. M or 3h. A number and date/time unit : (Y)ear, (S)eason, (M)onth, (D)ay, (W)eek, (h)our. See  │
│                                          Xarray's group-by operations.                                                                                       │
│                                          [default: None]                                                                                                     │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Plotting ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --uniplot                    --no-uniplot           Plot the PV power output time series in the terminal [default: no-uniplot]                               │
│ --terminal-width-fraction                    FLOAT  Fraction of number of columns of the current terminal, ex. 0.9 [default: 0.9]                            │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Metadata ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --fingerprint,--fp                       Fingerprint the output time series                                                                                  │
│ --metadata            --no-metadata      Print command metadata [default: no-metadata]                                                                       │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

We can see how this simulated quantity breaks down in its sub-components too by using a few -vs :

pvgis-prototype irradiance global horizontal \
    8.628 45.812 214 \
    '2010-01-27 12:00:00' \
    -vvv
                                                  Global Horizontal Irradiance in-plane irradiance series W/m²                                                  

                                                                                                                                          Global Horizontal ⤋   
  Time                  Altitude ⦩   Unrefracted ⦧   Linke Turbidity ⋅   Extra Normal ⦜   Direct Horizontal ⇣ ⭳   Diffuse Horizontal 🗤⭳   ⭳                     
 ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 
  2010-01-27 12:00:00   0.442        True            2.0                 1402.426         406.281                 52.892                  459.173               

  ⅀ / μ                                                                                   406.281                                                               

╭─────────────────────────────────────────────────────────────────────────────────╮ ╭─────────────────────────────────────────────────────╮
│ Location  Longitude ϑ, Latitude ϕ = 0.151, 0.8  Angular units Unitless          │ │  ⸾  Irradiance  🗤  Diffuse      ⋅  Factor           │
│ Algorithms  Timing : NOAA, Positioning : NOAA, Adjusted for refraction : True,  │ │  ⇣  Direct      ⏲  Timing       ⅀  N-ary Summation  │
│ Radiation model ⸾ : Hofierka 2002, Irradiance units W/m²                        │ │  ⭳  Horizontal  ⦩  Altitude     μ  Mean             │
│ Constants Solar constant : 1367.0                                               │ │  ⦜  Normal      ⯐  Positioning                      │
╰───────────────────────────────────────────────────────────────────── Reference ─╯ ╰──────────────────────────────────────────── Legend ─╯

Direct horizontal irradiance

We will get the same simulated direct horizontal estimation by using the direct horizontal commands :

pvgis-prototype irradiance direct horizontal \
    8.628 45.812 214 \
    '2010-01-27 12:00:00'
406.28064

Diffuse horizontal irradiance

The diffuse component is the difference between global and direct. As with the previous command examples, we can derive the diffuse horizontal component via :

pvgis-prototype irradiance diffuse horizontal \
    8.628 45.812 \
    '2010-01-27 12:00:00'
52.89197

Note

The diffuse horizontal irradiance component does not need to know of an elevation value, hence compared to the command for the direct irradiance, the number 214 was removed in this example command.

Satellite observations of solar irradiance

Instead of relying on the model, let's read-in observations of solar irradiance from the SARAH3 data collection :

SARAH3 SIS

  • Read the SIS component from SARAH3 :
pvgis-prototype series select \
    sarah2_sis_over_esti_jrc.nc \
    8.628 45.812 \
    '2010-01-27 12:00:00' \
    --neighbor-lookup nearest \
    --mask-and-scale \
    -v
 Selected  
   data    


 ───────── 
  388.000  



╭───────────────────────────────────────────────────╮
│ Location  Longitude ϑ, Latitude ϕ = 8.628, 45.812 │
│ Legend: Center Wavelengths (nm)                   │
╰───────────────────────────────────────────────────╯

SARAH3 SID

  • Read the SID component from SARAH3 :
pvgis-prototype series select \
    sarah2_sid_over_esti_jrc.nc \
    8.628 45.812 \
    --neighbor-lookup nearest \
    -v \
    --mask-and-scale \
    '2010-01-27 12:00:00'
 Selected  
   data    


 ───────── 
  242.000  



╭───────────────────────────────────────────────────╮
│ Location  Longitude ϑ, Latitude ϕ = 8.628, 45.812 │
│ Legend: Center Wavelengths (nm)                   │
╰───────────────────────────────────────────────────╯

Optional and required parameters

The latter command differs from the one before in that the order of the optional and required input parameters is not the same. The message here is that : indeed, we can mix the order of optional parameters in-between as long as we keep strictly the order of the required ones, as indicated in the help section of a command.

Just run pvgis-prototype series select and read the help text !

Indeed, the simulated values differ from the satellite-based observations retrieved from the SARAH3 datasets. Aren't they close enough ? We need to keep in mind that a series of assumptions and simplifications are part of the solar radiation model.

Direct normal irradiance

In estimating the photovoltaic power output, the solar radiation component with the greatest impact, is the direct normal irradiance.

From the theory, we know that

\[ Direct Normal Irradiance = Direct Horizontal Irradiance / cos(Solar Zenith Angle) \]

or using acronyms frequently used in solar science

\[ DNI = SID / cos(Solar Zenith Angle) \]
  1. First, let's get the zenith angle in radians
pvgis-prototype position zenith \
    8.628 45.812 \
    '2010-01-17 12:00:00'
       Solar Zenith Series        

  Time                  Zenith ⦭  
 ──────────────────────────────── 
  2010-01-17 12:00:00   1.168     

  ⅀ / μ                           

╭─────────────────────────────────────────────────╮ ╭────────────────────────────────────────────────────────────────────────╮ ╭─────────────╮
│ Start             Every  End               Zone │ │ Location  Longitude ϑ, Latitude ϕ = 0.151, 0.8  Angular units Unitless │ │  ⦭  Zenith  │
│ 2010-01-17 12:00  -      2010-01-17 12:00  UTC  │ │ Definitions  Unrefracted zenith: True                                  │ │             │
│                                                 │ ╰──────────────────────────────────────────────────────────── Reference ─╯ ╰──── Legend ─╯
│                                                 │                                                                                           
╰─────────────────────────────────────────────────╯                                                                                           

Bug

There is likely a bug in the position zenithcommand currently!

  1. Next, open a Python interpreter

    python 
    
  2. Set the direct horizontal irradiance reported in SARAH3 and the zenith angle calculated previously

    >>> sid = 431.00000
    >>> solar_zenith_angle = 1.15314
    
  3. Calculate the DNI using simple Pyhon

    >>> from math import cos
    >>> print(f'DNI = {sid / cos(solar_zenith_angle)}')
    

    DNI = 1062.5725738840667

Let's compare with PVGIS' model :

pvgis-prototype irradiance direct normal '2010-01-27 12:00:00'
981.2344087303509

We can assume the model in the new software is close and not wildly out of range !

Horizontal irradiance

If we simulate also the Direct Horizontal Component, it should be close to the SARAH3 observation.

Is it ? Let's find out ...

pvgis-prototype irradiance direct horizontal 8.628 45.812 214 '2010-01-27 12:00:00'
406.28064

Note

Isn't this close enough to 431 ?

Inclined irradiance

Next, the simulated direct inclined component :

pvgis-prototype irradiance direct inclined \
    8.628 45.812 214 180 45 \
    '2010-01-27 12:00:00'
887.52124

And the simulated global inclined component is :

pvgis-prototype irradiance global inclined \
    8.628 45.812 210 180 45 \
    '2010-01-27 12:00:00'
996.16626

Analytically, the above figure is broken down to its inclined components as :

pvgis-prototype irradiance global inclined \
    8.628 45.812 210 180 45 \
    '2010-01-27 12:00:00' \
    -vvv
                                                   Global Inclined Irradiance in-plane irradiance series W/m²                                                   

                                                    Ref…   Lin…          Dir…   Sky…   Gro…   Sky…   Dir…   Extra   Ext…                          Sha…          
                        Dir…   Sky…   Gro…   Glo…   alt.   Tur…   Inc…   ⇣ ∡    🗤 ∡    ⭞ ∡    Hor…   Hor…   Hori…   Nor…   Alti…   Inc…   Sun-…   sta…   In-s…  
  Time                  ⇣ ∡    🗤 ∡    ⭞ ∡    ⤋ ∡    ⦧ ⦩    ⋅      Irr…   ☉      ☉      ☉      🗤⭳     ⇣ ⭳    ⍖ ⭳     ⍖ ⦜    ⦩       ⭸      ⛰       🮞      🮞      
 ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 
  2010-01-27 12:00:00   887…   96.…   12.…   996…   25.…   2.0    100…   890…   97.…   13.…   52.…   406…   600.…   140…   0.442   1.22   Above   Sun…   False  

  ⅀ / μ                 887…   96.…   12.…   996…                        890…   97.…   13.…   52.…   406…   600.…   140…                                        

╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Location  Longitude ϑ, Latitude ϕ = 0.151, 0.8, Elevation: 210.0 m                                                                               │
│ Position  Surface Orientation ↻: 3.142, Surface Tilt ⦥: 0.785   Angular units None                                                               │
│ Definitions  Incidence angle: Sun-Vector-to-Surface-Plane, Sun-to-Horizon: ['Below', 'Low angle', 'Above']                                       │
│ Algorithms  Timing : NOAA, Positioning : NOAA, Incidence : Iqbal, Shading : PVGIS, Shading states : ['Sunlit', 'In-shade', 'Potentially-sunlit'] │
│ Radiation model ⸾ : Hofierka 2002, Irradiance units W/m²                                                                                         │
│ Equation : Direct ⇣∡ + Sky-Diffuse 🗤∡ + Ground-Diffuse ⭞∡                                                                                        │
│ Constants Solar constant : 1367.0                                                                                                                │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Reference ─╯
╭───────────────────────────────────────────────────────╮                                                                                           
│  ⸾  Irradiance    🗤  Diffuse      ↻  Orientation      │                                                                                           
│  -  Loss          ⭞  Reflected    ⦥  Tilt             │                                                                                           
│  ∡  Inclined      ⏲  Timing       ⭸  Incidence        │                                                                                           
│  ⇣  Direct        ⦩  Altitude     🮞  Shading          │                                                                                           
│  ⭳  Horizontal    󱦥  Azimuth      ⋅  Factor           │                                                                                           
│  ⍖  Extra Normal  ⯐  Positioning  ⅀  N-ary Summation  │                                                                                           
│  ⦜  Normal        ⛰  Horizon      μ  Mean             │                                                                                           
╰────────────────────────────────────────────── Legend ─╯                                                                                           

Default orientation and tilt angles

The default values for the orientation and tilt angles of a solar surface are (currently) set to 180 and 45 degrees respectively. Hence, we'd get the same result if we

pvgis-prototype irradiance global horizontal \
    8.628 45.812 214 \
    '2010-01-27 12:00:00'
459.1726

EXTRA

If we read the SIS and SID SARAH3 components to get the Global Inclined Irradiance :

pvgis-prototype irradiance global inclined \
    8.628 45.812 210 180 45 \
    '2010-01-27 12:00:00' \
    --global-horizontal-irradiance sarah2_sis_over_esti_jrc.nc \
    --direct-horizontal-irradiance sarah2_sid_over_esti_jrc.nc \
    --neighbor-lookup nearest
751.07935
  • The diffuse inclined component here uses, of course, SARAH3 SIS and SID and goes through the math to derive to 69.08706.

From normal to horizontal irradiance

\[ Direct Horizontal Irradiance = Direct Normal Irradiance * sin(Solar Altitude) \]

For verification !

>>> from math import sin
>>> dni = 1353.22228247
>>> altitude = 0.45729
>>> dni * sin(altitude)
>>> print(f' = {dni * sin(altitude)}')

= 597.4722358691096