Photovoltaics

Overview

Photovoltaics (PV) is the technology of converting light energy directly into electrical energy using semiconductor materials. At the heart of PV system modeling is the ability to accurately predict the electrical performance of solar cells and modules under varying environmental conditions. This capability is essential for system design, performance analysis, bankability studies, and operational optimization.

All photovoltaic modeling tools rely on pvlib-python, the industry-standard open-source library for simulating the performance of photovoltaic energy systems. Built on NumPy and pandas, pvlib provides validated implementations of established models and algorithms used throughout the PV industry.

Solar Position and Irradiance: Before modeling electrical performance, we must determine the sun’s position and the irradiance on the panel surface. The SOLARPOSITION tool calculates solar azimuth, elevation, and zenith angles using validated astronomical algorithms. The IRRADIANCE tool then translates global horizontal irradiance into plane-of-array irradiance components (direct, diffuse, and ground-reflected) accounting for the panel’s tilt and orientation.

Electrical Performance Modeling: The fundamental challenge in PV modeling is understanding how the current-voltage (IV) characteristics of a solar cell change with irradiance and temperature. The single diode model (equivalent circuit model) is the industry-standard approach, representing the cell as a current source in parallel with a diode, along with series and shunt resistances. The CALCPARAMS_CEC tool implements the California Energy Commission (CEC) parameter calculation method, translating manufacturer datasheet values into the five parameters needed for the single diode equation at any operating condition. Once parameters are known, I_FROM_V solves the implicit single diode equation to find current at any given voltage—essential for detailed IV curve analysis.

Simplified System Modeling: For system-level performance estimation where detailed IV curves aren’t needed, the PVWATTS_DC tool provides a simpler empirical model that directly estimates DC power output from irradiance and temperature. This approach is widely used for feasibility studies and preliminary system sizing (Figure 1).

Figure 1: Photovoltaic performance characteristics: (A) IV curves shift vertically with solar irradiance, maintaining similar voltage characteristics. (B) Temperature significantly affects open-circuit voltage, with IV curves shifting horizontally as temperature increases.

CALCPARAMS_CEC

This function computes the five single-diode model parameters using the CEC parameter translation model for specified effective irradiance and cell temperature conditions.

The model scales the photocurrent and diode terms from reference conditions to operating conditions, providing outputs suitable for downstream IV-curve calculations.

The returned vector is ordered as:

[I_L, I_0, R_s, R_{sh}, nN_sV_{th}]

where each term is the translated parameter at the requested operating point.

Excel Usage

=CALCPARAMS_CEC(effective_irradiance, temp_cell, alpha_sc, a_ref, I_L_ref, I_o_ref, R_sh_ref, R_s, Adjust, EgRef, dEgdT, irrad_ref, temp_ref)
  • effective_irradiance (float, required): Effective irradiance incident on cells (W/m^2).
  • temp_cell (float, required): Cell temperature under operating conditions (deg C).
  • alpha_sc (float, required): Short-circuit current temperature coefficient (A/deg C).
  • a_ref (float, required): Modified diode ideality factor term at reference conditions (V).
  • I_L_ref (float, required): Light-generated current at reference conditions (A).
  • I_o_ref (float, required): Diode saturation current at reference conditions (A).
  • R_sh_ref (float, required): Shunt resistance at reference conditions (ohm).
  • R_s (float, required): Series resistance at reference conditions (ohm).
  • Adjust (float, required): CEC adjustment to current temperature coefficient (%).
  • EgRef (float, optional, default: 1.121): Bandgap at reference temperature (eV).
  • dEgdT (float, optional, default: -0.0002677): Bandgap temperature dependence (1/K).
  • irrad_ref (float, optional, default: 1000): Reference irradiance (W/m^2).
  • temp_ref (float, optional, default: 25): Reference cell temperature (deg C).

Returns (list[list]): [photocurrent, saturation current, series resistance, shunt resistance, nNsVth]. If input is invalid, returns a string error message.

Example 1: Reference-condition CEC parameters

Inputs:

effective_irradiance temp_cell alpha_sc a_ref I_L_ref I_o_ref R_sh_ref R_s Adjust EgRef dEgdT irrad_ref temp_ref
1000 25 0.004 1.5 6 1e-10 200 0.5 0 1.121 -0.0002677 1000 25

