SURFACE_ORIENT

This function converts the rotation angle of a single-axis tracker into the conventional surface tilt and azimuth angles.

It accounts for the tilt and orientation of the tracker’s axis. This is useful for passing tracker geometry into standard transposition and irradiance models.

Excel Usage

=SURFACE_ORIENT(tracker_theta, axis_tilt, axis_azimuth)
  • tracker_theta (list[list], required): Tracker rotation angle (degrees).
  • axis_tilt (float, optional, default: 0): Tilt of the rotation axis (degrees).
  • axis_azimuth (float, optional, default: 0): Compass direction of the rotation axis (degrees).

Returns (list[list]): 2D list [[surface_tilt, surface_azimuth]], or an error string.

Example 1: 30 degree westward rotation on N-S axis

Inputs:

tracker_theta axis_tilt axis_azimuth
30 0 0

Excel formula:

=SURFACE_ORIENT({30}, 0, 0)

Expected output:

Result
30 90
Example 2: 30 degree eastward rotation on N-S axis

Inputs:

tracker_theta axis_tilt axis_azimuth
-30 0 0

Excel formula:

=SURFACE_ORIENT({-30}, 0, 0)

Expected output:

Result
30 270
Example 3: Horizontal tracker orientation

Inputs:

tracker_theta axis_tilt axis_azimuth
0 0 180

Excel formula:

=SURFACE_ORIENT({0}, 0, 180)

Expected output:

Result
0 270
Example 4: Vectorized tracker rotation inputs

Inputs:

tracker_theta axis_tilt axis_azimuth
-20 0 20 0 180

Excel formula:

=SURFACE_ORIENT({-20,0,20}, 0, 180)

Expected output:

Result
20 90
0 270
20 270

Python Code

Show Code
import pandas as pd
import numpy as np
from pvlib.tracking import calc_surface_orientation as result_func

def surface_orient(tracker_theta, axis_tilt=0, axis_azimuth=0):
    """
    Calculate surface tilt and azimuth for a given tracker rotation.

    See: https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.tracking.calc_surface_orientation.html

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

    Args:
        tracker_theta (list[list]): Tracker rotation angle (degrees).
        axis_tilt (float, optional): Tilt of the rotation axis (degrees). Default is 0.
        axis_azimuth (float, optional): Compass direction of the rotation axis (degrees). Default is 0.

    Returns:
        list[list]: 2D list [[surface_tilt, surface_azimuth]], or an error string.
    """
    try:
        def flatten_num(data):
            if not isinstance(data, list): return [float(data)]
            flat = []
            for row in data:
                row = row if isinstance(row, list) else [row]
                for val in row:
                    if val == "": flat.append(float('nan'))
                    else: flat.append(float(val))
            return flat

        theta_list = flatten_num(tracker_theta)
        if len(theta_list) == 0:
            return "Error: tracker_theta cannot be empty"

        at = float(axis_tilt) if axis_tilt is not None else 0.0
        aa = float(axis_azimuth) if axis_azimuth is not None else 0.0

        res = result_func(
            tracker_theta=np.array(theta_list),
            axis_tilt=at,
            axis_azimuth=aa
        )

        # res is a DataFrame or OrderedDict
        st = res['surface_tilt']
        sa = res['surface_azimuth']

        out = []
        for i in range(len(theta_list)):
            out.append([
                float(st[i]) if not pd.isna(st[i]) else "",
                float(sa[i]) if not pd.isna(sa[i]) else ""
            ])
        return out
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

Tracker rotation angle (degrees).
Tilt of the rotation axis (degrees).
Compass direction of the rotation axis (degrees).