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).
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
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
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
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
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