Excel formula:

=CALCPARAMS_CEC(1000, 25, 0.004, 1.5, 6, 1e-10, 200, 0.5, 0, 1.121, -0.0002677, 1000, 25)

Expected output:

Result
6 1e-10 0.5 200 1.5
Example 2: Higher cell temperature and altered bandgap

Inputs:

effective_irradiance temp_cell alpha_sc a_ref I_L_ref I_o_ref R_sh_ref R_s Adjust EgRef dEgdT irrad_ref temp_ref
800 35 0.004 1.5 6 1e-10 200 0.5 0 1.2 -0.0003 1000 25

Excel formula:

=CALCPARAMS_CEC(800, 35, 0.004, 1.5, 6, 1e-10, 200, 0.5, 0, 1.2, -0.0003, 1000, 25)

Expected output:

Result
4.832 5.75595e-10 0.5 250 1.55031
Example 3: Different irradiance and temperature references

Inputs:

effective_irradiance temp_cell alpha_sc a_ref I_L_ref I_o_ref R_sh_ref R_s Adjust EgRef dEgdT irrad_ref temp_ref
1000 25 0.004 1.5 6 1e-10 200 0.5 0 1.121 -0.0002677 900 20

Excel formula:

=CALCPARAMS_CEC(1000, 25, 0.004, 1.5, 6, 1e-10, 200, 0.5, 0, 1.121, -0.0002677, 900, 20)

Expected output:

Result
6.68889 2.34742e-10 0.5 180 1.52558
Example 4: Fully specified non-default parameter set

Inputs:

effective_irradiance temp_cell alpha_sc a_ref I_L_ref I_o_ref R_sh_ref R_s Adjust EgRef dEgdT irrad_ref temp_ref
950 30 0.004 1.6 6.2 2e-10 210 0.55 0.01 1.15 -0.00028 950 30

Excel formula:

=CALCPARAMS_CEC(950, 30, 0.004, 1.6, 6.2, 2e-10, 210, 0.55, 0.01, 1.15, -0.00028, 950, 30)

Expected output:

Result
6.2 2e-10 0.55 210 1.6

Python Code

Show Code
from pvlib.pvsystem import calcparams_cec as pvlib_calcparams_cec

def calcparams_cec(effective_irradiance, temp_cell, alpha_sc, a_ref, I_L_ref, I_o_ref, R_sh_ref, R_s, Adjust, EgRef=1.121, dEgdT=-0.0002677, irrad_ref=1000, temp_ref=25):
    """
    Calculate five CEC model parameters for the single diode equation at given irradiance and cell temperature.

    See: https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.pvsystem.calcparams_cec.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        effective_irradiance (float): Effective irradiance incident on cells (W/m^2).
        temp_cell (float): Cell temperature under operating conditions (deg C).
        alpha_sc (float): Short-circuit current temperature coefficient (A/deg C).
        a_ref (float): Modified diode ideality factor term at reference conditions (V).
        I_L_ref (float): Light-generated current at reference conditions (A).
        I_o_ref (float): Diode saturation current at reference conditions (A).
        R_sh_ref (float): Shunt resistance at reference conditions (ohm).
        R_s (float): Series resistance at reference conditions (ohm).
        Adjust (float): CEC adjustment to current temperature coefficient (%).
        EgRef (float, optional): Bandgap at reference temperature (eV). Default is 1.121.
        dEgdT (float, optional): Bandgap temperature dependence (1/K). Default is -0.0002677.
        irrad_ref (float, optional): Reference irradiance (W/m^2). Default is 1000.
        temp_ref (float, optional): Reference cell temperature (deg C). Default is 25.

    Returns:
        list[list]: [photocurrent, saturation current, series resistance, shunt resistance, nNsVth]. If input is invalid, returns a string error message.
    """
    try:
        args = [effective_irradiance, temp_cell, alpha_sc, a_ref, I_L_ref, I_o_ref, R_sh_ref, R_s, Adjust, EgRef, dEgdT, irrad_ref, temp_ref]
        if any(isinstance(arg, list) for arg in args):
            return "Error: All arguments must be scalar values"

        vals = pvlib_calcparams_cec(
            float(effective_irradiance), float(temp_cell), float(alpha_sc), float(a_ref), float(I_L_ref), float(I_o_ref), float(R_sh_ref), float(R_s), float(Adjust), float(EgRef), float(dEgdT), float(irrad_ref), float(temp_ref)
        )
        row = [float(vals[0]), float(vals[1]), float(vals[2]), float(vals[3]), float(vals[4])]
        return [row]
    except Exception as ex:
        return f"Error: {str(ex)}"

