Arrays and Mounting Configuration#

This page explains how collector arrays and their mounting configurations work in SunPeek, including fixed-tilt installations and single-axis tracking systems.

Overview#

In SunPeek, a collector array represents a group of solar thermal collectors that share the same orientation, collector type, and sensor connections. Arrays are the primary unit for Power Check analysis.

The mounting configuration defines how collectors are oriented relative to the sun:

  • Fixed mounting (MountingFixed): Collectors have a constant tilt and azimuth angle.

  • Single-axis tracking (MountingSingleAxis): Collectors rotate around one axis to follow the sun.

Note

Single-axis tracking support is available in the Python API. WebUI support for configuring tracking arrays is planned for a future release.

Mounting Types#

MountingFixed#

Use MountingFixed for fixed-tilt installations where collectors maintain a constant orientation.

Parameters:

MountingFixed Parameters#

Parameter

Description

Unit

Range

surface_tilt

Tilt angle from horizontal plane

degree

0-90

surface_azimuth

Compass direction the collectors face (North=0, East=90, South=180, West=270)

degree

0-360

Example:

from sunpeek.components import Array, MountingFixed
from sunpeek.common.unit_uncertainty import Q

# South-facing collectors tilted at 30 degrees
mounting = MountingFixed(
    surface_tilt=Q(30, 'deg'),
    surface_azimuth=Q(180, 'deg'),  # South
)

array = Array(
    name='Fixed array',
    plant=plant,
    collector=collector,
    mounting=mounting,
    area_gr=Q(500, 'm**2'),
    sensor_map={...},
)

MountingSingleAxis#

Use MountingSingleAxis for single-axis tracking installations where collectors rotate around a fixed axis to follow the sun. The surface orientation is calculated automatically based on sun position using pvlib.

Configuration Parameters:

MountingSingleAxis Parameters#

Parameter

Description

Unit

Range

axis_tilt

Tilt angle of the rotation axis from horizontal

degree

0-90

axis_azimuth

Compass direction of the rotation axis (North=0, East=90, South=180, West=270)

degree

0-360

max_angle

Maximum rotation angle from the horizontal position

degree

0-90

Common Configurations:

  • Horizontal N-S axis (tracks E-W): axis_tilt=0, axis_azimuth=180

  • Horizontal E-W axis (tracks N-S): axis_tilt=0, axis_azimuth=90

  • Tilted axis: Set axis_tilt to match latitude for optimal year-round performance

Example:

from sunpeek.components import Array, MountingSingleAxis
from sunpeek.common.unit_uncertainty import Q

# Horizontal N-S axis tracker (tracks east-to-west)
mounting = MountingSingleAxis(
    axis_tilt=Q(0, 'deg'),        # Horizontal rotation axis
    axis_azimuth=Q(180, 'deg'),   # N-S orientation
    max_angle=Q(60, 'deg'),       # Maximum rotation from horizontal
)

array = Array(
    name='Tracking array',
    plant=plant,
    collector=collector,
    mounting=mounting,
    area_gr=Q(500, 'm**2'),
    sensor_map={...},
)

Virtual Sensors for Tracking Arrays#

When using MountingSingleAxis, SunPeek automatically calculates time-varying surface orientation based on the sun position and tracker configuration. These values are available as virtual sensors:

Tracking Virtual Sensors#

Sensor

Description

Virtual

surface_tilt

Instantaneous tilt angle of collector surface

Always calculated

surface_azimuth

Instantaneous azimuth angle of collector surface

Always calculated

ideal_rotation_angle

Optimal tracker rotation angle based on sun position

Always calculated

rotation_angle

Actual measured rotation angle (if sensor available)

Optional (measured)

Accessing Virtual Sensors:

# After loading measurement data
use_csv(plant, csv_files=[...])

# Access time-varying surface orientation
tracking_array = plant.arrays[0]

# Get surface tilt as a time series (pint-pandas Series)
surface_tilt = tracking_array.mounting.surface_tilt.data
print(f"Surface tilt range: {surface_tilt.min():.1f} to {surface_tilt.max():.1f}")

# Get ideal rotation angle
ideal_rotation = tracking_array.mounting.ideal_rotation_angle.data

The virtual sensors are calculated using pvlib.tracking.singleaxis().

Array Properties#

Arrays provide convenient properties for accessing orientation, regardless of mounting type:

# For fixed mounting, tilt and azim are scalar Quantities
if array.has_orientation():
    print(f"Tilt: {array.tilt}")
    print(f"Azimuth: {array.azim}")

# For tracking mounting, tilt and azim are Sensor objects
# containing time-series data
if not array.has_orientation():
    print("Tracking array - orientation varies with time")
    print(f"Tilt data: {array.tilt.data.head()}")

# The orientation property returns tilt/azim in degrees
# Works for both fixed (scalar) and tracking (raises if time-varying)
if array.has_orientation():
    orient = array.orientation
    print(f"Orientation: tilt={orient['tilt']}°, azim={orient['azim']}°")

Backward Compatibility#

For backward compatibility, the legacy tilt and azim parameters on Array still work. They are automatically converted to MountingFixed internally:

# Legacy syntax (still works)
array = Array(
    name='Array',
    plant=plant,
    collector=collector,
    tilt=Q(30, 'deg'),
    azim=Q(180, 'deg'),
    area_gr=Q(500, 'm**2'),
    sensor_map={...},
)
# Internally creates: MountingFixed(surface_tilt=Q(30,'deg'), surface_azimuth=Q(180,'deg'))

# Recommended new syntax
array = Array(
    name='Array',
    plant=plant,
    collector=collector,
    mounting=MountingFixed(
        surface_tilt=Q(30, 'deg'),
        surface_azimuth=Q(180, 'deg'),
    ),
    area_gr=Q(500, 'm**2'),
    sensor_map={...},
)

Hint

While the legacy syntax is supported, we recommend using the explicit mounting parameter for new code to make the mounting configuration clear and enable future tracking support.

Additional Array Parameters#

Beyond mounting configuration, arrays have additional parameters for shading and layout calculations:

Array Parameters#

Parameter

Description

Unit

Required

name

Descriptive name for the array

Yes

collector

Collector type used in this array

Yes

mounting

Mounting configuration (MountingFixed or MountingSingleAxis)

Yes

area_gr

Total gross collector area

Yes

row_spacing

Distance between collector rows (for shading calculations)

m

No

ground_tilt

Slope of the ground beneath collectors

degree

No

sensor_map

Mapping of sensor slots to sensor objects

Yes

For details on sensor mapping, see Sensor Mapping.

See also

  • Collectors — Solar collector types and parameters

  • Fluids — Heat transfer fluid configuration

  • Shading — Internal shading algorithms

  • Advanced Topics — Advanced Python API examples including tracking arrays