Online Calculator

Effective irradiance incident on cells (W/m^2).
Cell temperature under operating conditions (deg C).
Short-circuit current temperature coefficient (A/deg C).
Modified diode ideality factor term at reference conditions (V).
Light-generated current at reference conditions (A).
Diode saturation current at reference conditions (A).
Shunt resistance at reference conditions (ohm).
Series resistance at reference conditions (ohm).
CEC adjustment to current temperature coefficient (%).
Bandgap at reference temperature (eV).
Bandgap temperature dependence (1/K).
Reference irradiance (W/m^2).
Reference cell temperature (deg C).

I_FROM_V

This function computes the current corresponding to a specified voltage using the photovoltaic single-diode model.

It uses model parameters for photocurrent, saturation current, series resistance, shunt resistance, and thermal voltage term to solve the implicit current-voltage relation.

The solved current I satisfies the single-diode equation at the requested voltage V.

Excel Usage

=I_FROM_V(voltage, photocurrent, saturation_current, resistance_series, resistance_shunt, nNsVth, ifv_method)
  • voltage (float, required): Device voltage under operating condition (V).
  • photocurrent (float, required): Light-generated current under operating condition (A).
  • saturation_current (float, required): Diode saturation current under operating condition (A).
  • resistance_series (float, required): Series resistance under operating condition (ohm).
  • resistance_shunt (float, required): Shunt resistance under operating condition (ohm).
  • nNsVth (float, required): Product of ideality factor, cells in series, and thermal voltage (V).
  • ifv_method (str, optional, default: “lambertw”): Numerical method used for solving current.

Returns (float): Device current in amperes, or an error message string.

Example 1: Lambert W solution at low voltage

Inputs:

voltage photocurrent saturation_current resistance_series resistance_shunt nNsVth ifv_method
0.5 8 1e-10 0.01 1000 1.5 lambertw

Excel formula:

=I_FROM_V(0.5, 8, 1e-10, 0.01, 1000, 1.5, "lambertw")

Expected output:

7.99942

Example 2: Lambert W solution at higher voltage

Inputs:

voltage photocurrent saturation_current resistance_series resistance_shunt nNsVth ifv_method
0.6 8 1e-10 0.01 1000 1.5 lambertw

Excel formula:

=I_FROM_V(0.6, 8, 1e-10, 0.01, 1000, 1.5, "lambertw")

Expected output:

7.99932

Example 3: Lambert W solution with larger series resistance

Inputs:

voltage photocurrent saturation_current resistance_series resistance_shunt nNsVth ifv_method
0.5 8 1e-10 1 1000 1.5 lambertw

Excel formula:

=I_FROM_V(0.5, 8, 1e-10, 1, 1000, 1.5, "lambertw")

Expected output:

7.99151

Example 4: Newton method gives consistent current

Inputs:

voltage photocurrent saturation_current resistance_series resistance_shunt nNsVth ifv_method
0.5 8 1e-10 0.01 1000 1.5 newton

Excel formula:

=I_FROM_V(0.5, 8, 1e-10, 0.01, 1000, 1.5, "newton")

Expected output:

7.99942

Python Code

Show Code
from pvlib.pvsystem import i_from_v as pvlib_i_from_v

def i_from_v(voltage, photocurrent, saturation_current, resistance_series, resistance_shunt, nNsVth, ifv_method='lambertw'):
    """
    Calculate the device current at a given device voltage for a PV cell/module using the single diode model.

    See: https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.pvsystem.i_from_v.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        voltage (float): Device voltage under operating condition (V).
        photocurrent (float): Light-generated current under operating condition (A).
        saturation_current (float): Diode saturation current under operating condition (A).
        resistance_series (float): Series resistance under operating condition (ohm).
        resistance_shunt (float): Shunt resistance under operating condition (ohm).
        nNsVth (float): Product of ideality factor, cells in series, and thermal voltage (V).
        ifv_method (str, optional): Numerical method used for solving current. Valid options: Lambert W, Newton, Brent Q, Chandrupatla. Default is 'lambertw'.

    Returns:
        float: Device current in amperes, or an error message string.
    """
    try:
        V = float(voltage)
        IL = float(photocurrent)
        I0 = float(saturation_current)
        Rs = float(resistance_series)
        Rsh = float(resistance_shunt)
        nNsVth_ = float(nNsVth)
        method = str(ifv_method)

        if method not in ["lambertw", "newton", "brentq", "chandrupatla"]:
            return "Error: ifv_method must be one of lambertw, newton, brentq, chandrupatla"

        result = pvlib_i_from_v(V, IL, I0, Rs, Rsh, nNsVth_, method=method)
        return float(result)
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

Device voltage under operating condition (V).
Light-generated current under operating condition (A).
Diode saturation current under operating condition (A).
Series resistance under operating condition (ohm).
Shunt resistance under operating condition (ohm).
Product of ideality factor, cells in series, and thermal voltage (V).
Numerical method used for solving current.

IRRADIANCE

This function computes plane-of-array irradiance components on a tilted photovoltaic surface using established transposition models.

It combines sun position, panel orientation, and irradiance inputs to estimate total incident irradiance and its direct, sky-diffuse, and ground-reflected components.

The output order is:

[\text{poa\_global},\ \text{poa\_direct},\ \text{poa\_diffuse},\ \text{poa\_sky\_diffuse},\ \text{poa\_ground\_diffuse}]

Excel Usage

=IRRADIANCE(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth, dni, ghi, dhi, dni_extra, airmass, albedo, irradiance_model)
  • surface_tilt (float, required): Surface tilt angle from horizontal (deg).
  • surface_azimuth (float, required): Surface azimuth clockwise from north (deg).
  • solar_zenith (float, required): Solar zenith angle (deg).
  • solar_azimuth (float, required): Solar azimuth angle (deg).
  • dni (float, required): Direct normal irradiance (W/m^2).
  • ghi (float, required): Global horizontal irradiance (W/m^2).
  • dhi (float, required): Diffuse horizontal irradiance (W/m^2).
  • dni_extra (float, optional, default: 1367): Extraterrestrial direct normal irradiance (W/m^2).
  • airmass (float, optional, default: null): Relative air mass (unitless).
  • albedo (float, optional, default: null): Ground albedo (unitless).
  • irradiance_model (str, optional, default: “haydavies”): Diffuse irradiance transposition model.

Returns (list[list]): 2D list [[poa_global, poa_direct, poa_diffuse, …]], or error string.

Example 1: Haydavies model with default optional inputs

Inputs:

surface_tilt surface_azimuth solar_zenith solar_azimuth dni ghi dhi dni_extra irradiance_model
30 180 40 180 800 1000 100 1367 haydavies

Excel formula:

=IRRADIANCE(30, 180, 40, 180, 800, 1000, 100, 1367, "haydavies")

Expected output:

Result
918.527 787.846 130.681 113.934 16.7468
Example 2: Haydavies model with explicit albedo

Inputs:

surface_tilt surface_azimuth solar_zenith solar_azimuth dni ghi dhi dni_extra albedo irradiance_model
30 180 40 180 800 1000 100 1367 0.2 haydavies

Excel formula:

=IRRADIANCE(30, 180, 40, 180, 800, 1000, 100, 1367, 0.2, "haydavies")

Expected output:

Result
915.178 787.846 127.332 113.934 13.3975
Example 3: Isotropic diffuse model comparison

Inputs:

surface_tilt surface_azimuth solar_zenith solar_azimuth dni ghi dhi dni_extra irradiance_model
30 180 40 180 800 1000 100 1367 isotropic

Excel formula:

=IRRADIANCE(30, 180, 40, 180, 800, 1000, 100, 1367, "isotropic")

Expected output:

Result
897.894 787.846 110.048 93.3013 16.7468
Example 4: Haydavies model with explicit air mass

Inputs:

surface_tilt surface_azimuth solar_zenith solar_azimuth dni ghi dhi dni_extra airmass irradiance_model
30 180 40 180 800 1000 100 1367 1.5 haydavies

Excel formula:

=IRRADIANCE(30, 180, 40, 180, 800, 1000, 100, 1367, 1.5, "haydavies")

Expected output:

Result
918.527 787.846 130.681 113.934 16.7468

Python Code

Show Code
from pvlib.pvsystem import PVSystem as pv_system

def irradiance(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth, dni, ghi, dhi, dni_extra=1367, airmass=None, albedo=None, irradiance_model='haydavies'):
    """
    Calculate the plane of array irradiance components on a tilted surface using PVLib.

    See: https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.pvsystem.PVSystem.get_irradiance.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        surface_tilt (float): Surface tilt angle from horizontal (deg).
        surface_azimuth (float): Surface azimuth clockwise from north (deg).
        solar_zenith (float): Solar zenith angle (deg).
        solar_azimuth (float): Solar azimuth angle (deg).
        dni (float): Direct normal irradiance (W/m^2).
        ghi (float): Global horizontal irradiance (W/m^2).
        dhi (float): Diffuse horizontal irradiance (W/m^2).
        dni_extra (float, optional): Extraterrestrial direct normal irradiance (W/m^2). Default is 1367.
        airmass (float, optional): Relative air mass (unitless). Default is None.
        albedo (float, optional): Ground albedo (unitless). Default is None.
        irradiance_model (str, optional): Diffuse irradiance transposition model. Valid options: Haydavies, Isotropic, Klucher, Reindl, King, Perez. Default is 'haydavies'.

    Returns:
        list[list]: 2D list [[poa_global, poa_direct, poa_diffuse, ...]], or error string.
    """
    try:
        args = [surface_tilt, surface_azimuth, solar_zenith, solar_azimuth, dni, ghi, dhi]
        for v in args:
            if v is None:
                return "Error: All required arguments must be provided"

        surface_tilt = float(surface_tilt)
        surface_azimuth = float(surface_azimuth)
        solar_zenith = float(solar_zenith)
        solar_azimuth = float(solar_azimuth)
        dni = float(dni)
        ghi = float(ghi)
        dhi = float(dhi)
        if dni_extra is not None:
            dni_extra = float(dni_extra)
        if airmass is not None:
            airmass = float(airmass)
        if albedo is not None:
            albedo = float(albedo)
        if irradiance_model is None:
            irradiance_model = 'haydavies'

        valid_models = ['haydavies', 'isotropic', 'klucher', 'reindl', 'king', 'perez']
        if irradiance_model not in valid_models:
            return "Error: model must be one of haydavies, isotropic, klucher, reindl, king, perez"

        system = pv_system(surface_tilt=surface_tilt, surface_azimuth=surface_azimuth)
        poa = system.get_irradiance(
            solar_zenith=solar_zenith,
            solar_azimuth=solar_azimuth,
            dni=dni,
            ghi=ghi,
            dhi=dhi,
            dni_extra=dni_extra,
            airmass=airmass,
            albedo=albedo,
            model=irradiance_model
        )

        keys = ['poa_global', 'poa_direct', 'poa_diffuse', 'poa_sky_diffuse', 'poa_ground_diffuse']
        row = []
        for k in keys:
            v = poa[k] if k in poa else None
            if v is None:
                row.append('')
            else:
                try:
                    row.append(float(v))
                except Exception:
                    row.append('')
        return [row]
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

Surface tilt angle from horizontal (deg).
Surface azimuth clockwise from north (deg).
Solar zenith angle (deg).
Solar azimuth angle (deg).
Direct normal irradiance (W/m^2).
Global horizontal irradiance (W/m^2).
Diffuse horizontal irradiance (W/m^2).
Extraterrestrial direct normal irradiance (W/m^2).
Relative air mass (unitless).
Ground albedo (unitless).
Diffuse irradiance transposition model.

PVWATTS_DC

This function computes photovoltaic DC power using the PVWatts temperature-corrected irradiance model.

Power scales linearly with effective irradiance and is corrected by the module power temperature coefficient relative to a reference cell temperature.

The model equation is:

P_{dc} = \frac{G_{eff}}{1000} P_{dc0} \left(1 + \gamma_{pdc}(T_{cell} - T_{ref})\right)

Excel Usage

=PVWATTS_DC(effective_irradiance, temp_cell, pdc_zero, gamma_pdc, temp_ref)
  • effective_irradiance (float, required): Effective irradiance transmitted to cells (W/m^2).
  • temp_cell (float, required): Cell temperature (deg C).
  • pdc_zero (float, required): Module DC power at reference conditions (W).
  • gamma_pdc (float, required): Power temperature coefficient (1/deg C).
  • temp_ref (float, optional, default: 25): Reference cell temperature (deg C).

Returns (float): DC power output (float), or error message string.

Example 1: Standard test condition power output

Inputs:

effective_irradiance temp_cell pdc_zero gamma_pdc temp_ref
1000 25 300 -0.003 25

Excel formula:

=PVWATTS_DC(1000, 25, 300, -0.003, 25)

Expected output:

300

Example 2: Higher cell temperature reduces output

Inputs:

effective_irradiance temp_cell pdc_zero gamma_pdc temp_ref
1000 35 300 -0.003 25

Excel formula:

=PVWATTS_DC(1000, 35, 300, -0.003, 25)

Expected output:

291

Example 3: Lower irradiance scales output linearly

Inputs:

effective_irradiance temp_cell pdc_zero gamma_pdc temp_ref
800 25 300 -0.003 25

Excel formula:

=PVWATTS_DC(800, 25, 300, -0.003, 25)

Expected output:

240

Example 4: Different reference temperature changes correction

Inputs:

effective_irradiance temp_cell pdc_zero gamma_pdc temp_ref
1000 35 300 -0.003 20

Excel formula:

=PVWATTS_DC(1000, 35, 300, -0.003, 20)

Expected output:

286.5

Python Code

Show Code
from pvlib.pvsystem import pvwatts_dc as pvlib_pvwatts_dc

def pvwatts_dc(effective_irradiance, temp_cell, pdc_zero, gamma_pdc, temp_ref=25):
    """
    Calculate the DC power output of a PV module using the PVWatts DC model.

    See: https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.pvsystem.pvwatts_dc.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        effective_irradiance (float): Effective irradiance transmitted to cells (W/m^2).
        temp_cell (float): Cell temperature (deg C).
        pdc_zero (float): Module DC power at reference conditions (W).
        gamma_pdc (float): Power temperature coefficient (1/deg C).
        temp_ref (float, optional): Reference cell temperature (deg C). Default is 25.

    Returns:
        float: DC power output (float), or error message string.
    """
    try:
      return float(pvlib_pvwatts_dc(float(effective_irradiance), float(temp_cell), float(pdc_zero), float(gamma_pdc), float(temp_ref)))
    except Exception as e:
      return f"Error: {str(e)}"

Online Calculator

Effective irradiance transmitted to cells (W/m^2).
Cell temperature (deg C).
Module DC power at reference conditions (W).
Power temperature coefficient (1/deg C).
Reference cell temperature (deg C).

SOLARPOSITION

This function calculates solar position angles for specified timestamps and geographic coordinates.

For each timestamp, it returns azimuth, elevation, and apparent zenith from PVLib’s solar position algorithms.

The geometric relation between elevation and zenith is:

ext{elevation} = 90^\circ - \text{zenith}

Apparent zenith includes atmospheric refraction effects.

Excel Usage

=SOLARPOSITION(time, latitude, longitude, altitude, pressure, solarpos_meth, temperature)
  • time (str, required): Timestamp in ISO8601 format (UTC or timezone-aware).
  • latitude (float, required): Latitude north of equator (deg).
  • longitude (float, required): Longitude east of prime meridian (deg).
  • altitude (float, optional, default: 0): Site elevation above sea level (m).
  • pressure (float, optional, default: 101325): Atmospheric pressure (Pa).
  • solarpos_meth (str, optional, default: “nrel_numpy”): Solar position algorithm method.
  • temperature (float, optional, default: 12): Ambient temperature used in refraction calculation (deg C).

Returns (list[list]): 2D list [[azimuth, elevation, apparent_zenith]], or error string.

Example 1: Summer midday position at sea level

Inputs:

time latitude longitude altitude pressure solarpos_meth temperature
2024-06-20T12:00:00Z 35 -120 0 101325 nrel_numpy 12

Excel formula:

=SOLARPOSITION("2024-06-20T12:00:00Z", 35, -120, 0, 101325, "nrel_numpy", 12)

Expected output:

Result
53.1775 -8.77273 98.7727
Example 2: Summer morning position at sea level

Inputs:

time latitude longitude altitude pressure solarpos_meth temperature
2024-06-20T06:00:00Z 35 -120 0 101325 nrel_numpy 12

Excel formula:

=SOLARPOSITION("2024-06-20T06:00:00Z", 35, -120, 0, 101325, "nrel_numpy", 12)

Expected output:

Result
329.216 -24.8381 114.838
Example 3: Winter midday position at higher altitude

Inputs:

time latitude longitude altitude pressure solarpos_meth temperature
2024-12-21T12:00:00Z 35 -120 100 90000 nrel_numpy 12

Excel formula:

=SOLARPOSITION("2024-12-21T12:00:00Z", 35, -120, 100, 90000, "nrel_numpy", 12)

Expected output:

Result
94.7359 -36.8049 126.805
Example 4: Summer midday position with warmer air

Inputs:

time latitude longitude altitude pressure solarpos_meth temperature
2024-06-20T12:00:00Z 35 -120 0 101325 nrel_numpy 25

Excel formula:

=SOLARPOSITION("2024-06-20T12:00:00Z", 35, -120, 0, 101325, "nrel_numpy", 25)

Expected output:

Result
53.1775 -8.77273 98.7727

Python Code

Show Code
import pandas as pd
from pvlib.solarposition import get_solarposition as pvlib_get_solarposition

def solarposition(time, latitude, longitude, altitude=0, pressure=101325, solarpos_meth='nrel_numpy', temperature=12):
    """
    Calculate solar azimuth, elevation, and apparent zenith for given times and location.

    See: https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.solarposition.get_solarposition.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        time (str): Timestamp in ISO8601 format (UTC or timezone-aware).
        latitude (float): Latitude north of equator (deg).
        longitude (float): Longitude east of prime meridian (deg).
        altitude (float, optional): Site elevation above sea level (m). Default is 0.
        pressure (float, optional): Atmospheric pressure (Pa). Default is 101325.
        solarpos_meth (str, optional): Solar position algorithm method. Valid options: NREL NumPy, NREL Numba, PyEphem, Ephemeris, NREL C. Default is 'nrel_numpy'.
        temperature (float, optional): Ambient temperature used in refraction calculation (deg C). Default is 12.

    Returns:
        list[list]: 2D list [[azimuth, elevation, apparent_zenith]], or error string.
    """
    try:
        def to2d(value):
            if not isinstance(value, list):
                return [[value]]
            return value

        time_2d = to2d(time)
        if not (isinstance(time_2d, list) and all(isinstance(row, list) and len(row) == 1 and isinstance(row[0], str) for row in time_2d)):
            return "Error: time must be a string or a 2D list of single-string rows"

        times = [row[0] for row in time_2d]
        dt_index = pd.DatetimeIndex(times)

        lat = float(latitude)
        lon = float(longitude)
        alt = float(altitude)
        pres = float(pressure)
        temp = float(temperature)
        meth = str(solarpos_meth)

        valid_methods = ['nrel_numpy', 'nrel_numba', 'pyephem', 'ephemeris', 'nrel_c']
        if meth not in valid_methods:
            return "Error: solarpos_meth must be one of nrel_numpy, nrel_numba, pyephem, ephemeris, nrel_c"

        df = pvlib_get_solarposition(
            time=dt_index,
            latitude=lat,
            longitude=lon,
            altitude=alt,
            pressure=pres,
            method=meth,
            temperature=temp
        )

        result = []
        for i in range(len(dt_index)):
            az = float(df.iloc[i]["azimuth"])
            el = float(df.iloc[i]["elevation"])
            zen = float(df.iloc[i]["apparent_zenith"])
            result.append([az, el, zen])
        return result
    except Exception as e:
          return f"Error: {str(e)}"

Online Calculator

Timestamp in ISO8601 format (UTC or timezone-aware).
Latitude north of equator (deg).
Longitude east of prime meridian (deg).
Site elevation above sea level (m).
Atmospheric pressure (Pa).
Solar position algorithm method.
Ambient temperature used in refraction calculation (deg C).