Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Proximal Energy Logo

Welcome

Welcome to Proximal Energy's documentation website. This website is intended to provide a comprehensive guide to the various aspects of Proximal Energy's software. The website is divided into several sections, each of which is designed to provide a detailed explanation of a specific aspect of each of the main functionalities of the platform.

Hints

  • The entire documentation set can be exported as PDF by clicking on the printer icon in the top right hand corner of the page.
  • You can press the left and right arrow keys on your keyboard to navigate to the previous and next page respectively.

Commissioning Overview

This document describes all of the things necessary to commission a project in Proximal. It can be used as a checklist for each project you would like to bring online.

System and SCADA Definition

Required Documents

Your contact at Proximal will provide you a Google Sheet to fill out for your specific project. This google sheet mirrors a combiner shedule diagram in your IFC or as-built construction documents and will be used by our team to set up your project in our database.

Performance Modeling

Required Documents

  • PAN file: Used for module modeling
  • OND file: Used for inverter modeling
  • Transformer Spec Sheet

Events Overview

An Event is a time-bounded, addressable period of project or component underperformance. The Events pipeline turns operational telemetry into Event records, assigns the most defensible device and failure mode, calculates energetic or financial impact where possible, and keeps the set of active Events shown in the platform up to date.

An Event is not simply an alarm. It is the pipeline's reconciled interpretation of several kinds of evidence:

  • measured power relative to a device's expected participation;
  • decoded equipment status and alarm bits;
  • BESS charge and discharge availability;
  • PV irradiance and expected operating conditions;
  • tracker position relative to an ideal tracking profile;
  • curtailment setpoints and related controls;
  • the plant's device hierarchy; and
  • previously detected Events that overlap the current analysis window.

The pipeline is deliberately heuristic. It favors operationally useful, addressable Events over emitting every anomalous sample. In particular, it suppresses short glitches, retains uncertainty when telemetry is missing, consolidates simultaneous child failures at an actionable ancestor, and reconciles every new detection with existing Event history.

Documentation map

  • Events Pipeline follows an Event from analysis through persistence, losses, and the active-Event list shown in the platform.
  • Event Detection Methods explains PV detection and the two independent BESS detection paths: status-based and status-less.
  • Event Ancestral Hierarchy explains ancestor suppression, descendant rollup, singleton correction, imputed parents, and the effects of hierarchy on Event continuity.

How an Event is represented

Each Event is attached to one device and uses a half-open time interval: it includes the start time and excludes the end time.

The start time is the first anomalous sample. The end time is the timestamp of the first recovered sample, so that recovered sample is not part of the Event. A missing end time means the Event is still open.

This interval convention matters for loss accounting and reconciliation. The first healthy five-minute sample is not charged as loss, and two Events that merely abut at the same timestamp do not overlap.

Event state is consistent with that interval:

  • Closed — the Event has an end time.
  • Active — the Event is open and current evidence is still anomalous, or current evidence is indeterminate.
  • Pending close — a BESS Event is being held open by slow-close hysteresis even though direct evidence has recovered.

Every Event with an end time is closed. An open Event whose state is missing or invalid is treated as active.

What the pipeline currently covers

The pipeline currently detects or supports:

  • project and device offline Events;
  • PV inverter, inverter-module, combiner, meter, and related hierarchy Events;
  • BESS PCS, PCS module group, PCS module, bank, string, collector, transformer, meter, and project Events, depending on available metadata;
  • tracker-row and tracker-zone underperformance Events; and
  • curtailment Events.

Soiling and some broader underperformance classifications remain separate or under continued development. The exact supported device set depends on the project's metadata, available telemetry, and failure-mode configuration rather than on this list alone.

Design principles

Unknown is not healthy

Most detection flags have three possible values:

  • True means positive anomalous evidence.
  • False means positive nominal or recovered evidence.
  • NA means that the method cannot determine state from the available data.

The distinction is essential. A communications gap must not automatically close an Event, but missing data must not automatically open one either.

Detection and attribution are separate

Detection answers whether and when a device appears unavailable or underperforming. Hierarchy processing answers where the condition should be represented. Failure-mode assignment answers what immediately observable condition best describes it. Root cause is a separate operational conclusion and may require inspection or maintenance evidence.

Reanalysis is expected

The pipeline repeatedly revisits recent history. Backfilled telemetry and revised evidence can extend, close, merge, or supersede an Event. Event IDs and existing metadata are preserved where intervals overlap, while redundant unclaimed records may be removed.

The Event device should be actionable

When every comparable child under a parent is anomalous at the same time, the hierarchy can roll the condition up to the parent. When an ancestor is already anomalous, descendant flags are made indeterminate so the platform does not present dependent symptoms as independent work items. See Event Ancestral Hierarchy for the precise rules and exceptions.

Events Pipeline

This page describes how Events are produced and kept current. PV and BESS processing follow asset-specific paths, then converge on saving Events, aggregating losses, and refreshing the active-Event list shown in the platform.

1. Project selection

PV projects run PV detection, BESS projects run BESS detection, and hybrid PV-plus-storage projects run both. A failure in one does not prevent the other, or later steps such as loss aggregation, from being attempted.

Only projects with Event integration enabled are processed.

2. Analysis-window selection

All window selection uses the project's local time zone. Events are reanalyzed on a regular cadence:

  • At local midnight, the preceding three days are analyzed in one-day chunks.
  • At each other six-hour boundary, the period from local midnight through the current five-minute boundary is reanalyzed.
  • At other five-minute boundaries, the preceding hour is analyzed.
  • When a specific range is reprocessed, ranges longer than one day are divided into one-day chunks.

Reanalysis is not just a recovery mechanism. It is part of normal correctness: delayed telemetry can change flags, recent open Events need to be extended or closed, and overlapping records must be reconciled.

The logical window convention is half-open: it includes the start and excludes the end. Samples are generally represented at five-minute resolution.

3. Metadata and existing Event retrieval

For each project and window, the pipeline loads the device and tag metadata needed for detection. It also retrieves existing Events that intersect the window.

Existing Events serve four purposes:

  • seed the initial state of a device so an Event can continue across window boundaries;
  • preserve the original Event ID, detection time, failure mode, root cause, and other durable metadata when intervals overlap;
  • close open Events for which no detection evidence remains; and
  • protect claim-linked Event records from deletion during overlap cleanup.

Before new detection, overlapping existing Events on the same device are consolidated. The retained Event covers the union of the overlapping intervals. The earliest Event is normally retained, but a claim-referenced Event takes precedence over an unclaimed Event. If more than one overlapping Event is claim-referenced, those records are kept rather than deleting a claim dependency.

4. Building detection flags

Both PV and BESS detection reduce heterogeneous telemetry to a flag for each device at each timestamp. Each flag is True, False, or NA:

  • True: anomalous evidence is present.
  • False: nominal or recovered evidence is present.
  • NA: the method has insufficient evidence.

PV primarily uses power under an irradiance gate, with separate tracker and curtailment paths. BESS creates two independent evidence sets: one from decoded statuses and another from power or availability telemetry. Those results are merged so that True wins, but False combined with NA remains NA rather than being treated as healthy.

The exact detection logic is covered in Event Detection Methods.

5. Hierarchy transformation

The raw device flags are transformed before they become Events:

  1. an active ancestor masks its descendants;
  2. simultaneous flags from every sibling of the same device type can roll up to their parent;
  3. rollup repeats until no higher-level change occurs; and
  4. BESS applies singleton and imputed-parent corrections for particular hierarchy shapes.

The result is not a simple aggregation. NA is used intentionally to express dependence and prevent a masked child from becoming a separate Event. The detailed algorithm and edge cases are in Event Ancestral Hierarchy.

6. Temporal cleanup and Event intervals

The pipeline removes isolated anomalous samples before creating Event intervals. The PV and BESS paths then apply slightly different temporal rules.

PV

PV joins True–NA–True across an interior telemetry gap, but leading or trailing NA does not start or extend a new Event. Consecutive True samples become one interval. A new non-curtailment Event must normally contain at least 15 minutes of POA-qualified anomalous duration. Existing Events and explicitly exempt devices are not discarded by this new-Event duration filter.

BESS

BESS converts consecutive True samples into intervals after removing isolated True samples. A newly detected interval must normally be at least 10 minutes long. BESS additionally applies a six-hour recovery grace period: a recovery gap shorter than six hours is treated as continuous, preventing short nominal periods from prematurely closing an Event.

The BESS Event state still records the distinction between evidence and hysteresis. If an Event is open only because of the grace period, it is pending close. If direct evidence remains anomalous, or is indeterminate, it remains active.

7. Reconciliation with existing Events

New intervals are reconciled with existing intervals per device using half-open overlap semantics. Overlapping intervals are unioned:

  • the earliest start time is retained;
  • if either interval is open, the merged interval remains open;
  • otherwise the latest end time is retained; and
  • existing durable metadata and Event IDs are preferred.

Two intervals where one ends exactly when the other begins are not merged.

Open Events not represented by the current detection results are treated as orphans. They are closed at the analysis start unless they are protected by an asset-specific exception, such as tracker handling, or are already represented by a merged Event. BESS slow-close history is analyzed before this point so short recoveries are not mistaken for orphans.

If interval consolidation makes an existing unclaimed Event redundant, it may be removed. Claim-referenced Events are protected from deletion.

8. Failure-mode assignment

Failure mode describes the first observable cause supported by telemetry; it is not necessarily the physical root cause.

For status-based BESS detection, an abnormal status bit can carry a configured failure mode directly into the Event. When several bits are abnormal, their configured failure modes are retained as candidates and the Event window is used to infer the most representative value. If no specific status-derived mode survives, BESS assigns a device-type fallback such as PCS offline, bank offline, string offline, module-group offline, or module offline; unsupported types receive unknown.

PV assigns failure modes after interval reconciliation. Curtailment is stamped separately so that a generic failure-mode lookup does not overwrite a supported curtailment classification. Tracker stow and other PV modes use their corresponding telemetry and device context.

Root cause remains distinct. It can be populated through later operational analysis, claims, or field findings.

9. Saving Events

The pipeline checks Event state before saving. New Events are created, existing Events are updated, and redundant unclaimed overlapping Events may be removed. Any closed Event whose state is not closed is corrected.

Loss records are stored separately and keyed by Event and timestamp. They are updated in place so repeated analysis can revise recent loss estimates.

10. Loss calculation

PV energetic loss compares expected and actual production, with device- and hierarchy-aware allocation. The calculation prevents overlapping ancestor and descendant Events from double counting the same shortfall and caps allocated loss by the available meter-level shortfall. Curtailment loss uses the curtailment setpoint and is bounded by both expected shortfall and actual shortfall.

BESS currently uses a capacity-based financial proxy. For each five-minute sample in the Event interval, it applies a flat daily value of $0.357/kW/day to the Event device's AC capacity. It also emits a capacity loss record. Project-level BESS Events use POI capacity.

After all per-window processing, recent loss records are coalesced onto the Event:

  • financial loss records become the Event's total financial loss;
  • that total divided by the inclusive number of calendar days becomes daily financial loss; and
  • energetic loss records become the Event's total energetic loss.

The coalesce step covers open Events and Events closed within the recent lookback, currently two days.

11. Notifications and active-Event refresh

PV and BESS notifications are generated only when notifications are enabled. A notification failure does not change the underlying Event interval.

At the end of processing for each project, the operational list of active Events is refreshed from the project's Event records. That list is a derived view rather than the source of truth; the Event and Event-loss records remain authoritative.

Event Detection Methods

Event detection converts telemetry into five-minute device flags that can be anomalous, nominal, or unknown. This page focuses on the evidence models. It is especially important to distinguish BESS status-based detection from BESS status-less detection: they run independently, answer the same availability question from different telemetry, and are merged only after each has produced its own result.

Nullable evidence semantics

Across the current pipeline, a device state has three values:

  • True — sufficient evidence that the device is anomalous or unavailable.
  • False — sufficient evidence that the device is nominal or has recovered.
  • NA — no defensible conclusion from this method at this timestamp.

This is not cosmetic missing-data handling. It controls Event opening, closing, merging, hierarchy behavior, and BESS slow-close state.

For BESS, status-based and status-less flags are combined with three-valued logic:

True  OR anything = True
False OR False    = False
False OR NA       = NA
NA    OR NA       = NA

Therefore, one method can establish an Event even when the other is unknown, but one method's nominal result cannot erase another method's uncertainty.

PV power-based detection

PV power detection asks whether a device is producing a minimum fraction of its capacity while irradiance says it could reasonably be operating.

The current configuration uses:

  • a POA gate of 125 W/m²; and
  • an offline threshold of 0.005 times device or project capacity.

The relevant power channels include meter active power, inverter AC power, inverter-module AC power, and DC combiner power. Device capacity is converted to the units of each channel before comparison.

At each sample:

  • measured power below the capacity threshold and POA at or above the gate produces True;
  • measured power at or above the threshold under qualifying POA produces False;
  • missing measured power produces NA; and
  • samples below the POA gate produce NA, because darkness or low irradiance is not evidence of equipment recovery or failure.

An all-missing device series is treated specially to preserve existing operational behavior: it can be flagged under qualifying POA. Individual missing samples in an otherwise reporting series remain unknown.

Dawn handling

The pipeline guards against nuisance Events during asynchronous startup. For inverter modules, it identifies cases where some but not all sibling modules have started while POA is below 600 W/m² and treats those samples as unknown.

It can also backfill the first daily offline detection by up to 60 minutes using a reduced POA threshold of 75 W/m² (125 - 50). Backfill requires at least two consecutive qualifying samples. This recovers a more realistic Event start without letting a single dawn sample create an Event.

Temporal qualification

An isolated True between nominal samples is removed. During interval creation, an interior True–NA–True sequence is treated as one continuous run so a short communications gap does not fragment an outage. Leading and trailing unknown samples do not independently open or prolong a new Event.

A new PV Event normally requires 15 minutes of anomalous time while POA qualifies. The duration is not simply wall-clock duration: nighttime or below-threshold samples that were carried forward for state continuity are excluded.

Tracker and curtailment paths

Tracker flags compare measured tracker position against the expected true-tracking and backtracking pattern. Localized deviations stay at tracker-row level; simultaneous row conditions may roll up to the tracker zone. Tracker flags join the general PV detection results after the ordinary power hierarchy pass.

Curtailment is detected from curtailment-specific controls and setpoints. Curtailment flags deliberately bypass ordinary hierarchy sweep and rollup so a curtailment classification is not converted into a generic device-offline ancestor Event. Curtailment Events are also exempted from the ordinary minimum-duration rejection when the curtailment evidence overlaps the detected interval.

BESS status-based detection

Status-based detection interprets configured status and alarm tags. It does not infer unavailability from power.

Inputs

Status and alarm tags are retrieved for BESS PCS modules, PCS devices, banks, project breakers, and project reclosers. Each tag has a status lookup that identifies a binary layout. Each bit definition can include:

  • bit position;
  • nominal bit state;
  • human-readable true and false states;
  • description; and
  • a configured failure mode.

Bit decoding

For each observed tag value, every configured bit is inspected. A bit becomes an alert when its actual state differs from its configured nominal state. A bit with no nominal state contributes descriptive status but does not create an alert.

The device flag at a timestamp is True when any of its reporting status tags contains an alert bit. It is False when reporting tags are present and none is alerting. If all relevant tag values are missing, the device flag remains NA.

Status descriptions from multiple tags are merged into one per-device representation. Failure modes from all abnormal bits are de-duplicated. A single mode is represented directly; multiple simultaneous modes remain candidates until Event-level inference.

Window continuity

The status lookup extends six hours before the nominal analysis start so the close decision can observe a sufficiently long recovery. A preexisting open Event seeds its device to True immediately before the retrieved series; that state is then carried forward through missing samples for that preexisting device. A device without a preexisting Event does not receive that assumption.

Missing status telemetry therefore behaves asymmetrically by design:

  • for a new device condition, missing data is not evidence to open an Event;
  • for a preexisting open Event, missing data is not enough to close the Event.

BESS status-less detection

Status-less detection infers unavailability without decoding status words. It uses real-power participation and, when available, charge/discharge availability. The name means “without status telemetry,” not “without state.” It still produces the same three-valued availability state as the status-based path.

The supported target device types are currently:

  • BESS PCS;
  • BESS PCS module group;
  • BESS PCS module; and
  • BESS string.

Each type has configured channels for real power, available charge power, available discharge power, and preferred capacity metadata.

Project activity gate

The project meter establishes whether the plant is active enough to judge a device by participation. Absolute meter power below 10% of project POI is indeterminate for opening a power-based device condition. If POI is unavailable, project AC capacity is used.

Project activity is debounced over 15 minutes with a 90% required fraction. A device group can still use the power path when its peer fleet is demonstrably active, even if the project-level gate is not yet active. The peer fleet is active when median absolute group power exceeds 5% of the group's median device capacity.

Availability path: preferred when supported

When a device has both charge-availability and discharge-availability tags, a valid availability signal, and usable capacity, availability takes precedence over the real-power path.

A device is unavailable when both available charge power and available discharge power are below 5% of device capacity. It is available when either is at or above that threshold.

Opening requires the project activity gate and a 15-minute rolling window with at least 75% unavailable samples. Closing uses a shorter five-minute rolling window with at least 75% available samples and does not require project activity. This asymmetry prevents opening an Event while the plant is idle but permits prompt recovery when availability returns.

Availability is carried forward as a state signal. An entirely missing tag remains missing; the pipeline does not synthesize zero availability from missing telemetry.

Power-participation path

If usable availability telemetry is absent but device power is available, the pipeline compares the device's absolute power with both its peers and a meter-derived reference.

The peer reference is the median absolute power of other devices of the same target type. At least two reporting peers are required. The meter reference is:

abs(project meter power / fleet size × 0.25)

When capacity is known, the meter reference is floored at 5% of device capacity.

With a peer reference, a device is low when its absolute power is below 10% of peer median and, when capacity is known, below 5% of its own capacity. It is active when it clears either of those thresholds. If a peer reference is unavailable, the meter reference is used.

For fleets smaller than ten devices, the rule is more conservative:

  • low power must satisfy both the peer and meter low-power tests; and
  • active power may satisfy either recovery test.

Power entry uses a 15-minute rolling debounce. The required fraction is 95% for small fleets and 90% otherwise. Power exit uses a five-minute window with a 75% required fraction.

Status-less unknowns

Status-less detection returns NA when neither availability nor power provides evidence. The following do not become automatic offline flags:

  • tags that exist but have no values;
  • missing capacity when the selected path requires a capacity comparison;
  • an inactive plant without active peer evidence; and
  • a device type with no supported telemetry path.

The status-less lookup also extends six hours into the lookback and applies the same preexisting-Event continuity seed as the status path.

Merging the BESS paths

Status and status-less detection do not have a primary/secondary relationship. Their results are merged per timestamp and device, after which hierarchy processing and interval creation operate on a single evidence set.

Some practical consequences:

  • an abnormal status bit opens an Event even if power participation looks normal;
  • clear status cannot close an Event while the status-less path is still anomalous;
  • clear status plus unavailable status-less data yields unknown, not healthy;
  • power-based recovery cannot erase an active decoded alarm; and
  • a device with no status configuration can still receive an Event from availability or participation telemetry.

Failure-mode evidence remains path-specific. Status-derived abnormal bits can supply a specific failure mode. A purely status-less Event normally reaches the fallback assignment based on device type.

BESS slow close

After the two BESS paths are merged, BESS uses a six-hour recovery grace period. A False segment following a True segment is treated as continuous until the nominal segment has lasted six hours. This applies across analysis boundaries because both detection paths include the lookback.

The direct evidence before that grace period is retained separately:

  • open plus directly anomalous evidence becomes active;
  • open plus unknown evidence remains active;
  • open plus directly recovered evidence, while the grace period still holds the interval open, becomes pending close; and
  • after six hours of continuous recovery, the end time is set to the first recovered sample and the Event becomes closed.

The close timestamp is the beginning of recovery, not the time at which the six-hour confirmation completes. The grace period changes confidence in closure; it does not bill the confirmation interval as anomalous once closure is established.

Interpreting a detection

For a BESS Event, determine the originating evidence before interpreting the failure mode:

  1. Check decoded status bits and their nominal-state configuration.
  2. Check whether charge/discharge availability was valid; if so, it superseded the status-less power path.
  3. Otherwise inspect meter power, peer median, device power, capacity floors, fleet size, and debounce state.
  4. Compare the status and status-less flags before they were merged.
  5. Inspect the direct evidentiary flag at the end of the window to distinguish active from pending close.
  6. Finally inspect hierarchy transformation, because the final Event device may be an ancestor of the device where the evidence originated.

Event Ancestral Hierarchy

The Events pipeline uses the project device hierarchy to answer a practical question: at what device level is an observed condition most actionable without double-reporting dependent symptoms?

The hierarchy process has two complementary operations:

  • ancestor sweep suppresses descendants while an ancestor is already anomalous; and
  • child rollup replaces a complete set of simultaneous sibling conditions with one parent condition.

These operations occur on time-indexed flags before Event intervals are created. Consequently, hierarchy can affect an Event's device, start, end, continuity, failure mode, and loss attribution.

Hierarchy representation

Each device has a parent and, where available, an ordered ancestry of devices from the project down to itself. The device itself is excluded from its ancestor list.

The parent is used for direct sibling groups and rollup. The full ancestry is used to identify all ancestors, not only the immediate parent. Incorrect or incomplete hierarchy metadata therefore changes attribution even if the telemetry itself is correct.

Operation 1: ancestor sweep

At each timestamp, if an ancestor flag is True, every represented descendant of that ancestor is set to NA.

Example before sweep:

Project: False
PCS:     True
Module:  True
String:  True

Example after sweep:

Project: False
PCS:     True
Module:  NA
String:  NA

The descendants become unknown rather than healthy. False would assert that the child had positively recovered, which is not supported when the ancestor condition can explain the child's behavior. NA prevents dependent child symptoms from becoming separate Events while preserving the distinction from nominal operation.

The sweep considers every ancestor present among the devices being evaluated, so a high-level Event can suppress descendants across multiple hierarchy levels in one pass.

Operation 2: complete-sibling rollup

Rollup groups direct children by both parent and device type. For each group and timestamp, rollup occurs only when:

  1. every configured child of that type under the parent is among the devices being evaluated; and
  2. every one of those children is True at that timestamp.

When both conditions hold, all grouped child flags become NA and the parent becomes True.

Example with three PCS modules under one PCS:

Before: module A=True, module B=True, module C=True, PCS=False
After:  module A=NA,   module B=NA,   module C=NA,   PCS=True

If module C is False, NA, or present in metadata but missing from the devices being evaluated, the complete-sibling rollup does not occur. A sibling missing from metadata cannot be counted at all and may therefore make the configured group appear complete; this is one reason hierarchy metadata quality is critical.

Children are grouped by type. If a parent has two banks and three PCS modules, all banks being anomalous can roll up independently of the module group. The pipeline does not require every child of every type under the parent to be anomalous.

Rollup repeats until no further change occurs. A complete set of module Events can first become a PCS condition; a complete set of PCS conditions can then become a collector, transformer, or project condition on a later iteration.

Project-level BESS exception

BESS treats Project, Meter, and PPC devices as project-level evidence. An active Meter or PPC condition is moved to the Project device even when there is only one such device. This avoids leaving a project-wide condition represented as a meter-component Event.

The PV rollup differs: it avoids ordinary rollup directly into the Project parent. Project-level PV evidence is principally supplied by the meter/project power logic rather than by arbitrary complete child sets.

Singleton correction in BESS

Complete-sibling rollup has a degenerate case: a group containing one child is trivially “all true.” Blindly retaining that rollup would move many Events to a parent that adds no useful aggregation.

After iterative BESS rollup, the singleton correction walks an inferred parent flag back down to its sole child of that type. It repeats until no more moves occur.

There are two important guards:

  • A parent flag that was present in the original evidence remains on the parent. Only a flag inferred by rollup is moved down.
  • Walk-down skips a BESS DC skid singleton. For example, a module condition that rolls through one DC skid to a PCS is allowed to remain on the PCS rather than being forced back to the skid.

This distinction preserves real parent telemetry while correcting hierarchy artifacts introduced by one-child groups.

Imputed BESS ancestors

Some BESS ancestors may not have direct detection telemetry but are still meaningful Event devices. The current imputed-parent device types include:

  • MV collector circuit;
  • medium-voltage transformer;
  • Project; and
  • Meter.

Before intervals are created, the pipeline attempts to derive these parent flags from descendant PCS evidence.

The preferred derivation runs the normal rollup algorithm on leaf flags with existing imputed-parent results temporarily set aside. If ordinary hierarchy rollup reaches the parent, that result is used.

If it does not, a fallback examines all descendant PCS devices:

  • all PCS flags True, or a mixture of True and NA with no False, produces parent True;
  • any PCS False produces parent False; and
  • all PCS NA produces parent NA.

All descendant PCS devices must be present. Missing a PCS series prevents the fallback from asserting a parent condition.

When a parent also has direct status or status-less evidence, inferred evidence is combined carefully:

  • inferred True can establish the parent condition;
  • inferred False is closing evidence; and
  • inferred NA does not overwrite an existing parent True.

The last rule is crucial: missing leaf telemetry cannot erase direct evidence on the parent.

Existing ancestor Events and continuity

Hierarchy must remain consistent across overlapping analysis windows. A child may have current telemetry while its ancestor has an existing open Event but no direct telemetry in the current window.

The BESS path collects all ancestors of flagged devices and relevant existing Event devices, then constructs an ancestor-active mask:

  • if the ancestor has raw telemetry, that telemetry is authoritative;
  • if it is an imputed-parent type, its derived flag is authoritative; and
  • otherwise, existing Event intervals are applied onto the current timestamps.

The six-hour recovery grace period is applied to each ancestor-active mask. While that mask is active, the later ancestor sweep suppresses descendant flags. This prevents a child Event from appearing merely because the current window did not include or produce a direct ancestor tag.

Existing Event intervals use the half-open convention described in Events Overview. A closed ancestor ceases to suppress descendants at its first recovered sample.

Continuity across analysis windows

Before hierarchy processing and interval creation, preexisting Events seed a True value just before the available timestamps. That state is then carried forward from the seed.

This solves a boundary problem: a window that begins in the middle of an Event should extend the existing Event rather than create a new Event at the window start.

Imputed BESS parent Events are excluded from ordinary preexisting seeding. Their current state must be re-derived from the leaves; otherwise a stale imputed parent could perpetuate itself without descendant evidence.

An Event ending exactly at the analysis start is also excluded. Since the end time is exclusive, that Event is already recovered and must not reopen through seeding.

Why NA is central to hierarchy

Hierarchy uses NA for two different but compatible meanings:

  • the detector lacks sufficient telemetry; or
  • an ancestor explains the descendant, so the descendant's independent state is intentionally not asserted.

Both meanings say “do not create an independent Event here.” They differ from False, which says “we have positive evidence of nominal operation.”

This produces several important outcomes:

  • a swept child does not immediately close as healthy merely because its parent is active;
  • a communications gap does not become an outage solely through missing data;
  • all-unknown leaves do not create an imputed parent Event; and
  • a clear child can provide closing evidence for an imputed parent.

Event continuity when parent and child timing differ

Hierarchy is evaluated per timestamp, not once per analysis window. The represented device can therefore change as the condition evolves.

Consider two sibling modules:

  1. Module A fails first, so its flag remains on Module A.
  2. Module B later fails, making every module True; both module flags roll up to the PCS.
  3. During the PCS-level interval, module flags are NA.
  4. Module B recovers while Module A remains failed; complete rollup ends and Module A can again carry a device-level condition.

The reconciliation stage then compares these generated intervals with existing Events. It preserves overlapping Event IDs on the same device, but it does not merge intervals across different devices merely because they share ancestry. Operators may therefore see a child Event followed by a parent Event, or the reverse, when the breadth of the condition changes.

An existing child Event is not automatically deleted just because a later parent Event appears. This is intentional when timing supports distinct addressable conditions. Dependent simultaneous samples are suppressed prospectively by the flag hierarchy, while historical Event reconciliation remains device-specific.

Failure modes and losses after hierarchy

Hierarchy chooses the Event device before final failure-mode fallback and loss assignment.

For BESS, a status-derived failure mode may be inferred over the Event window before device-type fallback. If no specific mode is available after rollup, the ancestor's device type may receive unknown because only PCS, bank, string, module-group, and module types currently have explicit offline fallbacks.

For PV, a rolled PV Block Event is reassigned to the first inverter below the block, optionally through an MV transformer. This is a later correction intended to keep the Event on an actionable inverter device.

Loss allocation also follows the final hierarchy. PV explicitly masks loss on descendants while an ancestor Event is active to avoid double counting. BESS capacity-based loss uses the final Event device's capacity, with Project Events using POI.

When hierarchy attribution looks wrong

When an Event appears on an unexpected device, inspect these items in order:

  1. Verify that the device's ancestry includes every expected ancestor in the correct order.
  2. Verify each device's direct parent.
  3. Verify sibling device types; rollup groups by type as well as parent.
  4. Confirm that every configured sibling is being evaluated and has evidence rather than a gap.
  5. Determine whether the parent flag was direct, rolled up, imputed, continued from an existing Event, or seeded from a preexisting Event.
  6. Check singleton correction and the DC-skid exception.
  7. Check whether a six-hour BESS grace mask is holding the ancestor active.
  8. Inspect the pre-hierarchy and post-hierarchy flags at the exact timestamp.
  9. Finally, inspect Event reconciliation and claim references before concluding that a redundant Event should have been deleted.

The hierarchy output is only as reliable as device metadata. A missing sibling, incorrect parent, malformed ancestry, or wrong device type can prevent rollup, over-suppress descendants, or attach the Event to an inappropriate ancestor even when detection evidence is correct.

Warranty Claims

Use Warranty Claims to prepare, submit, and track claims with equipment manufacturers (OEMs) for a project. A claim records the affected equipment, related events, supporting files, correspondence, and status in one place.

Open a project and go to Maintenance → Warranty Claims. Claims are visible to every company with access to the project.

Set up an OEM

Before submitting a claim, configure the OEM or other counterparty for the project. Select Add OEM and choose the counterparty, then set its preferred submission channel:

  • Email sends the claim by email.
  • Portal records the portal used to submit the claim.
  • Hybrid supports both email and a portal.

Add the OEM's default contact and, when applicable, its portal URL. You can edit an OEM configuration later. An OEM cannot be deleted while claims use it.

Submit a new claim

Select Submit New Claim, then complete the guided workflow:

  1. Select the OEM.
  2. Optionally select related open events. You can include events closed in the last 90 days. Selected events add their affected devices to the claim.
  3. Review the devices and add serial numbers, part numbers, notes, or additional devices as needed.
  4. Review the OEM warranty claim form. If a matching warranty form is available for the OEM, you can use Auto-fill with AI to suggest values from the claim, device, and event information. Review and correct all suggested values before saving the form.
  5. Review the generated site map and attached support files.
  6. Review the delivery details, including recipients and the email message, then submit the claim.

You can save the claim as a draft before submitting it. Draft claims remain editable from the claims table.

For example, for an inverter failure, select the affected inverter's event, confirm its serial number and part number, review the completed OEM form, and send the claim with the supporting documents.

Track a claim

Select a submitted claim from the table to open its detail page. The page shows the claim's OEM, summary, affected devices, attachments, and timeline.

Use Add Update to record a note, OEM message, part update, field visit, submission, or status change. An update can include attachments up to 40 MB each. You can download claim attachments from the detail page.

Claims use the following statuses:

  • Draft: saved but not submitted.
  • Submitted: sent to the OEM.
  • In Progress: being investigated or processed.
  • Resolved: a resolution has been reached.
  • Closed: the claim is complete.

Only draft attachments can be removed directly. Deleting a claim permanently removes its devices, timeline entries, and attachments.

Add a historical claim

Use Add Historical Claim to bring an existing claim into Proximal. Choose the OEM, upload the claim form and supporting PDFs, and select Analyze with AI. The analysis suggests claim details, devices, related events, and timeline entries. Review and edit every suggestion, choose the historical claim status, then create the claim.

Historical claim uploads accept PDF files up to 40 MB each. The original files are attached to the created claim.

Deal Rooms

Deal Rooms provide a controlled workspace for running a project sale or other buyer diligence process. A room brings together the linked projects, a structured data room, buyer participants, and a Q&A workflow so the seller can share the right information as the process progresses.

Who uses a deal room

  • Seller team members organize the room, add buyer companies, manage the data room, and respond to diligence questions.
  • Investment bank users, when included, can participate in managing the process according to the permissions assigned to them.
  • Buyer users can view the information made available to their company and ask and track their own diligence questions. They cannot see other buyers' questions or restricted documents.

Your company administrator creates a deal room. Within the room, permissions determine which seller and bank users can manage it and which buyer companies can access it.

Create a deal room

  1. Open Deal Rooms and select New Deal Room.
  2. Select one or more projects, then enter a name and optional description.
  3. Select Create.

You can also add an off-platform asset during creation when the transaction includes an asset that is not already available in Proximal. Provide its project type, location, interconnection limit, relevant capacity values, and, optionally, commercial operation date.

The new room starts in Draft. Use the room's Participants and Settings tabs to prepare access before inviting buyers.

Organize the data room

Use the Data Room tab to create a folder structure and upload diligence materials. Seller-side users with upload access can:

  • create, rename, move, and remove folders;
  • upload, rename, move, and remove documents;
  • browse and search the files in the room; and
  • control whether a document may be downloaded.

Buyers can only browse folders and documents available to their current phase. They can download files only when the seller has enabled buyer data-room downloads and the individual files allow downloads. Large downloads may be prepared as an export rather than being delivered immediately.

PDFs can be processed for in-product viewing and used as supporting material for Q&A. Processing may take time after upload; a document is not immediately available as a Q&A source while it is still being processed.

Add and advance participants

On the Participants tab, add a buyer company and a contact. Send the buyer an invitation from the participant's detail panel. You can then move the buyer through the process stages:

  1. Prospecting
  2. Invited
  3. Round 1
  4. Round 2
  5. Exclusivity

Advancing a buyer can also advance the deal room's status. Before confirming a move, Proximal shows the folder and project-data access that will be granted or removed. Removing a buyer company revokes its access to the deal room.

Control access by phase

In Settings, configure the folders and linked-project data available at each buyer phase. Folder access controls what buyers can browse in the data room. Project-data access can separately enable access to Proximal, raw-data downloads, or the API for each linked project.

When a room is Closed, buyer access to deal-room files and project data is revoked. You can also configure exclusivity cleanup so that moving one buyer to Exclusivity removes earlier-stage access for other buyers.

Manage diligence Q&A

Buyers use the Q&A tab to submit questions for a selected asset or for the general transaction. They can filter and review only their own company's questions and responses. A buyer can also import questions from a CSV template that contains these columns:

Asset, Subject, Question, Priority

Seller-side users can group questions by topic, assign owners, draft and post answers, and attach document references. The Q&A workspace can suggest a topic, identify similar questions, retrieve supporting snippets from room documents, and prepare an AI draft. Treat every AI draft as a starting point: review its content and references before posting an answer to a buyer.

Example workflow

A seller creates a room for a solar project and adds an investment bank. The seller uploads a first-round data package, then configures that folder for Round 1 access. After adding each prospective buyer and sending invitations, the buyers can review the first-round files and submit questions. The seller routes questions to subject-matter experts, uses the cited documents to prepare answers, and posts the reviewed responses. When a buyer progresses to Round 2, the seller grants the next folder and any appropriate linked-project access without exposing those materials to other buyers.

Aria Chat

Aria Chat is an assistant for investigating the project you currently have open in Proximal. It can help you explore project performance, equipment, events, and other operational information without leaving the project workspace.

Start a conversation

  1. Open the project you want to investigate.
  2. Select Aria in the project navigation.
  3. Enter a question in the chat box.
  4. Press Enter or select Send.

Aria uses the context of the open project. Switch to the relevant project before asking about its data or operations.

Clear questions produce more useful answers. Include the relevant time period, equipment, or metric when possible. For example:

What were the largest production-impacting events at this project last week, and which ones are still open?

Aria's response may include text, tables, charts, record summaries, and related questions. Select a related question to continue the investigation.

Work with a response

Aria displays its progress while preparing an answer. Wait for the response to finish before relying on it.

To stop a response, select Stop in the chat box or press Escape. If you send another message while Aria is working, the message is placed in a queue. After the current response finishes, select Steer to send the queued message, or remove it if it is no longer needed.

Aria can make mistakes. Verify critical answers against project records and source data before taking action.

Use conversation history

Recent conversations for the open project appear in the navigation panel. Select a conversation to reopen it. On smaller screens, open the navigation panel to see recent conversations.

  • Select New conversation to start with an empty chat.
  • Select the delete button beside a recent conversation to remove it.

Export a conversation

After sending a message, use the export button at the top of the chat to:

  • copy the conversation as Markdown;
  • download the conversation as a Markdown file.

The export includes conversation content and diagnostic details. Review it for sensitive project information before sharing it, and attach it to a support request when troubleshooting an Aria response.

Keyboard controls

  • Enter sends a message.
  • Shift+Enter adds a new line.
  • Command+K on macOS or Ctrl+K on Windows focuses the chat box.
  • Escape stops a response that is in progress.

Aria Memory

Aria Memory gives Aria project-specific context that it can use when answering questions. There are two types of memory:

  • Semantic Memory contains reference documents such as equipment manuals, datasheets, and warranties.
  • Episodic Memory captures project-related information from email conversations. This feature is in development and is not yet searchable in Aria Chat.

Both types of memory are associated with specific projects so Aria only uses information in the appropriate project context.

Semantic Memory

Semantic Memory lets Aria search project reference documents when answering questions. Memory is scoped to the open project, so upload a document to the project where it should be used.

Good candidates for Semantic Memory include equipment manuals, equipment datasheets, warranties, and other reference material used to understand the project's equipment and operations.

Add a document from Aria Chat

  1. Open the relevant project and select Aria.
  2. Select the upload button in the upper-right corner.
  3. Choose a document.
  4. Complete the document metadata.
  5. Select Upload.

A confirmation appears when the upload succeeds. Allow up to five minutes for a new document to become searchable.

Add and manage project documents

Documents added from project settings are also included in Semantic Memory.

  1. Open the relevant project.
  2. Go to Settings → Documents.
  3. Select Upload Document.
  4. Choose one PDF, complete its metadata, and select Upload.

Each project-settings upload accepts one PDF up to 40 MB. The Documents page lists uploaded project documents and lets you open them. Users with delete permission can remove a document from the project and Semantic Memory.

Uploaded project documents are visible to all users in your company. You need document-upload permission to add them from project settings. If the upload button is disabled, contact an administrator.

Choose document metadata

Metadata helps Aria determine when and how to use a document:

  • Status: Choose Active, Superseded, or Archived. Use Active for the current document and update the status when it is replaced or retired.
  • Language: Choose English or Spanish to match the document.
  • Valid until: Add an expiration date when the document is only valid for a limited period. Otherwise, leave this blank.
  • Document type: Choose the closest available type. If left blank, the document is treated as Miscellaneous.

Available document types depend on where you upload the document. Common types include Equipment datasheet, Equipment manual, Miscellaneous, and Warranty.

Ask Aria about a document

After indexing is complete, identify the document or equipment in your question. For example:

According to the active inverter manual, what does alarm code 42 mean?

If Aria cannot find a newly uploaded document, wait five minutes and try again. Also confirm that you uploaded it to the project currently open in Proximal and that its metadata reflects how it should be used.

Episodic Memory

Episodic Memory is being developed to give Aria context from project-related email conversations. When complete, users will be able to include Aria on an email thread so that eligible messages become searchable within the relevant project.

Availability: Email receipt and project routing are under development, but accepted emails are not yet added to searchable Aria Memory. Do not rely on this feature to preserve or retrieve project information yet.

Start a project email thread

The planned production workflow uses aria@inbox.proximal.energy.

  1. Start the email from the address associated with your Proximal account.
  2. Add aria@inbox.proximal.energy as a recipient.
  3. Add the project's short name in square brackets to the subject. For example: [SUNSET] Weekly construction update.
  4. Write the project information in the plain-text body and send the email.

You can associate an email with more than one project by adding multiple project tags, such as [SUNSET] [RIVER] Shared procurement update. You must have access to every tagged project when starting the thread.

When the first email is accepted, Aria sends the initiating user a confirmation email. If no project tag matches, Aria responds with the projects available to that user and the tags to use.

Continue a monitored thread

Keep Aria included on replies and retain at least one of the original project tags in the subject. Aria identifies the conversation from its email-thread headers, not from the subject alone.

After an eligible user starts a thread, people without Proximal accounts can participate in later replies. If a reply loses all of the thread's project tags, Aria stops monitoring the thread and notifies the user who started it.

Email content and visibility

Episodic Memory currently reads the email subject and plain-text body. It does not use attachments or HTML-only content, so include important information in plain text.

Memories remain associated with the tagged projects. Within a company, eligible project information can be shared with other users of that company. For cross-company email threads, include registered Proximal users in To or Cc so their company's visibility can be established for the tagged projects. Unregistered recipients do not extend memory visibility.

Aria only considers recipients on messages where it is included. Adding Aria later does not import earlier messages from the thread.

If an email is not accepted

Aria may not accept an email when:

  • the first sender is not an active Proximal user;
  • the subject does not contain a matching project tag;
  • the sender cannot access every tagged project;
  • the email cannot be authenticated; or
  • a later reply no longer contains one of the original project tags.

Aria sends guidance for some of these cases, including an unmatched project tag or a thread that lost its tag. Other rejected messages may not receive a response.

Public MCP OAuth provisioning

The public MCP endpoint is https://mcp.proximal.energy/mcp. Clerk authenticates the human user's identity and client they are using, for example Claude or Codex. The public AgentCore Gateway validates the Clerk access token, and its request interceptor exchanges that token for a short-lived, KMS-signed Mono delegation token. The original Clerk credential stops at the Gateway. Mono authorizes the actual operation and the user's access to its project and resources.

Web-app authentication flow:

  • User → Aria web app → Clerk sign-in → Clerk session → Aria

MCP authentication flow:

  • User → Client → Clerk sign-in → Oauth Token → Agentcore Gateway

Clerk instances and current setup

EnvironmentClerk issuerClient ID Metadata Document clients
Staging (Clerk development)https://concrete-snapper-8.clerk.accounts.devhttps://chatgpt.com/oauth/client.json, https://claude.ai/oauth/claude-code-client-metadata
Productionhttps://clerk.proximal.energyThe same two client IDs

As of September 23, 2026, both instances require authorization code with S256 PKCE, issue signed OAuth access tokens, are configured to include an audience when the client requests a resource, and have a configured Clerk Account Portal for sign-in and consent. Both advertise Client ID Metadata Document support and admit only pre-registered clients. Dynamic client registration is disabled. Clerk adds offline_access to Client ID Metadata Document clients.

The default custom scopes for clients that omit scope are mcp:connect and endpoint:read. No write scope is defined or granted for the initial release. Both custom scopes are Advertised in Clerk, and each reviewed client is limited to them. Clerk also requires offline_access for these clients.

External scopeIntended internal delegated scopeMeaning
mcp:connectmcp:connectEnter the MCP Gateway; does not authorize every tool.
endpoint:readendpoint:readUse any read-only MCP tool, subject to the user's normal data permissions.

The interceptor must explicitly allowlist this external-to-internal mapping and use only scopes Clerk actually granted. Unknown or ungranted scopes confer no Mono authority. The validated OAuth client_id must map to a canonical client value: https://chatgpt.com/oauth/client.json to chatgpt, and https://claude.ai/oauth/claude-code-client-metadata to claude-code. Do not derive client identity from request headers, tool arguments, or the token audience. The delegation token names the user, trusted actor, canonical client, allowed scopes, and request identifiers; it does not need a predetermined MCP tool claim. Mono resolves the actual operation before checking its required scope. Every initial read-only operation requires endpoint:read.

Deployment inputs

The following non-secret Parameter Store values are in us-east-2:

PathValue
/auth/clerk/prod/issuerhttps://clerk.proximal.energy
/auth/clerk/prod/mcp-audiencehttps://mcp.proximal.energy/mcp
/auth/clerk/prod/mcp-allowed-clientsThe two Client ID Metadata Document URLs above, comma-separated.
/auth/clerk/staging/issuerhttps://concrete-snapper-8.clerk.accounts.dev
/auth/clerk/staging/mcp-allowed-clientsThe same two Client ID Metadata Document URLs, comma-separated.

Clerk places the requested OAuth resource in the access token's aud claim. Clients must request the public MCP resource above; the Gateway validates that exact audience. Staging still needs a stable resource URL before /auth/clerk/staging/mcp-audience can be set. The interceptor stacks also need /auth/mono-delegation/{staging,prod}/issuer and /auth/mono-delegation/{staging,prod}/audience, coordinated with Mono's token validator. The signing keys are created by the interceptor stacks.

Client admission

For each new client, review its HTTPS Client ID Metadata Document, redirect URIs, and token authentication method. Pre-register the exact document URL in Clerk's OAuth applications > Applications tab, assign only mcp:connect and endpoint:read, and add the exact client ID to the Gateway allowed-client parameter. Clerk's settings must keep admission at Pre-registered clients only. Enable dynamic client registration only if a required client cannot use a metadata document or a manually registered client ID; it exposes a public registration endpoint.

ChatGPT publishes https://chatgpt.com/oauth/client.json, which was reviewed and pre-registered. Clerk provides a Claude Code preset. Cursor has not been registered: establish its current registration method and redirect URI before adding it. A custom client likewise needs a published metadata document or a manually registered client ID. Neither client should be added to the Gateway allowed-client list before its Clerk configuration is reviewed.

Remaining work

The two custom scopes, default grants, and ChatGPT/Claude Code registrations are configured in both Clerk instances. Authorization-server discovery has been checked for both issuers: it advertises those two custom scopes and metadata- document support, and no dynamic registration endpoint. This does not yet verify sign-in, token issuance, or MCP connectivity. The unchecked items below are the remaining work; task numbers refer to aria/scaffold.md.

Configuration and deployment

  • Choose the stable staging MCP resource URL and set /auth/clerk/staging/mcp-audience in us-east-2. Clients must request that exact URL as their OAuth resource.
  • Agree on the Mono delegation issuer and audience for staging and production, then set /auth/mono-delegation/{staging,prod}/{issuer,audience} in us-east-2. Match these values in the token issuer and Mono validator.
  • Complete Mono's delegation settings, verification-key injection, token validation, delegated-agent authentication, project-access cache, request identity, operation-level endpoint:read enforcement, and request-context wiring (Tasks 8-16). Normal Clerk and API-key callers must retain their existing behavior.
  • Complete the single shared MCP server and canonical read-only tool registry: package the plugin, use one Mono client and trusted delegation path, require explicit project_id on project tools, add project discovery and generated read tools, and serve both Gateways from the same Runtime (Tasks 17-26). Do not expose mutating or dashboard-only tools.
  • Bind Aria's trusted current project into the same canonical tools without changing their public schemas, and verify the shared Runtime, catalog, scope coverage, and credential propagation (Tasks 27-29).
  • Add non-blocking MCP telemetry storage and instrumentation without storing credentials or treating telemetry as audit history (Tasks 30-32).
  • Replace raw Clerk-token forwarding in internal Aria with project-bound delegation and complete its shared MCP execution path (Tasks 33-35).
  • Deploy the shared MCP service and Mono changes, then the staging and production interceptor, Gateway, and target-sync stacks. Deploy the production public edge stack in us-east-1; these seven public MCP stacks are not deployed yet. Confirm pipeline dependencies and stack outputs before exposing the endpoint.

Client admission

  • Establish Cursor's current registration method and redirect URI. Review it, register it in Clerk, grant only mcp:connect and endpoint:read, and add its exact client ID to the Gateway allowlist.
  • Do the same for at least one custom MCP client. Keep dynamic registration disabled unless a required client cannot use a metadata document or manually registered client ID.

Launch verification

  • Fetch https://mcp.proximal.energy/.well-known/oauth-protected-resource/mcp after the edge deploys; confirm the resource URL and Clerk authorization server. Check the equivalent staging metadata at its chosen URL.
  • Complete sign-in, consent, callback, and token issuance with ChatGPT and Claude Code in staging and production. Verify the issued token's signature, issuer, audience, client ID, subject, and the two granted MCP scopes. Starting an authorization redirect alone is insufficient.
  • Confirm the Gateway rejects a missing mcp:connect, an unregistered client, a wrong audience, and an unsigned token. Confirm every read-only tool requires endpoint:read, reaches Mono with only the internal delegation token, and still obeys the user's current project and resource permissions.
  • Run production MCP connectivity and canonical-tool-catalog checks with ChatGPT, Claude Code, Cursor, and the custom client (Task 36).
  • Confirm internal Aria still works through its existing Gateway and shared Runtime using project-bound delegation, not a raw Clerk token (Task 37).
  • Verify the validated execution context needed for future auditing survives the full request path; do not implement audit storage yet (Task 38).

There is one canonical MCP tool registry and one shared Runtime per environment. The initial canonical tools are read-only. Dashboard-only capabilities remain agent built-ins and never appear in MCP tool discovery. ClickHouse holds asynchronous operational telemetry, not authoritative audit history. Authoritative auditing is deferred; the validated request context must remain available for it later.

See Clerk's OAuth setup, Clerk's metadata-document guide, and AgentCore's inbound token validation.

BESS Revenue on Portfolio Home

Use the BESS table on Portfolio Home to compare revenue across battery projects. The table shows month-to-date (MTD) and year-to-date (YTD) revenue for each BESS or PV-plus-storage project, alongside availability and open-event information.

Choose a revenue source

Use the selector in the BESS table's Revenue header to choose the revenue view:

  • Total adds the physical and virtual revenue values for each day.
  • Physical shows only the physical revenue value.
  • Virtual shows only the virtual revenue value.

The Average Revenue summary card and the BESS section of a downloaded CSV use the selected source. For example, select Physical to compare the physical MTD and YTD revenue of your battery projects, then download the CSV to share that same view.

For a PV-plus-storage project, the BESS table shows $0 in the Virtual view. Its PPA-based PV revenue remains available in the PV table and PV section of the CSV.

Interpret the values

MTD includes daily revenue from the first local calendar day of the current month through the completed local day before today. YTD uses the same approach from the first local calendar day of the year. Proximal uses each project's time zone when grouping daily values.

Total treats a missing physical or virtual value as $0 for that day. If both values are missing, that day is not included.

Choose to view the unnormalized amount. A project needs a positive POI capacity to show a $/kW value.

Availability and access

BESS revenue is available only when the project's QSE integration is configured.

Custom Dashboards

Custom Dashboards let you build a project-specific view of the metrics and telemetry you monitor most often. Use them to keep related operational charts, KPIs, and notes together instead of switching between separate product pages.

Custom Dashboards are available only for projects where they have been enabled. If the Custom Dashboards page says the feature is unavailable, use the feedback button in Proximal to request access.

Create a dashboard

  1. Open the relevant project and select Custom Dashboards.
  2. Select New Dashboard.
  3. Enter a dashboard name and choose defaults for the chart and KPI time ranges.
  4. Select Add Component and configure the components you need.
  5. Drag or resize components to arrange the layout.
  6. Select Save Layout.

Use Edit Layout on an existing dashboard to change its name, time ranges, components, or arrangement. Select Exit Without Saving to discard changes made during the current edit session.

Add components

Choose Add Component while editing a dashboard. Available component types are:

  • Line chart: Plot one or more sensor traces over time. Choose a sensor type and aggregation for each trace. When aggregation is None, you can limit the trace to individual tags and add optional minimum and maximum thresholds.
  • Bar chart: Compare an aggregated sensor value across the project's devices.
  • Scatter plot: Compare two sensor types. Large selections are sampled to 1,000 representative points, so use the plot to investigate patterns rather than as a complete point-by-point export.
  • KPI card: Show one of the project's visible KPIs. Selecting a card while viewing the dashboard opens that KPI's detail page.
  • Gauge: Compare metered energy with expected energy. This component is available only when the project has an expected-energy integration.
  • Rich text: Add formatted headings, context, assumptions, or handoff notes alongside the data.

The chart date control is available while viewing a dashboard. Chart components use the selected range, which can cover up to three days. KPI cards use the dashboard's KPI time-range default: one month, month to date, year to date, or beginning of life.

Build a draft with Aria

While editing, select Build with Aria and describe the dashboard you want. For example:

Create an operations overview with production trends and key metrics.

Aria can add or revise the dashboard during that edit session, and you can ask follow-up questions to refine the draft. Review the resulting components, configuration, and layout before selecting Save Layout. Aria's changes are not saved automatically, and Exit Without Saving discards them.

Share, duplicate, and remove dashboards

Dashboard owners can use the actions on the Custom Dashboards page to:

  • share a dashboard with other users in their company;
  • update or remove access for people it has been shared with;
  • duplicate a dashboard in the current project or in other projects they can access; and
  • delete a dashboard they own.

Dashboards shared with you are listed under Shared with me. You can view a shared dashboard, remove it from your own list, or duplicate it to create an editable copy. Only the owner can edit or delete the original shared dashboard.

When you duplicate a dashboard to another project, review every component before using it. In particular, line-chart tag selections may need to be chosen again for the destination project.

Example

An operations manager creates a Morning review dashboard for a solar project. They add a metered-versus-expected-energy gauge, a KPI card for performance ratio, line charts for production and irradiance, and a rich-text note describing the day's planned maintenance. They share the finished dashboard with the project team so everyone starts the review with the same project context.

KPI Overview

KPIs (Key Performance Indicators) are a set of metrics that are used to measure the performance of a system. Calculated on a daily basis, KPIs can be used to characterize a system either at a point in time or to trend data over a longer period.

KPIs are separated into two categories: Benchmark & Contractual.

Benchmark KPIs are used to characterize a system's performance relative to itself and other projects in a user's portfolio. These KPIs are consistent across all projects. Proximal intends to provide industry-supplied values to compare an individual project or portfolio to.

Contractual KPIs are used to track the specific behavior of a system or component as defined by a contract between two parties. These KPIs are project-specific, and are created by the Proximal team individually for each project. As such, documentation for these KPIs cannot be found in these pages, but will be more thoroughly documented in the KPI page on the Proximal platform. These KPIs are not available for benchmarking against other projects, nor industry standards. They have an associated contract available to view, and typically have an incurred liquidated damages calculation as well as the liable party.

Contractual KPIs

Contractual KPIs track performance requirements defined in contracts for a specific project. Proximal configures these KPIs for each project. They are not portfolio or industry benchmarks.

KPI page

The Contractual KPI page shows the KPI name and description. Select the performance-data year to view the annual performance chart and the contracts associated with that KPI.

Each associated contract has its own panel. The panel identifies the counterparty and contract execution date. When a contract document is available, it is displayed in the panel and can be opened for a larger view. If no document is available, the panel shows that it is unavailable.

Each panel has the following tabs:

  • Threshold shows the contract-defined performance targets.
  • Remedies shows contract-configured liquidated-damages information.
  • Claim shows the configured submission method, timeframe, and required information.

Remedies and Claim details may not be specified for every contract. Proximal does not calculate damages or submit claims from this page.

Thresholds

Thresholds can be configured in one of two ways:

  • Discrete annual targets show the target for each year.
  • Surface-by-device targets define a guarantee surface of warranty year (x), cycles per year (y), and guaranteed value (z). Each device has a warranty start (x_origin) and optional pre-telemetry cycle offset (y_origin).

Surface-by-device evaluation

For surface-by-device targets, the current period is the device's current warranty year: the largest tabulated x that is less than or equal to the years since that device's x_origin.

Historical cycles per year are:

(y_origin + measured string cycle count through the as-of date) / years since x_origin

Measured cycles come from the BESS_STRING_CYCLE_COUNT KPI. Missing y_origin is treated as 0.

The guaranteed value at that warranty year is linearly interpolated between neighboring tabulated cycle-count (y) points. Cycle counts outside the tabulated range are clamped to the nearest edge.

The performance and annual charts draw one applied threshold line: the simple mean of per-string guaranteed values. Strings that cannot be evaluated are omitted from the mean. If cycle data is not available, the charts fall back to showing every tabulated cycles-per-year slice.

The Threshold tab keeps the contract surface as a reference: device warranty dates, cycles at connection, and a cycles-per-year selector to explore tabulated z values.

The Applied Device Thresholds table shows the current, time-specific evaluation for each string: warranty year, historical cycles per year, guaranteed SoH, latest actual SoH, and margin. Rows below the guaranteed floor are highlighted.

If threshold data is unsupported or missing, it is shown as unavailable.

Availability of contract details

Contract documents, thresholds, liquidated-damages information, and claim instructions depend on the contract configuration for the project. When any of these details are absent, the Contractual KPI page shows them as unavailable or not specified.

PV

Combiner Field Health KPI

Description

The Combiner Field Health KPI measures the DC health of a project based on combiner current data. Each combiner receives a daily health score ranging from 0 to 1, where a score of 1 indicates the healthiest combiners on the project.

Methodology

  1. Retrieve DC combiner current data for each combiner box on a 5-minute interval. The data is filtered to focus on the time window from 11:30 AM to 12:30 PM to capture peak irradiance conditions.
  2. Normalize each combiner's current against its own DC capacity to account for differences in combiner size.
  3. Identify the "ideal" combiner by calculating the 99th percentile of all normalized combiner currents. The 99% threshold is chosen to exclude outliers and focus on typical combiner performance.
  4. Normalize all combiners' ratios against the ideal combiner. This gives the ideal combiner a score of 1.0, with all other combiners having a score ranging from 0 to 1. Outliers may exceed a score of 1.0.
  5. Calculate the daily mean score of each combiner trace to calculate the overall DC Field Health for each combiner on that day.
  6. Calculate the mean of all combiner scores to derive the overall DC Field Health for the project on that day.

Trackers

Description

Tracker KPIs are used to monitor performance of single-axis trackers. Multiple KPIs are calculated for each project.

  1. Row position deviation from setpoint.
  2. Row setpoint deviation from the project median setpoint.
  3. Row availability (when the prior two metrics are both less than 5°).

These KPIs can help identify offline trackers, errant zone controller setpoints, and communication issues.

Filters

To exclude time periods when trackers are not in use, any time intervals in which the sun elevation angle is less than or equal to 0° are excluded from the calculations.

Position Deviation from Setpoint

  1. Query 5-minute position and setpoint data for each row.
  2. Compare position to setpoint for each 5-minute interval for each row. Average the absolute value of the difference between these values for the entire day.
  3. Aggregate each tracker row into blocks, averaging the values again.

Setpoint Deviation from Median

  1. Query 5-minute setpoint data for each row.
  2. Calculate the median setpoint for the project.
  3. Compare setpoint to project median for each 5-minute interval for each row. Average the absolute value of the difference between these values for the entire day.
  4. Aggregate each tracker row into blocks, averaging the values again.

Availability

  1. Query 5-minute position and setpoint data for each row.
  2. Compare position to setpoint for each 5-minute interval for each row.
  3. If both the position and setpoint deviations are less than 5° for a given interval, the row is considered available.
  4. Aggregate each tracker row into blocks, averaging the values again.

Specific Yield KPI

Description

The Specific Yield KPI quantifies how much AC energy is delivered per unit of installed DC capacity. It provides a normalized metric for evaluating site performance independent of plant size and is especially useful for comparing across projects.

This KPI is calculated daily and expressed in units of kWh/kWp.

Methodology

  1. Retrieve time-series data for:

    • meter_active_power: AC power delivered by the site over the day.
  2. Clean and aggregate the data:

    • Clip negative values to zero to eliminate erroneous readings.
    • Resample data to hourly averages to standardize granularity.
  3. Calculate total energy delivered:

    • Integrate the hourly AC power measurements to get total daily energy output in kWh.
  4. Normalize by DC capacity:

    • Divide the total energy output by the site’s installed DC capacity (also referred to as kW-peak, or kWp) to get the specific yield.
  5. Compute Specific Yield:

    • The formula is:

  6. Store the KPI result:

    • The resulting value is stored as a project-level KPI for the corresponding date.

Performance Ratio KPI

Description

The Performance Ratio KPI quantifies the overall efficiency of a PV site by comparing the actual energy produced to the theoretical maximum possible under prevailing irradiance. This KPI helps identify underperformance due to issues such as soiling, inverter clipping, or balance of system losses.

The KPI is calculated daily and results in a dimensionless number typically between 0 and 1, where 1 represents a perfectly efficient system.

Methodology

  1. Retrieve time-series data at hourly resolution for:

    • meter_active_power: Total AC power delivered by the site.
    • met_station_poa: Plane-of-array irradiance from on-site weather stations.
  2. Clean the data by:

    • Removing any columns (sensor streams) where the maximum value is less than or equal to 0.
    • Clipping all negative values to zero to remove erroneous negative readings.
    • Averaging the values to a uniform hourly granularity.
  3. Calculate Specific Yield:

    • Total AC energy delivered by the site (sum of meter_active_power across all meters) divided by the total DC capacity of the project.
    • Units: kWh/kWp
    • See also: Specific Yield
  4. Calculate Reference Yield:

    • Total POA irradiance summed across all sensors, averaged, and then normalized by a reference peak irradiance value of 1000 Wp/m² (Watt-peak per square meter).
  5. Compute Performance Ratio:

    • This results in a dimensionless efficiency metric.
  6. Store the KPI result:

    • The daily PR value is inserted as a project-level KPI for the given date.

BESS

State of Charge

Description

State of Charge (SOC) KPIs monitor BESS performance and health. Two key metrics help identify utilization patterns and operational efficiency:

  1. Average SOC - The mean state of charge over a time period
  2. Resting SOC - The state of charge when the battery is idle

Average SOC

Why It Matters

  • Battery Health: Extreme SOC levels (very high or very low) accelerate battery degradation
  • Longevity: Operating within optimal SOC ranges extends battery lifespan
  • Performance: Consistent extreme SOC can reduce capacity and power capability over time

How It's Calculated

  1. Collect SOC data at regular intervals
  2. Calculate the arithmetic mean for the time period

Resting SOC

Why It Matters

  • Battery Stress: Prolonged storage at extreme SOC levels causes chemical stress
  • Aging: High resting SOC increases calendar aging, low resting SOC can cause capacity fade
  • Safety: Extreme resting SOC levels may indicate potential safety concerns

How It's Calculated

  1. Collect SOC and power flow data
  2. Identify periods with minimal power flow
  3. Calculate mean SOC during these resting periods

Depth of Discharge KPI

Description

The Depth of Discharge (DoD) KPI quantifies the average depth to which a battery storage system is discharged during a given day. It is calculated as the inverse of the average State of Charge (SOC). A higher DoD indicates that the battery is being used more deeply, while a lower DoD suggests more conservative usage.

This KPI is useful for assessing operational behavior and wear-and-tear on battery storage systems. It is reported daily as a percentage between 0 and 1, where 1 means fully discharged on average, and 0 means fully charged on average.

Methodology

  1. Retrieve time-series data for:

    • project_soc_percent: The State of Charge (%) of the project’s battery storage system.
  2. Convert timestamp index:

    • The index is converted to the project’s local timezone for consistent daily aggregation.
  3. Calculate average SOC:

    • Take the mean of all State of Charge (SOC) readings for the day. SOC values are expected to be in the range [0, 1].
  4. Calculate Depth of Discharge:

    • DoD is the complement of SOC:

    • The result is rounded to four decimal places.

  5. Store the KPI result:

    • The daily average DoD is inserted as a project-level KPI for the corresponding date.

Project Cycle Count KPI

Description

The Project Cycle Count KPI estimates the number of full charge-discharge cycles a battery storage system performs in a single day. This KPI is essential for understanding battery utilization and degradation over time.

The KPI is calculated daily and reported as a floating-point number, where 1.0 represents one full cycle (100% discharge followed by 100% recharge, or equivalent cumulative partial cycles).

Methodology

  1. Retrieve time-series data for:

    • project_soc_percent: The State of Charge (%) of the project’s battery system over the day.
  2. Convert timestamp index:

    • The index is standardized to ensure consistent time stepping.
  3. Calculate absolute changes in SOC:

    • Take the absolute difference in SOC between each pair of consecutive time steps.

  4. Sum the absolute changes and normalize by 2:

    • The total cycle count is estimated by summing all absolute SOC changes and dividing by 2. This accounts for the fact that a full cycle consists of both discharge and charge.

  5. Round and store the KPI result:

    • The daily cycle count is rounded to four decimal places and stored as a project-level KPI for the given date.

Reports Overview

Reports are automated, or semi-automated, studies performed by the Proximal platform which can keep you informed about the health of various aspects of the power plant. These reports generally have intelligent data filters which can be modified by a human in the loop.

The outputs of these reports are generated so that they can be shared with internal and external stakeholders who may or may not have access to the Proximal platform. The XLSX and CSV download features allow users to take the data generated by a report and do further manual analysis.

The PV PR Test Report is a dataset-preparation workflow for an external (typically PVSyst) performance-ratio test: it applies automatic and manual validity filters and exports weather, production, energy, and filter-audit files. It does not compute the contractual PR inside Proximal.

DC Amperage Report

Overview

This report shows the normalized current at every combiner at the PV power plant filtered for clearsky conditions. Combiner current is normalized based off of the nameplate capacity of each combiner. This makes it so that combiners with different amounts of dc capacity can be compared against one another on an apples-to-apples basis.

Different combiners may have different DC capacity due to differences in the number of strings attached to each combiner, module bin class, etc.

Filters

The analysis is generated with user input for clearsky data on a given day. Users may select thresholds for minimum POA, maximum POA derviative, and maximum POA derivative standard deviation. The input data is sampled at 5-minute intervals by default, which can be changed via the settings dropdown located in the filters card. The maximum POA derivative and maximum POA derivative standard deviation thresholds may be turned off at the risk of reduced report accuracy.

POA derivative is the rate of change of POA with respect to time. A lower POA derivative indicates a more stable POA, correlating to fewer moving clouds over the array. Proximal recommends a maximum POA derivative of 1 W/m^2^/minute.

POA derivative standard deviation is the standard deviation of the POA derivative over each 5-minute interval. A lower POA derivative standard deviation indicates that all sensors are moving in a similar way at the same time, indicating that the entire site is experiencing similar sky conditions. Proximal recommends a maximum POA derivative standard deviation of 1 W/m^2^/minute.

Both POA derivative and POA derivative standard deviation are calculated using the selected sample rate of the data, then aggregated to a 1-hour moving average.

Calculation

This report is calculated by pulling the 5-minute combiner current data, finding the nominal string current at the maximum voltage of the modules, then normalizing the actual current by the nominal string current. This normalization is then compared to the median combiner current for either the inverter associated with that combiner or the site as a whole. The intermediate calculations are available in the output XLSX file.

Outputs

By default, this report shows the normalzied DC performance of each combiner compared to its peers on the same inverter. Via the settings dropdown, this normalization can be changed to compare to the combiner performance of the entire site. Results are displayed as a normalized value, where 1.0 indicates that the combiner is operating at an equal level to the median combiner. Combiners colored in green are performing within 5% of the median combiner, while those colored in red are at least 5% below the median and those colored in pink are at least 5% above the median. This 5% threshold can be changed via the settings dropdown.

The combiner performance can be downloaded as an Excel file in the top-right corner of the page, while the raw POA and combiner current data can be downloaded as CSV files in the output settings dropdown.

Caveats

  • There must be at least one clearsky timestamp during the day for this report to be generated.
  • If the system definition is incorrect, (for example if the DC capacity reported to Proximal during commissioning was incorrect) then the report will be incorrect for those combiners which are defined incorrectly since the combiner DC capacity is used in the normalization calculation.

Module State of Health Report

Overview

This report is designed to characterize the performance of the modules using the combiners as a proxy. Through heavy filtering, the report aims to analyze only the combiners that are performing at the highest level, to achieve a picture representative of the best possible performance of the modules. The filters are designed to remove any effects that can be attributed to the underperformance of inverters, trackers, or other non-DC related effects.

After filtering, the performance of each combiner is characterized through the following formula:

Where:

  • is the expected energy production of the combiner, detailed in the PV Model Overview. is representative of the warranted degradation curve of the modules at the time of analysis.
  • is the actual energy production of the combiner, calculated as the combiner current × inverter DC voltage.

The resulting metric is representative of the performance of the modules, with 100% indicating that the modules are performing at the expected level.

Filters

Unlike the DC Amperage report, the module state of health report is not capable of user-defined filters. Instead, the report has a defined set of filters that are applied to the data, and the analysis is automatically generated on a daily basis. In addition to clearsky filters, several performance-based filters are applied to ensure that the analysis is only performed on combiners that can be considered representative of high performance.

Clearsky Filters

  • Minimum POA: 250 W/m²
  • Maximum POA Derivative: 2 W/m²/minute
  • Standard Deviation filters
    • Maximum POA Standard Deviation: 7.5 W/m²
    • Maximum POA Derivative Standard Deviation: 0.25 W/m²/minute
    • To filter on standard deviation and derivative standard deviation, both conditions must be met to exclude data. All other conditions are applied individually.
  • POA sensors on errant trackers are excluded analytically
  • At least 1 hour of clearsky-filtered data

Performance-Based Filters

  • Inverter AC output between 5% and 95% of the inverter's nameplate capacity
    • This ensures the inverter is online and not AC clipping
  • Inverter module voltages are within 5V of each other (as applicable)
    • Since combiner power must be calculated as (combiner current) × (inverter DC voltage), the module voltages must be within a narrow band to ensure that the voltage is representative of the combiners.
  • Combiner DC Field Health is at least 97.5% of the project nonzero mean per day.
    • If a combiner fails the fuse health filter, it is removed from the analysis.
  • Tracker position deviating from setpoint is less than 1° on average per day.
  • Tracker setpoint deviating from median is less than 1° on average per day
    • Both tracker filters are applied to entire blocks. If a block fails the analysis, all combiners on the block are excluded for that day.

Other

  • Soiling is accounted for in the expected performance calculation through the onsite soiling sensors. Since this adjustment is applied to both expected and actual performance, it is assumed to cancel out in the performance calculation and is not considered in the analysis.

Manual Filtering

  • On the Clearsky tab, users may select individual days to view. The individual days show combiner-level performance as well as the clearsky POA data shaded in green for timestamps selected for analysis.
  • On all tabs, users may select a specific date range to view. It is recommended to select a date range that is at least one month long to ensure enough data is available for analysis.
  • The report is presented for the previous year of data by default, but either of these filters are applied to data presentation on all tabs.

Outputs

Outputs are available for each combiner, as well as various summary statistics. Graphics are available on the project level, individual combiner level, and aggregates for inverter and circuit level roll-ups. Combiner-level graphics are colored based on the capacity and bin classification of modules associated with each combiner. On the GIS tab, the report is available on a combiner-level basis.

Caveats

  • Due to the heavy filtering applied to the data, the report may not generate for some days.
  • If the system definition is incorrect, (for example if the DC capacity reported to Proximal during commissioning was incorrect) then the report will contains inaccuracies for those combiners which are defined incorrectly since the combiner DC capacity is used in the normalization calculation.

Inverter Availability

Description

Inverter availability KPIs measure how often each inverter (and, when present, its internal power-conversion modules) is producing at least a minimum power output under valid irradiance conditions.

One daily report is produced containing:

  1. Inverter Availability – percentage of daylight intervals in which each inverter’s AC power exceeds a user-defined threshold.
  2. Module Availability – same calculation applied to individual inverter-module channels (only shown if the project reports module-level power).

This report helps identify offline or under-performing inverters, balance-of-plant outages, and data-quality issues.

Parameters (default values)

ParameterPurposeDefault
Available Min (MW)Minimum inverter (or module) AC power required to count as “available”.0 MW
Irradiance Min (W/m²)Minimum plane-of-array irradiance at which availability is evaluated.0 W/m²
Inverter Availability (%)Workbook formula – average of all inverter availabilities.(output)
Inverter Module Availability (%)Workbook formula – average of all module availabilities (shown only if module data exists).(output)

Filters

An individual 5-minute interval is excluded from availability calculations if:

  1. Plane-of-array irradiance ≤ Irradiance Min.

All other samples form the valid daylight set for the day.

Method – Inverter Availability

  1. Query 5-minute pv_inverter_ac_power and met_station_poa for every inverter in the project.
  2. Validate irradiance – keep only timestamps where POA > Irradiance Min.
  3. Evaluate power threshold – for each inverter, flag samples where
    [ P_{\text{inv}}(t) > \text{Available Min} ]
  4. Compute availability per inverter
    [ A*{\text{inv}}=\frac{\text{count}\left(P*{\text{inv}}> \text{Available Min}\right)} {\text{count(valid daylight samples)}} ]
  5. Export an Excel workbook containing:
    • Parameters – editable inputs & live output KPIs.
    • Inverter Availability – % available for each inverter.
    • Inverter Power – raw 5-minute power time-series.
    • Irradiance – POA irradiance (mean + individual sensors).

Availability formulas live in Excel, so users can adjust Available Min or Irradiance Min and see KPIs update instantly.

Module Availability (when reported)

If the project provides PV Inverter Module AC Power:

  1. Repeat Steps 1-4 using module-level power.
  2. Add sheets – Module Availability and Module Power – mirroring the inverter sheets.

Tracker Availability

Description

Tracker availability KPIs quantify how often each tracker row is correctly following its expected angle.
Two daily reports are generated:

  1. Row vs Row Setpoint – compares each row’s measured position to its own controller setpoint.
  2. Row vs Zone Median Setpoint – compares each row’s position to the median setpoint of all rows in its zone.

A row is considered available when the absolute position error is within an acceptable tolerance. These KPIs surface drifted trackers, stow-logic faults, communication drop-outs, and other issues.

Parameters (default values)

ParameterPurposeDefault
Available Max (deg)Max position error allowed to count as “available”.5°
Irradiance Min (W/m²)Minimum plane-of-array irradiance required to evaluate availability.0 W/m²
Exclude Stow PeriodsIf TRUE, stow periods are removed from the analysis. If a project lacks stow data this flag is ignored.TRUE
Maximum Setpoint Change (deg)Quality gate that rejects 5-min setpoint jumps above this value.60°

Filters

Before availability is calculated, any 5-minute interval is discarded if any of the following are true:

  1. Tracker position or setpoint is blank.
  2. Plane-of-array irradiance ≤ Irradiance Min.
  3. Exclude Stow Periods is TRUE and the tracker zone is reported as stowed.
  4. |Position − Setpoint| ≥ 120°.
  5. |Setpoint(t) − Setpoint(t-1)| > Maximum Setpoint Change. (Rule 5 is skipped for the first sample of the day.)

Method 1 – Row vs Row Setpoint

  1. Query 5-minute tracker position, tracker setpoint, met station poa, and tracker zone status for every row in the project.
  2. Apply filters listed above to build the valid-data mask.
  3. Calculate position error
    [ \Delta\theta*{\text{row}}(t)=\left|\text{Position}*{\text{row}}(t)-\text{Setpoint}_{\text{row}}(t)\right| ]
  4. Compute availability for each row
    [ A*{\text{row}}=\frac{\text{count}\left(\Delta\theta*{\text{row}}\le\text{Available Max}\right)} {\text{count(valid samples)}} ]
  5. Export an Excel workbook containing:
    • Parameters – editable inputs & descriptions.
    • Availability – one value per row (percent).
    • Difference – per-sample (\Delta\theta_{\text{row}}) table.
    • Raw data sheets: Position, Setpoint, Stow, Irradiance.

Method 2 – Row vs Zone Median Setpoint

  1. Derive zone setpoints by taking the median of all row setpoints within each zone at every 5-minute timestamp.
  2. Repeat Steps 2-5 from Method 1, replacing Setpoint₍row₎(t) with Setpoint₍zone median₎(t) in the error formula.
  3. The workbook layout is identical; the Setpoint sheet now shows zone medians (prefixed “Zone”).

Usage Notes

  • All calculations occur in the exported Excel file via formulas, allowing users to adjust parameters post-hoc.

PV PR Test Report

Description

The PV PR Test Report prepares measured weather, production, and energy datasets for an external performance-ratio (PR) test workflow, typically completed in PVSyst. Proximal does not compute the contractual PR, run a PVSyst simulation, or score modeled versus actual energy in this report. The platform's job is to assemble a defensible measured dataset: apply automatic and manual exclusions, document those exclusions, and export files that a modeler can import into PVSyst (or another independent tool) for the modeled-vs-actual comparison.

In the app the page is titled PR Test (project → Reports → PR Test). It currently shows an In Development banner. The report is organized as four sequential tabs:

  1. Test Setup – test identity, date range, timezone, source-data status, and optional import of a prior filter configuration.
  2. Automatic Filters – exclusion rules and a timestamp-level impact preview.
  3. Manual Filters – weather-trace review plus global and device-specific timestamp-range exclusions with reasons.
  4. Outputs – downloadable artifacts for PVSyst weather import, production/energy analysis, and audit of the filter set.

This page is the methodology and instruction reference for engineers who already know how a PR test is structured (valid-period selection, irradiance and soiling gates, clipping and outage exclusions, measured vs. modeled energy). It documents what Proximal assumes, what it calculates automatically, and what each exported file is for.

Scope and capabilities

The report can:

  • Query on-site meteorological traces (GHI, POA, POA tilt, secondary/rear POA, ambient temperature, wind speed, soiling) over a user-selected inclusive calendar range.
  • Query project-level and inverter-level AC power, the PPC active-power setpoint, and plant energy-meter registers.
  • Query project-level Events for curtailment and availability/outage windows.
  • Apply a configurable set of automatic exclusions, then optional manual exclusions.
  • Roll weather up to hourly values in the project timezone and write a PVSyst-oriented custom weather CSV.
  • Derive hourly DHI from GHI when no measured DHI tag is present and site coordinates are available.
  • Produce irradiance-weighted monthly soiling and albedo summaries for PVSyst parameter tables.
  • Export production (MW) and hourly energy (Wh) tables, a reusable JSON filter configuration, an hourly TRUE/FALSE filter matrix, a manual-exclusion audit log, and a README manifest.

The report cannot:

  • Compute PR, reference yield, or specific yield (see the Performance Ratio KPI for the operational PR KPI, which is a different calculation).
  • Import or score a PVSyst .MET / simulation output against metered energy inside Proximal.
  • Apply IEC 61724 or ASTM E2848 capacity-test regressions. Those remain external.

Assumptions

The following assumptions are built into the current implementation. They are not user-editable unless a corresponding filter or setup field exists.

  1. This phase is dataset preparation only. Modeled-vs-actual scoring is performed outside Proximal.

  2. All timestamps are interpreted in the project timezone (IANA name from the project record, overridable on Setup). Native-interval samples are bucketed to the civil hour [h, h+1) in that timezone. Hour labels are written as YYYY-MM-DD HH:mm:ss at the start of the hour.

  3. The selected date range is inclusive of both calendar dates. Queries run from startDate 00:00:00 through endDate 23:59:59. The hourly grid runs from startDate 00:00 through endDate 23:00.

  4. The query interval follows the project's configured data interval. One-second projects are queried at one minute. Unrecognized intervals fall back to five minutes. The interval is not a Setup control; it is taken from the project and stored in the exported config.

  5. An exact-zero meteorological reading is treated as a malfunction, not as a physical night-time or dry-sensor value, except soiling loss. Finite non-zero readings are required for other met-station types. MET_STATION_SOILING_LOSS of is a physical no-soiling value and is kept.

  6. Irradiance is nonphysical when or . The bound is applied to GHI and POA (and to DHI in the weather roll-up), and to up-facing / down-facing samples used to derive albedo from pairs. It is a per-sensor drop, not an automatic site-timestamp drop.

  7. Minimum-POA uses the mean of remaining front-facing POA sensors, not the site minimum. Rear-, back-, down-facing, reflected, and ground-facing POA traces are ignored for this gate so that a single rear or low sensor cannot zero the valid set.

  8. Hours with no remaining front-facing POA fail the minimum-POA gate in the hourly filter matrix (missing POA is treated as ). That matrix is what filtered weather, energy pass/fail columns, and the Excel filter file use.

  9. All soiling traces are converted to soiling loss percent before thresholds and export. loss means no soiling.

    • Soil percent (MET_STATION_SOIL_PERCENT, id 39) and soiling ratio (MET_STATION_SOILING_RATIO, id 245) are remaining performance, typically –, where means no soiling.
    • Soiling loss (MET_STATION_SOILING_LOSS, id 246) is already lost performance, typically –, where means no soiling.

    Values in the unit-fraction range are scaled to percent; values above that range are already percent. Soiling ratio uses a wider unit-fraction band () so clean readings slightly above stay loss:

with for soil percent and for soiling ratio.

The weather CSV Soiling column, monthly soiling summary, and maximum-soiling-loss gate all use . 10. Clipping is evaluated at 98% of the relevant limit. Project clipping compares plant power to PPC_ACTIVE_POWER_SETPOINT. Inverter clipping uses capacity_power_ac_kva treated as kW (power factor of 1) and converted to MW. PVS projects use the MV collector-circuit meter power, summed across those meters, in place of METER_ACTIVE_POWER. 11. If the PPC setpoint is missing or non-positive, project clipping never excludes. If an inverter has no positive nameplate, that inverter is skipped for clipping. If no inverter AC-power traces exist, communication-gap exclusion does not remove native timestamps. Communication-gap exclusion is preview-only; it does not fail hours in the matrix or filtered exports. 12. Sensor validity, outlier sigma, and hourly completeness are front-facing POA-only. Rear-, back-, down-facing, reflected, and ground-facing POA traces are ignored for these gates, matching the minimum-POA filter. GHI remains in the weather CSV and is still dropped per-sensor when nonphysical, but it does not decide validity, outliers, or completeness. 13. POA outlier statistics are population mean and population standard deviation over every usable front-facing POA sample in the selected range (not a rolling or per-hour statistic). A timestamp/hour fails if any remaining front-facing POA sample at that key is more than from that site-wide mean. 14. Hourly completeness requires at least 60% of the expected sub-intervals in that civil hour to contain a valid front-facing POA timestamp. Expected count is , using the query interval (1, 5, 10, 15, 30, or 60 minutes). 15. The filtered weather CSV always applies the 60% completeness rule, even if the completeness switch is turned off. Turning the switch off only stops completeness from contributing to the hourly matrix verdict; the filtered-weather file still drops incomplete hours. 16. Event exclusions use project-level Events, not inverter- or device-level Events. Availability/outages are other project-level Events whose event_id is not in that curtailment set. 17. An Event overlaps an hour if the Event window and [hour, hour+1) share any open interval. Events that started before the report window are included when they still overlap the selected range. 18. DHI derivation uses the Erbs diffuse-fraction correlation and a simplified solar-position model (no equation of time). Measured DHI tags, when present, always take precedence. Derivation runs only for hours that already meet the 60% front-facing POA completeness rule and only when latitude and longitude are available. 19. Weather CSV GPI is the hourly mean of traces classified as POA (MET_STATION_POA and MET_STATION_POA_TILT). Secondary/down-facing POA is not mapped into GPI. Name-based rear/back traces that are still typed as MET_STATION_POA are included in GPI, unlike the minimum-POA filter, which excludes them. 20. Albedo is not a weather-CSV column. It is computed for the monthly summary from an albedo tag when present, otherwise from same-device up-facing / down-facing irradiance pairs ( when ). 21. Energy registers are assumed to be kWh. Hourly export is in Wh. A trace is treated as cumulative if at least 80% of consecutive valid samples are non-decreasing; otherwise samples in an hour are summed as interval energy. 22. Manual exclusions are not columns in the hourly filter matrix. They omit matched weather samples from hourly averages. Global ranges also remove those native timestamps from the Automatic Filters preview; device ranges remove every candidate timestamp in that range from the preview remaining set. The matrix Final verdict is automatic filters only.

Workflow

  1. Open the report on the project. The Documentation button in the upper-right opens this methodology page. Confirm Weather, Project production, Inverter production, Energy meter, and Project events source status on Test Setup after a date range is selected.
  2. Set Test run name, Date range, and Timezone. Import a previous pr-test-filter-config/v1 JSON if you are repeating a test. Reset restores the default setup and empty filter set and clears this project's saved browser state.
  3. On Automatic Filters, enable the gates required by the test protocol. Defaults are listed below. Click Compute preview after changes; impact counts do not refresh automatically. Preview is for tuning; it is not required before exporting.
  4. On Manual Filters, review weather traces, then add global and/or device timestamp ranges for conditions the automatic engine cannot see (soiling events not captured by the soil sensor, known pyranometer outages, snow, etc.). Include a reason; it is written to the audit log (the form does not block an empty reason).
  5. On Outputs, download the artifacts required by the PVSyst workflow. At minimum this is usually the filtered weather CSV, production and/or energy CSV, filter matrix, and README. Re-download after any filter change.

Browser state for the project is written when you download an Outputs artifact and restored the next time you open the report. The exported JSON is the portable copy so another engineer can reload the same filter set.

Setup fields

FieldIntentionDefault
Test run nameHuman label used in the JSON, README, and download filenames.{project name} PR test
Date rangeInclusive civil dates that bound queries, the hourly grid, and every export.Last 7 days through today (UTC calendar dates at page load)
TimezoneIANA timezone for local-hour bucketing, Event overlap, and CSV clocks.Project timezone
Data intervalNative query step used for completeness (expected intervals per hour = 60 / Δt). Not shown as an editor; taken from the project.Project data_interval (1 s → 1 min; otherwise 5 min fallback)
Import filter configReloads automatic filters, manual exclusions, test name, dates, timezone, and interval from a previously exported JSON. Project identity stays the current project.(none)
ResetRestores default setup (including the last-7-days date range), default automatic filters, and empty manual exclusions, and clears this project's browser storage.—

Source-status rows are availability checks only. Unavailable does not block configuration; exports that need Events will retry and fail if availability exclusions are on and Events cannot be fetched.

Source data

Weather

Queried sensor types:

  • GHI
  • Ambient temperature
  • Wind speed
  • Soil percent (legacy remaining performance, typically –)
  • Soiling ratio (remaining performance, typically –; same conversion as soil percent)
  • Soiling loss (lost performance, typically –; scaled to percent, not inverted)
  • POA
  • POA tilt
  • POA secondary (typically rear / down-facing; used for albedo pairing, not for GPI or the minimum-POA mean)

Production

  • Project power: METER_ACTIVE_POWER, except PVS projects, which use PV_MV_COLLECTOR_CIRCUIT_METER_ACTIVE_POWER summed across those meters.
  • PPC setpoint: PPC_ACTIVE_POWER_SETPOINT, used as the project-clipping limit.
  • Inverter power: PV_INVERTER_AC_POWER.
  • Inverter nameplate: capacity_power_ac_kva on PV inverter devices, treated as kW.

Energy

  • METER_ENERGY_EXPORTED_TO_GRID
  • METER_NET_ENERGY
  • PV_MV_COLLECTOR_CIRCUIT_METER_ENERGY_EXPORTED_TO_GRID (PVS)

Events

Two summaries are fetched over the same overlap window (open: false, losses not requested):

  • Curtailment: failure_mode_id = 205.
  • Project-level Events: device_type_id = PROJECT. Availability/outage windows are this set minus curtailment event_ids.

Time, candidates, and two evaluation grids

The engine builds two related views of the same range.

Native-interval preview (Automatic Filters tab). Candidate timestamps are the union of GHI, front-facing POA, soiling, and production timestamps after conversion to project-local time. Filters are applied sequentially in the order listed under Automatic filters. Each filter's Removed count is the number of candidates that still remained after earlier filters and then failed this one (except nonphysical irradiance, which counts dropped sensor readings). Percent is that removed count divided by the original candidate count, except the nonphysical row, which divides by the irradiance-reading count. Scope device-specific means the filter dropped individual sensor readings (or is attributed per device); global means the whole timestamp is removed.

Hourly filter matrix (Outputs). One row per project-local hour from startDate 00:00 through endDate 23:00. Each enabled condition is evaluated independently against hourly aggregates (except communication gaps, which do not fail hours — see below). Disabled conditions are treated as TRUE. Final verdict is the logical AND of every condition. Filtered weather, energy pass/fail columns, and the Excel matrix all use this hourly verdict.

Because preview is sequential at native interval and the matrix is independent at hourly resolution, preview coverage and hourly pass counts will not match one-for-one. Use the preview to tune gates; use the matrix as the record of which hours entered the filtered weather/energy files.

Automatic filters

Defaults apply to a new test. Every switch and numeric threshold is written into the JSON config under automaticFilters.

ControlDefaultIntention
Exclude nonphysical irradianceOnDrop individual GHI/POA samples that cannot be physical.
Minimum POA thresholdOn, 150 W/m²Keep only periods with enough front-facing POA for a PR-valid irradiance set.
Maximum soiling lossOn, 10%Drop periods with excessive measured soiling loss so the valid set is not dominated by dirty-array hours.
Exclude project-level clippingOnRemove periods where plant power is at or near the PPC setpoint, so PR is not credited/penalized for plant clipping.
Exclude inverter-level clippingOnSame intent at inverter nameplate; any one inverter at the clip bound fails the timestamp/hour.
Exclude availability / outage periodsOnRemove project-level outage/availability Events other than curtailment.
Require hourly sub-interval completeness (60%)OnRequire enough front-facing POA sub-samples in the hour to treat the hourly mean as representative.
Exclude communication gapsOnDrop native-interval timestamps with no inverter AC power reading (SCADA hole). Does not fail hours in the matrix or filtered weather.
Require valid POA sensorsOnRequire at least one remaining valid front-facing POA reading.
POA sensor outlier thresholdOn, 3 σDrop timestamps where any remaining front-facing POA sample is an extreme relative to the site-wide POA distribution.

Evaluation order (preview)

On the native-interval preview, remaining timestamps are reduced in this order:

  1. Nonphysical irradiance (site timestamp removed only if no physical GHI or POA remains).
  2. Minimum POA.
  3. Maximum soiling loss.
  4. Sensor validity (valid front-facing POA present).
  5. POA outlier sigma.
  6. Hourly front-facing POA completeness.
  7. Communication gaps.
  8. Inverter clipping.
  9. Project clipping.
  10. Availability/outage Events.
  11. Manual global ranges.
  12. Manual device ranges.

The hourly matrix does not apply steps 11–12 and does not use sequential masking; it ANDs the enabled automatic conditions on hourly means. Communication-gap exclusion (step 7) is native-interval only: it does not fail hours in the matrix, so it does not remove hours from filtered weather, energy pass/fail columns, or the Excel file.

Nonphysical irradiance

A GHI or POA sample is nonphysical when

Each failing sample is dropped from that sensor only. Other sensors at the same timestamp remain. The site timestamp (preview) or hour (matrix) is removed only when every irradiance reading at that key was nonphysical, i.e. no physical GHI mean and no physical front-facing POA mean remain.

Preview Removed for this row counts dropped sensor readings, not site timestamps. That is why its scope is device-specific.

When this switch is off, nonphysical values are not dropped as nonphysical, but exact zeros are still rejected as invalid met-station readings.

Minimum POA

Front-facing POA traces are those classified as POA (MET_STATION_POA or MET_STATION_POA_TILT) that are not secondary/down/reflected/ground and whose names do not contain rear or back. After nonphysical samples are removed, remaining front-facing values at the key are averaged.

Hourly matrix (governs filtered exports):

If the hourly mean is missing, it is treated as , so the hour fails whenever the gate is enabled.

Native-interval preview: the timestamp is removed only when a mean exists and that mean is below . A timestamp with no front-facing POA therefore passes this preview gate (it may still fail sensor validity or other gates).

Maximum soiling loss

Soiling traces are converted to soiling loss percent (see assumption 9) and averaged across remaining sensors at the timestamp or hour. Soil percent and soiling ratio are remaining performance and are inverted to loss. Soiling loss is already lost performance and is only scaled to percent. The period fails when

If no valid soiling reading exists, the gate does not fail the period (null soiling is treated as “no evidence of excessive soiling”). A soiling-loss reading of is valid and counts as . An exact-zero soil-percent or soiling-ratio reading is dropped as a malfunction.

Sensor validity

Fails when no valid front-facing POA remains at the timestamp (preview) or when the hourly front-facing POA mean is missing / the hour has no POA values (matrix). This is independent of GHI. If the project has no front-facing POA traces, the preview skips this gate; the matrix still requires a POA mean when the switch is on, so hours without POA fail.

POA outlier sigma

Let and be the population mean and standard deviation of every usable front-facing POA sample in the selected range. A timestamp/hour fails if any remaining front-facing POA value at that key satisfies

If , nothing is flagged. If there are no usable front-facing POA samples, the gate is inactive.

Hourly completeness

For civil hour , let be the number of distinct local timestamps in that hour that still have valid front-facing POA, and let . The hour (and every native timestamp in it, on preview) fails unless

An hour with no front-facing POA timestamps has no completeness record and fails this gate when it is enabled.

Communication gaps

On the native-interval preview, fails when no inverter AC-power trace has a finite reading at that timestamp. If inverter power traces exist but a timestamp has none of them, the timestamp is a gap. If there are no inverter traces at all, the gate does not exclude.

This gate is not applied on the hourly matrix. Filtered weather, energy pass/fail, and the Excel matrix therefore still include hours that the preview would drop as communication gaps.

Inverter clipping

Fails if any inverter with a positive nameplate satisfies

Preview uses the instantaneous inverter power at the native timestamp. The hourly matrix uses the mean inverter power within the hour. Nameplate is capacity_power_ac_kva / 1000 (kVA stored as if it were kW).

Project clipping

Fails if the PPC active-power setpoint is a finite positive MW value and

Project power is METER_ACTIVE_POWER at that timestamp, or for PVS projects the sum of PV_MV_COLLECTOR_CIRCUIT_METER_ACTIVE_POWER traces. The hourly matrix uses the mean of those timestamp values versus the mean setpoint in the hour. Missing project power, or a missing/non-positive setpoint, does not fail the gate. project.poi is not used.

Availability Events

When enabled, an hour (and native timestamps whose hour overlaps) fail if any availability Event overlaps [hour, hour+1). Overlap is half-open on the Event end: time_end must be after the hour start; an Event that ends exactly at the hour start does not overlap that hour. time_end = null overlaps all later hours.

Availability uses project-level Events whose event_id is not in the curtailment set (failure_mode_id = 205). Curtailment Events are fetched only so they can be subtracted from that availability set; there is no automatic curtailment-event gate.

Manual filters

Manual exclusions are timestamp ranges. A reason string is stored on the row and written to the audit log; the form does not require it.

  • Global: every weather sample whose local timestamp falls inside [start, end] (inclusive) is omitted from hourly averages. The native-interval preview also removes those timestamps from remaining.
  • Device / tag: in hourly weather construction, only the matched trace is omitted. Match is by tag_id when set, otherwise by device_id (and tag-less traces on that device). In the native-interval preview, every candidate timestamp in that range is removed from remaining (not only the matched trace).

Use these for protocol-specific exclusions the automatic gates cannot encode (known instrument failure, snow cover, washing, shading from construction, etc.). They appear in the manual-exclusion CSV and in the JSON. They do not flip Excel matrix columns or Final verdict. They change the weather values (and weather-side 60% completeness counts) that go into hourly averages.

Hourly weather construction

After manual exclusions and the nonphysical / zero-reading rules, remaining samples of each weather metric are arithmetically averaged within each civil hour. Metrics are assigned from sensor type and, for DHI/albedo/up/down, from tag/name matching.

Weather CSV columnSourceUnits
Year, Month, Day, Hour, MinuteHour-start timestamp expressed in the advertised GMT offset—
GHIMean of GHI tracesW/m²
TambMean ambient temperature°C
DHIMeasured DHI mean if any DHI tag exists in the hour; otherwise Erbs derivation from hourly GHIW/m²
GPIMean of POA / POA-tilt tracesW/m²
WindVelMean wind speedm/s
SoilingMean soiling loss percent after converting every soiling sensor type%

Missing numeric values are written as -99. A units row follows the header (W/m2, deg.C, m/sec, %).

Comment rows before the header use PVSyst custom-file convention: field name in column A (# Site, # Country, …) and value in column B.

CommentValue
SiteProject / site name
CountryParsed from project address (US state abbreviation or “United States” → USA; otherwise last comma-separated segment if it looks like a country; else USA)
Data SourceProximal Energy
Time stepHour
Latitude / LongitudeProject point coordinates (GeoJSON [lon, lat])
AltitudeProject elevation
Time ZoneGMT offset in hours at startDate 00:00 local. Every data-row timestamp is converted onto this same fixed offset so a DST transition does not shift PVSyst solar time.
Summarization periodStart and end dates as DD/MM/YYYY; DD/MM/YYYY

Measured vs derived DHI

A trace is treated as measured DHI when its name/type contains dhi, diffuse_hor, diffuse horizontal, or met_station_dhi, and is not labeled as POA. If any such sample lands in the hour, DHI is the mean of those samples (dhiSource = measured).

Otherwise, for hours that already meet 60% front-facing POA completeness, with finite GHI and site latitude/longitude, DHI is derived:

  1. Day of year in the project timezone.
  2. Extraterrestrial irradiance:
  3. Solar declination:
  4. Hour angle from local clock time and longitude, without equation of time: with in degrees.
  5. Zenith angle from latitude and . If the sun is at or below the horizon (zenith ), derived DHI is .
  6. Clearness index:
  7. Erbs diffuse fraction :

  1. . GHI yields DHI .

If coordinates are missing, derived DHI is omitted (-99).

Albedo (monthly summary only)

If an albedo-named trace exists, its hourly mean is used. Otherwise albedo is the mean of per-device ratios in that hour, pairing up-facing GHI/front POA with down-facing/secondary POA on the same device_id. When nonphysical-irradiance exclusion is on, pair inputs must satisfy the same bound as GHI/POA. Up-facing irradiance for weighting falls back to GHI when POA is missing.

Outputs

Weather, production, energy, and monthly-summary filenames use the project's name_short. JSON, Excel, manual-exclusion log, and README filenames use {sanitized project name_long}-{sanitized test name}-{start}-{end}. All clocks in tabular files are project-local.

Weather CSV

Unfiltered hourly PVSyst custom file for the full selected range. Use this as the raw measured meteorological record: every hour is present, incomplete hours included, automatic-filter failures included. Typical uses: PVSyst custom weather import when you will apply validity inside PVSyst; audit of the as-measured hourly means; comparison against the filtered file.

Filtered weather CSV

Same schema as the weather CSV, restricted to hours that pass every enabled automatic filter on the hourly matrix (Final verdict = TRUE) and meet the 60% front-facing POA completeness rule (always, even if that switch is off). Communication-gap exclusion is not part of that hourly verdict. Use this as the candidate valid-period weather for the PR test in PVSyst when you want Proximal to have already applied the protocol gates. Hours removed by automatic filters or incompleteness are omitted rather than zero-filled.

Monthly weather summary CSV

Columns: Month (YYYY-MM), Soiling loss (%), Albedo, Soiling sample hours, Albedo sample hours.

Built only from hours that are complete (60% front-facing POA) and pass the hourly automatic-filter verdict:

  • Soiling: POA-weighted mean of hourly soiling loss percent, using hours with .
  • Albedo: up-irradiance-weighted mean of hourly albedo, using hours with up-facing irradiance (POA, else GHI) .

Use these monthly values as PVSyst soiling-loss and albedo parameters for the test period when the contract or model calls for irradiance-weighted monthly constants rather than hourly soiling in the weather file.

Production CSV

Wide table: Time (local) plus one column per meter, inverter AC-power, or PPC setpoint trace (MW, four decimal places). All native-interval timestamps in range are included; there is no validity mask. Empty cells are missing readings, not excluded hours. Use this for:

  • Independent clipping checks against nameplate or the PPC setpoint.
  • Aligning measured AC power with a PVSyst simulation timestep.
  • Investigating hours the filter matrix rejected.

Energy CSV

Hourly Wh from plant energy meters, one column per energy trace, plus Passes all filters and Is excluded (TRUE/FALSE). The pass/fail pair is the hourly automatic-filter verdict (Is excluded is the negation). The file contains every hour in the grid, including failed hours.

Cumulative vs interval detection: if ≥ 80% of consecutive valid samples are non-decreasing, hourly energy is in Wh, and hours where the register drops are left blank. Otherwise valid samples in the hour are summed and converted kWh → Wh. The first hour of a cumulative series has no delta and is blank.

Use this as the measured energy time series for the PR numerator, with the pass column as the valid-period mask if you are not using the filtered weather file alone.

JSON filter file

Version pr-test-filter-config/v1. Contains generatedAt, setup metadata, automaticFilters, filterLabels, manualExclusions, and notes stating that Proximal is not completing modeled-vs-actual comparison. Import this on Setup to reproduce the same test configuration in another session or for another engineer. Legacy capacity-test-dataset-builder/v1 files still parse.

Excel filter matrix

HTML .xls table: Timestamp (hourly), one TRUE/FALSE column per automatic condition (using the labels below), and Final verdict. Independent hourly evaluation, not sequential preview masking. Use this as the auditable valid-period mask: which gate failed which hour, for inclusion in a test report appendix or for rebuilding a mask in Excel/PVSyst.

Matrix column labels:

  • Nonphysical irradiance exclusion
  • Minimum POA threshold
  • Maximum soiling loss threshold
  • POA sensor validity requirement
  • POA sensor outlier sigma limit
  • Hourly POA sub-interval completeness (60%)
  • Communication gap exclusion
  • Inverter-level clipping exclusion
  • Project-level clipping exclusion
  • Availability / outage exclusion

A disabled gate is TRUE for every hour. Communication-gap exclusion is also TRUE for every hour in this matrix; that gate is native-interval (preview) only.

Manual exclusion log

CSV columns: scope, start_timestamp, end_timestamp, device_id, device_label, reason. One row per global or device-specific range. Use this as the test-report appendix of engineering judgments that sat outside the automatic protocol.

Export manifest / README

Markdown summary of project, test name, date range, timezone, data interval, units, generation time, config version, every automatic-filter value, manual-exclusion counts, and a preview summary computed at download time from the current filters and source data (not the last Compute preview click on Automatic Filters). Use this as the cover sheet for a delivered PR-test data package so a reviewer can see units and gates without opening the JSON.

Caveats

  • The in-app PR Test page is still marked In Development. Treat this document as the current methodology, and expect further changes.
  • Browser state is written when you download an Outputs artifact, not on every filter edit. Use Reset on Test Setup, or the exported JSON, if you need a known starting point.
  • Operational Performance Ratio KPI is a daily site KPI on unfiltered hourly POA and meter energy. It is not this report's valid-period PR and will not match a contractual PR test.
  • Preview coverage is native-interval and sequential; do not treat it as the hourly valid fraction in the filtered weather file.
  • Communication-gap exclusion affects the Automatic Filters preview only. It does not remove hours from filtered weather, energy pass/fail, or the Excel matrix.
  • Rear/down-facing POA is excluded from the minimum-POA mean, sensor validity, outlier sigma, and completeness counts, but can still affect GPI if a rear sensor is typed as primary POA.
  • Derived DHI is an Erbs estimate from GHI and a simplified solar position. Prefer measured DHI when the site has a shaded pyranometer.
  • Inverter nameplate is taken from capacity_power_ac_kva as kW. Incorrect commissioning nameplates will mis-fire inverter clipping.
  • Missing or non-positive PPC setpoint silently disables project clipping.
  • Exact-zero met readings are discarded. Night-time POA of true zero therefore never contributes; completeness is driven by daytime (or non-zero) front-facing POA samples only.
  • Energy conversion assumes kWh registers. If a meter is already in Wh, exported values will be 1000× high.
  • Event exclusions require a successful Events fetch. If Events fail and the availability gate is on, filter-dependent downloads stop after retry.
  • Turning off hourly completeness still drops incomplete hours from filtered weather; only the matrix completeness column becomes unconditionally TRUE. Completeness is counted on unique front-facing POA timestamps, not GHI. Manual exclusions can reduce that weather-side count even though they do not change the matrix completeness column.

Combiner Mismatch Report

Use the Combiner Mismatch Report to identify likely mismatches between PV combiner locations in the site layout and their SCADA current tags. It analyzes each PV block and recommends mappings to review; it does not change field wiring, GIS, or SCADA mappings.

Open a project and go to Reports → Combiner Mismatch Report.

How the report works

The report uses a fixed 14-day window of high-resolution combiner-current data, ending on the date you select. It looks for moving cloud shadows crossing a PV block. When the layout and tags are correct, combiner currents should decrease in the same spatial order as the shadow. A tag that repeatedly responds where another combiner is located may be swapped.

It also compares combiner capacity with current. On the same days, larger combiners should generally draw more current than smaller combiners. This is an independent check that can identify a potential mismatch even when useful moving-cloud patterns are unavailable.

The report needs combiner current tags, combiner locations in the site layout, and combiner nameplate capacities. It skips days without a clear moving cloud edge or sufficient data.

Generate a report

  1. Select the end date for the analysis window. The report automatically uses the preceding 13 calendar days, for 14 days in total.
  2. Select Generate report.
  3. Wait for block results to finish loading. The site map and block table update as blocks are analyzed.

If the selected window has no high-variability days, select a different end date that includes cloudier conditions. A block can also show a warning or fail when it has too little usable moving-cloud data, no combiner-current tags, or an analysis error.

Completed reports remain available from the Report history tab. Select a past report to review its saved results.

Review block results

The block table and site map show the status of every analyzed PV block:

  • Swaps: the report found a suggested remap.
  • Review: there is a finding that needs investigation but is not a suggested remap.
  • Clean: enough useful data was available and no mismatch was found.
  • Warning or Failed: the block could not be reliably analyzed. Try a different 14-day window or check the available data and layout.

Select a block in the table or on the map to open its time-series viewer. The viewer replays combiner current by capacity across the selected block. Compare Before (the tagged currents) with After (the recommended remap) to see whether the current timing matches the combiner locations more closely.

Use Download CSV after the report completes to share the block results and findings outside Proximal.

Interpret findings

The results distinguish between the strength and type of evidence:

  • Confirmed: cloud timing and capacity-versus-current both identify the same combiners. Prioritize these for a mapping or field check.
  • Likely (timing): the cloud-order check remains consistent on later days. A capacity finding may be absent when the combiners have the same size.
  • Likely (capacity): current and capacity indicate a mismatch, but cloud timing did not confirm it. Review it, but do not treat it as a completed remap.
  • Walk the block: larger combiners appear to draw less current than smaller ones across the block. Individual pair recommendations are not reliable; check every combiner mapping in the block.
  • Investigate: there was insufficient useful data or the two checks disagree. Review the block before taking action.

For example, if two same-sized combiners repeatedly show each other's cloud arrival pattern, the report can recommend swapping their tags. Open the block, compare the Before and After replay, then confirm the mapping in the field or in the mapping table before making any change.

Limitations

A recommended swap is evidence to investigate, not proof that field wiring was changed. The issue may be in GIS, SCADA tags, or another mapping source.

The report can identify two-combiner swaps and some three-combiner mix-ups. More complex mapping problems may appear as multiple findings or as Walk the block. Incorrect nameplate capacities, missing layout data, and unusual combiner geometry can also affect the analysis. Correct layout issues before relying on the results.

Forecasts Overview

Proximal forecasts hourly weather and solar power production for utility-scale solar projects. Each forecast combines project configuration, weather data from the Integrated Forecasting System (IFS), and the Proximal PV performance model.

Weather forecast

The forecast service requests the ECMWF Integrated Forecasting System (IFS) at the project's latitude and longitude. The request is aligned to the most recent available IFS model run. The current request returns 240 hourly forecast points, covering 10 days.

All forecast timestamps are stored in UTC:

  • time_forecast_run identifies the IFS model run used by the forecast.
  • time_forecasted identifies the valid time of each weather and PV value.

The weather input contains:

FieldUnitDescription
ghiW/m²Global horizontal irradiance
dniW/m²Direct normal irradiance
dhiW/m²Diffuse horizontal irradiance
ambient_temperature°CAir temperature
wind_speedm/sWind speed

PV simulation

The forecast adapter passes the IFS weather series and project configuration to the Proximal PV performance model. See the PV model overview for the model chain and individual calculation steps.

The simulation runs one step for each weather timestamp. For the current IFS request, this is 240 hourly steps; the forecast does not add sub-hourly interpolation. Each step uses the weather values for that timestamp to calculate:

  • Tracker position, using the project's true-tracking or backtracking configuration and rotation limits
  • Plane-of-array and effective irradiance
  • Module temperature and DC power
  • Inverter and other electrical losses
  • AC power at the point of interconnection

The simulation uses the project's DC capacity, module temperature coefficient, geometry, and interconnection limit. PV power is clipped at the interconnection limit before export.

p_mp is instantaneous AC power at the point of interconnection, stored in watts. It is not an energy value. To estimate energy for an hourly interval, multiply the power by one hour and convert watts to the desired energy unit.

Forecast outputs

The service stores both weather and PV results in two forms:

  1. Forecast history: Each run is retained with its time_forecast_run, allowing forecasts to be compared with later runs and observations.
  2. Latest forecast: The most recent run is retained for each time_forecasted value for applications and dashboards.

PV Model Overview

Why Proximal

The Proximal PV performance model has been specifically designed with operating assets in mind. The following are a few highlights of the model that distinguish it from other PV models used in asset management.

Built on Open Source

Modern, tested, transparent, trusted by the community. By building on top of pvlib, we can ensure that the proximal energy model is understandable by all users and easily extendable.

⑃

Nodal

Expected energy can be calculated at the combiner, inverter, array, or substation level.

🕑

Sub-Hourly

Operating assets emit high frequency data which is captured by the energy model.

🗺️

Geospatial

Each block of the system uses the meteorological data that is closest to it which can yield great improvements for large systems with passing clouds.

📄

Documented

Each step of the model is documented in detail through pvlib and through this documentation set.

♲

Efficient

Inputs to each individual model are automatically factored into unique combinations. This makes the model capable of handling large systems with high levels of detail at high frequency possible.

Model Chain

The proximal performance model at a high level is comprised of 6 major sub-models. Clicking on any of the models will take you to the actual model steps that occur in each sub-model.

flowchart TD

%% --- CLASSES ---
classDef source fill:#6B7A8F, color:#CCCCCC
classDef model fill:#202020, color:#CCCCCC
classDef model_dashed fill:#202020, color:#CCCCCC, stroke-dasharray: 5 5
classDef inputs fill:#1A1A1A, color:#CCCCCC
classDef outputs fill:#B39245, color:#CCCCCC

met_params[Meteorological Parameters]:::source
click met_params "./simulation/meteorological_parameters.html"

tracker_rotation_angles[Tracker Rotation Angles]:::source
click tracker_rotation_angles "./simulation/tracker_rotation_angles.html"

poai[Plane of Array Irradiance]:::source
click poai "./simulation/plane_of_array_irradiance.html"

epoai[
    Effective
    Plane of Array Irradiance
]:::source
click epoai "./simulation/effective_plane_of_array_irradiance.html"

DC[DC System Losses]:::source
click DC "./simulation/dc_system_losses.html"

AC[AC System Losses]:::source
click AC "./simulation/ac_system_losses.html"

met_params --> tracker_rotation_angles
tracker_rotation_angles --> poai
poai --> epoai
epoai --> DC
DC --> AC

Edits and Additions

If you would like to see support for another algorithm or would like to suggest edits or additions to this documentation page, please open an issue on the Proximal GitHub repository.

Simulation

General

The Proximal expected energy model converts measured weather conditions and the configured physical properties of a photovoltaic system into expected power at the point of interconnection. The model preserves the system hierarchy throughout the calculation, so results can also be reported for combiners, inverters, and transformers.

The simulation runs each model stage in order. Outputs from one stage become inputs to the next stage, while equipment assignments determine how values are mapped and combined between strings, combiners, inverters, transformers, and the project.

Acronyms

  • POAI: Plane of Array Irradiance
  • EPOAI: Effective Plane of Array Irradiance
  • DC: Direct Current
  • AC: Alternating Current
  • POI: Point of Interconnection

Simulation Pipeline

The following flow diagram shows the major stages of the Proximal expected energy simulation. The flow chart is interactive. Clicking a documented model stage will take you to its detailed model chain.

Legend

flowchart LR

  classDef source fill:#6B7A8F, color:#CCCCCC
  classDef model fill:#202020, color:#CCCCCC
  classDef outputs fill:#B39245, color:#CCCCCC

  source[(Input Data)]:::source
  model_step[[Model Stage]]:::model
  model_outputs([Calculated Results]):::outputs

  source --> model_step --> model_outputs

Model Chain

flowchart TD

  classDef source fill:#6B7A8F, color:#CCCCCC
  classDef model fill:#202020, color:#CCCCCC
  classDef outputs fill:#B39245, color:#CCCCCC

  met_data[(
    --- MEASURED DATA ---
    irradiance
    ambient temperature
    relative humidity
    wind speed
    soiling
  )]:::source

  system_data[(
    --- SYSTEM DATA ---
    project location
    module parameters
    racking parameters
    electrical hierarchy
    inverter parameters
    transformer parameters
  )]:::source

  meteorological[[Meteorological Parameters]]:::model
  click meteorological "meteorological_parameters.html"

  rotations[[Tracker Rotation Angles]]:::model
  click rotations "tracker_rotation_angles.html"

  poai[[Plane of Array Irradiance]]:::model
  click poai "plane_of_array_irradiance.html"

  epoai[[Effective Plane of Array Irradiance]]:::model
  click epoai "effective_plane_of_array_irradiance.html"

  dc[[DC System Losses]]:::model
  click dc "dc_system_losses.html"

  ac[[AC System Losses]]:::model
  click ac "ac_system_losses.html"

  poai_output([POAI by combiner]):::outputs
  combiner_output([DC power by combiner]):::outputs
  inverter_output([AC power by inverter]):::outputs
  transformer_output([AC power by transformer]):::outputs
  poi_output([Expected power at POI]):::outputs

  met_data --> meteorological
  system_data --> meteorological
  meteorological --> rotations
  system_data --> rotations
  rotations --> poai
  meteorological --> poai
  system_data --> poai
  poai --> poai_output
  poai --> epoai
  met_data --> epoai
  system_data --> epoai
  epoai --> dc
  met_data --> dc
  system_data --> dc
  dc --> combiner_output
  dc --> ac
  system_data --> ac
  ac --> inverter_output
  ac --> transformer_output
  ac --> poi_output

Simulation Outputs

The model emits intermediate results as soon as each electrical level is complete:

  1. Plane of array irradiance by combiner
  2. DC power by combiner
  3. AC power by inverter
  4. AC power by transformer
  5. Expected project power at the point of interconnection

Edits and Additions

If you would like to see support for another algorithm or would like to suggest edits or additions to this documentation page, please open an issue on the Proximal GitHub repository.

Meteorological Parameters

General

The first step of the Proximal expected energy simulation is to ingest data from the project meteorological stations. This data is then used to calculate the intermediate meteorological parameters that are required to calculate the Plane of Array Irradiance (POAI).

This section of the documentation shows all models in the order that they are calculated in the simulation.

Met Station Assignments

The Proximal performance model treats weather data slightly differently than other performance models users may be familiar with. Instead of using a single set of weather data for every electrical component being modeled, Proximal assigns electrical components to individual blocks and then assigns those blocks a met station to use for modeling purposes. Each block is then modeled with the data that corresponds to its assigned met station. Generally the closest met station to the block is chosen to be that blocks assigned met station.

F.A.Q.

  • Why not interpolate geospatially between weather stations?
    • Because passing clouds create a hard edge of irradiance, interpolating irradiance between sensors would create non-physical values in the data stream.

Acronyms:

  • DHI: Diffuse Horizontal Irradiance
  • DNI: Direct Normal Irradiance
  • extraDNI: Extraterrestrial Direct Normal Irradiance
  • PWAT: Precipitable Water
  • RH: Relative Humidity

Simulation Pipeline

The following flow diagram shows how meteorological parameters is calculated in the Proximal expected energy simulation. The flow chart is meant to be interactive. Clicking on any of the modeling step nodes will take you to the documentation for that modeling step.

You may need to zoom in to be able to better see all of the details in the flow chart.

Legend

  flowchart LR

  %% --- CLASSES ---
  classDef source fill:#6B7A8F, color:#CCCCCC
  classDef model fill:#202020, color:#CCCCCC
  classDef inputs fill:#1A1A1A, color:#CCCCCC
  classDef outputs fill:#B39245, color:#CCCCCC

  database[(Database)]:::source
  model_step[[
    Modeling Step
    DEFAULT MODEL CHOICE
  ]]:::model
  model_inputs[\
    Input Parameters
    for Modeling Step
  /]:::inputs
  model_outputs([Calculated Parameters]):::outputs

  database --> model_inputs
  model_inputs --> model_step --> model_outputs --> model_inputs

Model Chain

flowchart TD

  %% --- CLASSES ---
  classDef source fill:#6B7A8F, color:#CCCCCC
  classDef model fill:#202020, color:#CCCCCC
  classDef model_dashed fill:#202020, color:#CCCCCC, stroke-dasharray: 5 5
  classDef inputs fill:#1A1A1A, color:#CCCCCC
  classDef outputs fill:#B39245, color:#CCCCCC

  %% --- SOURCES ---

  pv_system[(
    --- PV SYSTEM ---
    elevation
  )]:::source
  pv_system --> calc_pressure_inputs

  met_station[(
    --- MET STATION ---
    time
    ambient_temperature
    global_horizontal_radiation
    relative_humidity
    wind_speed
    *albedo
  )]:::source
  met_station --> TDEW_inputs
  met_station --> solar_position_inputs
  met_station --> extraDNI_inputs
  met_station --> DHI_inputs

  %% --- ATMOSPHERIC PRESSURE ---
  calc_pressure_inputs[\elevation/]:::inputs
  calc_pressure_inputs --> calc_pressure

  calc_pressure[[
    pvlib.atmosphere
    .alt2pres
    ]]:::model
  calc_pressure --> calc_pressure_outputs
  click calc_pressure "https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.atmosphere.alt2pres.html"

  calc_pressure_outputs([
    pressure
  ]):::outputs
  calc_pressure_outputs --> DNI_inputs

  %% --- SOLAR POSITION ---
  solar_position_inputs[\
    time
    ambient_temperature
    latitude
    longitude
    altitude
  /]:::inputs
  solar_position_inputs --> solar_position

  solar_position[[
    pvlib.solarposition
    .get_solarposition
    NREL_2008
    ]]:::model
  solar_position --> solar_position_outputs
  click solar_position "https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.solarposition.get_solarposition.html#pvlib.solarposition.get_solarposition"

  solar_position_outputs([
    apparent_zenith
    azimuth
  ]):::outputs
  solar_position_outputs --> DNI_inputs
  solar_position_outputs --> DHI_inputs
  solar_position_outputs --> airmass_inputs

  %% --- AIRMASS ---
  airmass_inputs[\
    apparent_zenith
  /]:::inputs
  airmass_inputs --> airmass

  airmass[[
    pvlib.atmosphere
    .get_relative_airmass
    KASTEN_YOUNG_1989
  ]]:::model
  airmass --> airmass_outputs
  click airmass "https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.location.Location.get_airmass.html#pvlib.location.Location.get_airmass"

  airmass_outputs([
    airmass
    ]):::outputs

  %% --- EXTRATERRESTRIAL DNI ---
  extraDNI_inputs[\
  time
  solar_constant=1360.8
  epoch_year=2014
  /]:::inputs
  extraDNI_inputs --> extraDNI

  extraDNI[[
    pvlib.irradiance
    .get_extra_radiation
    SPENCER
    ]]:::model
  extraDNI --> extraDNI_outputs
  click extraDNI "https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.irradiance.get_extra_radiation.html#pvlib.irradiance.get_extra_radiation"

  extraDNI_outputs([
    extraterrestrial_DNI
    ]):::outputs

  %% --- TDEW ---

  TDEW_inputs[\
    relative_humidity
  /]:::inputs
  TDEW_inputs --> TDEW

  TDEW[[
    pvlib.atmosphere
    .tdew_from_rh
    MAGNUS_TETENS
    ]]:::model_dashed
  TDEW --> TDEW_outputs
  click TDEW "https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.atmosphere.tdew_from_rh.html#pvlib.atmosphere.tdew_from_rh"

  TDEW_outputs([
    temp_dew_point
    ]):::outputs
  TDEW_outputs --> DNI_inputs

  %% --- DNI ---

  DNI_inputs[\
    solar_zenith
    ghi
    pressure
    temp_dew
    use_delta_kt_prime=False,
    min_cos_zenith=0.065
    max_zenith=87
  /]:::inputs
  DNI_inputs --> DNI

  DNI[[
    pvlib.irradiance
    .dirint
    DIRINT
  ]]:::model
  DNI --> DNI_outputs
  click DNI "https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.irradiance.dirint.html#pvlib.irradiance.dirint"

  DNI_outputs([
    DNI
  ]):::outputs
  DNI_outputs --> DHI_inputs

  %% --- DHI ---
  DHI_inputs[\
    GHI
    DNI
    solar_zenith
  /]:::inputs
  DHI_inputs --> DHI

  DHI[[
    pvlib.irradiance
    .complete_irradiance
    GEOMETRIC
  ]]:::model
  DHI --> DHI_outputs
  click DHI "https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.irradiance.complete_irradiance.html#pvlib.irradiance.complete_irradiance"

  DHI_outputs([
    DHI
    ]):::outputs

Edits and Additions

If you would like to see support for another algorithm or would like to suggest edits or additions to this documentation page, please open an issue on the Proximal GitHub repository.

Tracker Rotation Angles

General

This section describes how tracker rotation angles are calculated in the Proximal Performance Model.

Caveats

  • At the moment, only two dimensional modeling is taken into account. This means that 3D models such as terrain avoidance are not implemented (yet).
  • At the moment, only solar position is taken into account. This means that tracker algorithms which take into account all-sky conditions are not implemented (yet).
  • At the moment, only full cell module algorithms are taken into account. This means that tracker algorithms which take into account half-cell shading electrical effects are not implemented (yet).

Acronyms:

  • Tracking
  • aoi: Angle of Incidence

Legend

  flowchart LR

  %% --- CLASSES ---
  classDef source fill:#6B7A8F, color:#CCCCCC
  classDef previous fill:#4F5B6F,color:#CCCCCC
  classDef model fill:#202020, color:#CCCCCC
  classDef inputs fill:#1A1A1A, color:#CCCCCC
  classDef outputs fill:#B39245, color:#CCCCCC

  database[(Database)]:::source
  previous{{Previous Calculation}}:::previous
  model_step[[
    Modeling Step
    DEFAULT MODEL CHOICE
  ]]:::model
  model_inputs[\
    Input Parameters
    for Modeling Step
  /]:::inputs
  model_outputs([Calculated Parameters]):::outputs

  database --> model_inputs
  previous --> model_inputs
  model_inputs --> model_step --> model_outputs --> model_inputs

Model Chain

  flowchart TD

  classDef source fill:#6B7A8F, color:#CCCCCC
  classDef previous fill:#4F5B6F,color:#CCCCCC
  classDef model fill:#202020, color:#CCCCCC
  classDef model_dashed fill:#202020, color:#CCCCCC, stroke-dasharray: 5 5
  classDef inputs fill:#1A1A1A, color:#CCCCCC
  classDef outputs fill:#B39245, color:#CCCCCC

  %% --- Data Sources ---
  met_params{{
    --- MET PARAMS ---
    apparent_zenith
    azimuth
  }}:::previous
  met_params --> tracker_rotation_angles_inputs
  click met_params "meteorological_parameters.html"

  pv_system[(
    --- PV SYSTEM ---
    tracker_tilt
    tracker_azimuth
    tracker_max_angle
    tracking_type
    gcr
  )]:::source
  pv_system --> tracker_rotation_angles_inputs

  %% --- Tracker Rotation Angles ---
  tracker_rotation_angles_inputs[\
    apparent_zenith
    azimuth
    tracker_tilt
    tracker_azimuth
    tracker_max_angle
    tracking_type
    gcr
    /]:::inputs
  tracker_rotation_angles_inputs --> tracker_rotation_angles

  tracker_rotation_angles[[
    pvlib.tracking
    .single_axis
    ANDERSON_MIKOFSKI_2020
    ]]:::model
  tracker_rotation_angles --> tracker_rotation_angles_outputs
  click tracker_rotation_angles "https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.tracking.singleaxis.html#pvlib.tracking.singleaxis"

  tracker_rotation_angles_outputs([
    tracker_rotation_angle
    surface_tilt
    surface_azimuth
    aoi
    ]):::outputs

Edits and Additions

If you would like to see support for another algorithm or would like to suggest edits or additions to this documentation page, please open an issue on the Proximal GitHub repository.

Plane of Array Irradiance

General

The Plane of Array Irradiance (POAI) is the amount of irradiance that is incident upon the front face of the photovoltaic array.

This section of the documentation explains all of the different models and sub-models required to calculate POAI in the order that they are calculated in the simulation.

Switching Behavior

The Proximal Performance Model behaves different from other performance modeling software the user may be familiar with. It automatically switches between using the POA sensor as the input to the POA components model and the GHI sensor as the input to the POA components model. The model does this to account for the tendency of POA sensors to get shaded by nearby racks and become out of position due to tracking faults. When the predicted POA from the GHI sensor is greater than ten percent above the measured POA data, then the decomposed and transposed components from the GHI sensor are used for the rest of the model. This behavior is then noted in the data stream as lower quality data.

Acronyms:

  • extraDNI: Extraterrestrial Direct Normal Irradiance
  • DNI: Direct Normal Irradiance
  • DHI: Diffuse Horizontal Irradiance
  • RHI: Reflected Horizontal Irradiance
  • POAI: Plane of Array Irradiance

Simulation Pipeline

The following flow diagram shows how the Plane of Array Irradiance is calculated in the Proximal expected energy simulation. The flow chart is meant to be interactive. Clicking on any of the modeling step nodes will take you to the documentation for that modeling step.

You may need to zoom in to be able to better see all of the details in the flow chart.

Legend

  flowchart LR

  %% --- CLASSES ---
  classDef source fill:#6B7A8F, color:#CCCCCC
  classDef previous fill:#4F5B6F,color:#CCCCCC
  classDef model fill:#202020, color:#CCCCCC
  classDef inputs fill:#1A1A1A, color:#CCCCCC
  classDef outputs fill:#B39245, color:#CCCCCC

  database[(Database)]:::source
  previous{{Previous Calculation}}:::previous
  model_step[[
    Modeling Step
    DEFAULT MODEL CHOICE
  ]]:::model
  model_inputs[\
    Input Parameters
    for Modeling Step
  /]:::inputs
  model_outputs([Calculated Parameters]):::outputs

  database --> model_inputs
  previous --> model_inputs
  model_inputs --> model_step --> model_outputs --> model_inputs

Model Chain

flowchart TD

  %% --- CLASSES ---
  classDef source fill:#6B7A8F, color:#CCCCCC
  classDef previous fill:#4F5B6F,color:#CCCCCC
  classDef model fill:#202020, color:#CCCCCC
  classDef model_dashed fill:#202020, color:#CCCCCC, stroke-dasharray: 5 5
  classDef inputs fill:#1A1A1A, color:#CCCCCC
  classDef outputs fill:#B39245, color:#CCCCCC

  %% --- SOURCES ---
  met_station[(
    --- MET STATION ---
    ghi
  )]:::source
  met_station --> ground_diffuse_inputs

  tracker_params{{
    --- TRACKER PARAMS ---
    tracker_rotation_angle
    tracker_surface_tilt
    tracker_surface_azimuth
    aoi
  }}:::previous
  click tracker_params "tracker_rotation_angles.html"
  tracker_params --> sky_diffuse_inputs
  tracker_params --> ground_diffuse_inputs
  tracker_params --> beam_inputs

  met_params{{
    --- MET PARAMS ---
    dhi
    dni
    dni_extra
    apparent_zenith
    azimuth
    airmass_relative
  }}:::previous
  met_params --> sky_diffuse_inputs
  met_params --> beam_inputs
  click met_params "meteorological_parameters.html"

  %% --- Ground Diffuse ---
  ground_diffuse_inputs[\
    surface_tilt
    ghi
    albedo
    /]:::inputs
  ground_diffuse_inputs --> ground_diffuse

  ground_diffuse[[
    pvlib.irradiance
    .ground_diffuse
    GEOMETRIC
    ]]:::model
  ground_diffuse --> ground_diffuse_outputs
  click ground_diffuse "https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.irradiance.get_ground_diffuse.html"

  ground_diffuse_outputs([
    ground_diffuse
    ]):::outputs
  ground_diffuse_outputs --> poai_inputs

  %% --- Sky Diffuse ---
  sky_diffuse_inputs[\
    surface_tilt
    surface_azimuth
    dhi
    dni
    dni_extra
    apparent_zenith
    azimuth
    airmass_relative
    /]:::inputs
  sky_diffuse_inputs --> sky_diffuse

  sky_diffuse[[
    pvlib.irradiance
    .perez_driesse
    POAI
  ]]:::model
  sky_diffuse --> sky_diffuse_outputs
  click sky_diffuse "https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.irradiance.perez_driesse.html#pvlib.irradiance.perez_driesse"

  sky_diffuse_outputs([
    isotropic
    horizon
    circumsolar
    ]):::outputs
  sky_diffuse_outputs --> poai_inputs

  %% --- BEAM ---
  beam_inputs[\
    surface_tilt
    surface_azimuth
    solar_zenith
    solar_azimuth
    dni
    /]:::inputs
  beam_inputs --> beam

  beam[[
    pvlib.irradiance
    .beam_component
    GEOMETRIC
    ]]:::model
  beam --> beam_outputs
  click beam "https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.irradiance.beam.html"

  beam_outputs([
    beam
    ]):::outputs
  beam_outputs --> poai_inputs

  %% --- POAI ---
  poai_inputs[\
    isotropic
    circumsolar
    horizon
    ground_diffuse
    beam
    /]:::inputs
  poai_inputs --> poai

  poai[[
    proximal.poai_components
    SUM
  ]]:::model
  poai --> poai_outputs


  poai_outputs([
    poai_global
    ]):::outputs

Edits and Additions

If you would like to see support for another algorithm or would like to suggest edits or additions to this documentation page, please open an issue on the Proximal GitHub repository.

Effective Irradiance

General

The Effective Plane of Array Irradiance (EPOAI) is the amount of irradiance that is incident upon the active cell area of the photovoltaic array. This is differentiated from the Plane of Array Irradiance (POAI) which is the amount of irradiance that is incident upon the front face of the photovoltaic array glass.

Conceptually, losses calculated while calculating the effective plane of array irradiance are generally calculated in the same order as the physical losses that occur between the sun's rays and t`he cell active material. For example, soiling loss on top of the module glass is calculated before the incidence angle effect inside of the module glass. On the other hand, some losses such as spectral correction, which are actually material science losses are calculated empirical losses in effective plane of array irradiance.

Acronyms:

  • Irradiance
    • POAI: Plane of Array Irradiance
  • EPOAI: Effective Plane of Array Irradiance

Simulation Pipeline

The following flow diagram shows how the Effective Plane of Array Irradiance is calculated in the Proximal expected energy simulation. The flow chart is meant to be interactive. Clicking on any of the modeling step nodes will take you to the documentation for that modeling step.

You may need to zoom in to be able to better see all of the details in the flow chart.

Legend

  flowchart LR

  %% --- CLASSES ---
  classDef source fill:#6B7A8F, color:#CCCCCC
  classDef previous fill:#4F5B6F,color:#CCCCCC
  classDef model fill:#202020, color:#CCCCCC
  classDef inputs fill:#1A1A1A, color:#CCCCCC
  classDef outputs fill:#B39245, color:#CCCCCC

  database[(Database)]:::source
  previous{{Previous Calculation}}:::previous
  model_step[[
    Modeling Step
    DEFAULT MODEL CHOICE
  ]]:::model
  model_inputs[\
    Input Parameters
    for Modeling Step
  /]:::inputs
  model_outputs([Calculated Parameters]):::outputs

  database --> model_inputs
  previous --> model_inputs
  model_inputs --> model_step --> model_outputs --> model_inputs

Model Chain

flowchart TD

  %% --- CLASSES ---
  classDef source fill:#6B7A8F, color:#CCCCCC
  classDef previous fill:#4F5B6F,color:#CCCCCC
  classDef model fill:#202020, color:#CCCCCC
  classDef model_dashed fill:#202020, color:#CCCCCC, stroke-dasharray: 5 5
  classDef inputs fill:#1A1A1A, color:#CCCCCC
  classDef outputs fill:#B39245, color:#CCCCCC

  %% --- SOURCES ---
  met_station[(
    --- MET STATION ---
    soiling
  )]:::source
  met_station --> soiling_inputs

  pv_system[(
    --- PV Modules ---
    n
    K
    L
    n_ar
    cell_technology
  )]:::source
  pv_system --> direct_iam_inputs
  pv_system --> spectral_inputs

  tracker_params{{
    --- TRACKER PARAMS ---
    rotation_angle
    surface_tilt
    surface_azimuth
    aoi
  }}:::previous
  click tracker_params "tracker_rotation_angles.html"
  tracker_params --> direct_shade_inputs
  tracker_params --> direct_iam_inputs

  met_params{{
    --- MET PARAMS ---
    dhi
    dni
    dni_extra
    apparent_zenith
    azimuth
    airmass_relative
  }}:::previous
  click met_params "meteorological_parameters.html"
  met_params --> direct_shade_inputs
  met_params --> spectral_inputs

  poai_params{{
    --- POAI PARAMS ---
    isotropic
    horizon
    ground_diffuse
    circumsolar
    beam
  }}:::previous
  click poai_params "plane_of_array_irradiance.html"
  poai_params --> direct_shade_inputs

  %% --- Direct Shade ---
  direct_shade_inputs[\
    apparent_zenith
    azimuth
    axis_tilt
    axis_azimuth
    rotation_angle
    collector_width
    pitch
    surface_to_axis_offset
    cross_axis_slope
    shading_row_rotation
    /]:::inputs
  direct_shade_inputs --> direct_shade

  direct_shade[[
    pvlib.shading
    .shaded_fraction_1d
    ]]:::model
  click direct_shade "https://pvlib-python.readthedocs.io/en/latest/reference/generated/pvlib.shading.shaded_fraction1d.html"
  direct_shade --> direct_shade_outputs

  direct_shade_outputs([
      isotropic
      horizon
      ground_diffuse
      circumsolar - shade?
      beam - shade
    ]):::outputs
  direct_shade_outputs --> soiling_inputs

  %% --- Soiling ---
  soiling_inputs[\
    soiling_loss
    /]:::inputs
  soiling_inputs --> soiling

  soiling[[
    proximal.soiling
    RATIO
  ]]:::model
  soiling --> soiling_outputs

  soiling_outputs([
    isotropic - soil
    horizon - soil
    ground_diffuse - soil
    circumsolar - soil
    beam - soil
    ]):::outputs
  soiling_outputs --> direct_iam_inputs

  %% --- Direct IAM ---
  direct_iam_inputs[\
  aoi
  n
  K
  L
  n_ar
  /]:::inputs
  direct_iam_inputs --> direct_iam

  direct_iam[[
    pvlib.iam.physical
    PHYSICAL
  ]]:::model
  click direct_iam "https://pvlib-python.readthedocs.io/en/latest/reference/generated/pvlib.iam.physical.html"
  direct_iam --> direct_iam_outputs

  direct_iam_outputs([
      isotropic
      horizon
      ground_diffuse
      circumsolar - iam?
      beam - iam
    ]):::outputs
  direct_iam_outputs --> spectral_inputs

  %% --- Spectral ---
  spectral_inputs[\
      prcipitable_water
      airmass_absolute
      cdte_coefficients
      min_p_wat=0.1
      max_p_wat=8.0
      min_airmass_abs=0.58
      max_airmass_abs=10.0
    /]:::inputs
  spectral_inputs --> spectral

  spectral[[
    pvlib.spectral.spectral
    SPECTRAL
  ]]:::model
  click spectral "https://pvlib-python.readthedocs.io/en/latest/reference/generated/pvlib.spectrum.spectral_factor_firstsolar.html"
  spectral --> spectral_outputs

  spectral_outputs([
    isotropic - spectral
    horizon - spectral
    ground_diffuse - spectral
    circumsolar - spectral
    beam - spectral
    ]):::outputs
  spectral_outputs --> epoai_inputs

  %% --- EPOIA ---
  epoai_inputs[\
      isotropic
      horizon
      ground_diffuse
      circumsolar
      beam
      /]:::inputs
  epoai_inputs --> epoai

  epoai[[
    proximal.epoai_components
    SUM
  ]]:::model
  epoai --> epoai_outputs

  epoai_outputs([
    epoai_global
    ]):::outputs

Edits and Additions

If you would like to see support for another algorithm or would like to suggest edits or additions to this documentation page, please open an issue on the Proximal GitHub repository.

DC System Losses

General

DC system losses include losses that occur between the photovoltaic cell and the DC wiring to the inverter. In the diagrams, steps for combining power into strings and into combiners has been left out for the sake of brevity.

Acronyms:

  • DC: Direct Current
  • EPOAI: Effective Plane of Array Irradiance
  • i: Current
  • v: Voltage
  • p: Power
  • mp: Maximum Power
  • oc: Open Circuit

Simulation Pipeline

The following flow diagram shows how DC system losses are calculated in the Proximal expected energy simulation. The flow chart is meant to be interactive. Clicking on any of the modeling step nodes will take you to the documentation for that modeling step.

You may need to zoom in to be able to better see all of the details in the flow chart.

Legend

  flowchart LR

  %% --- CLASSES ---
  classDef source fill:#6B7A8F, color:#CCCCCC
  classDef previous fill:#4F5B6F,color:#CCCCCC
  classDef model fill:#202020, color:#CCCCCC
  classDef inputs fill:#1A1A1A, color:#CCCCCC
  classDef outputs fill:#B39245, color:#CCCCCC

  database[(Database)]:::source
  previous{{Previous Calculation}}:::previous
  model_step[[
    Modeling Step
    DEFAULT MODEL CHOICE
  ]]:::model
  model_inputs[\
    Input Parameters
    for Modeling Step
  /]:::inputs
  model_outputs([Calculated Parameters]):::outputs

  database --> model_inputs
  previous --> model_inputs
  model_inputs --> model_step --> model_outputs --> model_inputs

Model Chain

flowchart TD

  %% --- CLASSES ---
  classDef source fill:#6B7A8F, color:#CCCCCC
  classDef previous fill:#4F5B6F,color:#CCCCCC
  classDef model fill:#202020, color:#CCCCCC
  classDef model_dashed fill:#202020, color:#CCCCCC, stroke-dasharray: 5 5
  classDef inputs fill:#1A1A1A, color:#CCCCCC
  classDef outputs fill:#B39245, color:#CCCCCC

  %% --- SOURCES ---
  met_station[(
    --- MET STATION ---
    ambient temperature
    wind speed
  )]:::source
  met_station --> cell_temperature_inputs

  epoai{{
    --- EPOAI ---
    epoai
  }}:::previous
  click tracker_params "effective_plane_of_array_irradiance.html"
  epoai --> cell_temperature_inputs
  epoai --> single_diode_inputs

  %% --- Cell Temperature ---
  cell_temperature_inputs[\
    epoai
    ambient temperature
    wind speed
    /]:::inputs
  cell_temperature_inputs --> cell_temperature

  cell_temperature[[
    pvlib.temperature
    .pvsyst_cell
    PVSYST_CELL
    ]]:::model
  cell_temperature --> cell_temperature_outputs
  click cell_temperature "https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.temperature.pvsyst_cell.html#pvlib.temperature.pvsyst_cell"

  cell_temperature_outputs([
    cell_temperature
    ]):::outputs
  cell_temperature_outputs --> single_diode_inputs

  %% --- Single Diode Model ---
  single_diode_inputs[\
    epoai
    cell temperature
    module parameters
    /]:::inputs
  single_diode_inputs --> single_diode

  single_diode[[
    pvlib.pvsystem
    .calcparams_desoto
    DESOTO
    ]]:::model
  click single_diode "https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.pvsystem.calcparams_desoto.html#pvlib-pvsystem-calcparams-desoto"
  single_diode --> single_diode_outputs

  single_diode_outputs([
    single diode parameters
  ]):::outputs
  single_diode_outputs --> iv_inputs

  %% --- IV Curve ---
  iv_inputs[\
    single diode parameters
    /]:::inputs
  iv_inputs --> iv

  iv[[
    pvlib.pvsystem
    .singlediode
    ]]:::Model
  click iv "https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.pvsystem.singlediode.html#pvlib.pvsystem.singlediode"
  iv --> iv_outputs

  iv_outputs([
    iv_curve
  ]):::outputs
  iv_outputs --> degradation_inputs

  %% --- Degradation ---
  degradation_inputs[\
    iv_curve
    /]:::inputs
  degradation_inputs --> degradation

  degradation[[
    proximal.degradation
    RATIO
  ]]:::model
  degradation --> degradation_outputs

  degradation_outputs([
    iv_curve
  ]):::outputs
  degradation_outputs --> wiring_inputs

  %% --- DC Wiring to Combiner ---
  wiring_inputs[\
    iv_curve
    /]:::inputs
  wiring_inputs --> wiring

  wiring[[
    proximal.target_stc
    TARGET LOSS AT STC
    ]]:::model
  wiring --> wiring_outputs

  wiring_outputs([
    iv_curve
  ]):::outputs


Edits and Additions

If you would like to see support for another algorithm or would like to suggest edits or additions to this documentation page, please open an issue on the Proximal GitHub repository.

PV Module Definition

Single Diode Model Parameters

The single diode model requires a set of PV module parameters. These parameters are generally calculated at a test lab and placed inside of a .PAN file. The Proximal platform can read data from a .PAN file or from the CEC database of pv modules.

Other Parameters

There are other parameters that may or may not be included in the .PAN file that Proximal needs for performance modeling purposes. These parameters may appear on a data sheet or can be found by contacting the manufacturer.

  • Warranted Degradation Rate
  • Warranted Degradation at Year Zero
  • Length
  • Width
  • Frame overhang: Describes the non-active PV between the PV active cell and the edge of the module frame
  • AR coating presence

Degradation

General

The Proximal platform automatically creates a model with warranted module degradation baked in. This module degradation occurs on the DC side of the plant and therefore cannot be post-processed due to the effects of clipping.

The warranted module degradation curve is module specific and usually comes in the form of an initial degradation value at year zero and a linear or piecewise linear drop from year one on-wards.

Degradation in PV modules can occur in both current and voltage. The Proximal model currently assumes a 50% degradation in current and 50% degradation in voltage for a given warranted degradation in power.

A different assumption can be used for a given PV module technology, if specified by the user.

AC System Losses

General

AC system modeling begins after DC power has been calculated at each combiner. The model applies the remaining DC wiring loss, combines child combiners at each inverter, converts DC power to AC power, applies transformer losses, and combines the result into expected power at the point of interconnection.

The electrical hierarchy stored for the project determines which combiners feed each inverter and which inverters feed each transformer.

Acronyms

  • AC: Alternating Current
  • DC: Direct Current
  • i: Current
  • v: Voltage
  • p: Power
  • mp: Maximum Power
  • POI: Point of Interconnection
  • STC: Standard Test Conditions

Simulation Pipeline

The following flow diagram shows how AC system losses are calculated in the Proximal expected energy simulation. The flow chart is interactive. Clicking a model step will take you to its external documentation when available.

You may need to zoom in to better see all of the details in the flow chart.

Legend

flowchart LR

  classDef source fill:#6B7A8F, color:#CCCCCC
  classDef previous fill:#4F5B6F,color:#CCCCCC
  classDef model fill:#202020, color:#CCCCCC
  classDef inputs fill:#1A1A1A, color:#CCCCCC
  classDef outputs fill:#B39245, color:#CCCCCC

  database[(Database)]:::source
  previous{{Previous Calculation}}:::previous
  model_step[[
    Modeling Step
    DEFAULT MODEL CHOICE
  ]]:::model
  model_inputs[\
    Input Parameters
    for Modeling Step
  /]:::inputs
  model_outputs([Calculated Parameters]):::outputs

  database --> model_inputs
  previous --> model_inputs
  model_inputs --> model_step --> model_outputs --> model_inputs

Model Chain

flowchart TD

  classDef source fill:#6B7A8F, color:#CCCCCC
  classDef previous fill:#4F5B6F,color:#CCCCCC
  classDef model fill:#202020, color:#CCCCCC
  classDef inputs fill:#1A1A1A, color:#CCCCCC
  classDef outputs fill:#B39245, color:#CCCCCC

  combiner_power{{
    --- COMBINER POWER ---
    i_mp
    v_mp
    i_sc
    v_oc
  }}:::previous
  click combiner_power "dc_system_losses.html"

  system[(
    --- SYSTEM ---
    combiner to inverter assignments
    inverter to transformer assignments
    DC wiring loss at STC
    POI limit
  )]:::source

  inverter[(
    --- INVERTER ---
    nominal AC power
    nominal DC power and voltage
    startup power
    efficiency coefficients
    night tare
  )]:::source

  transformer[(
    --- TRANSFORMER ---
    rating
    no-load loss
    load loss
  )]:::source

  dc_wiring_inputs[\
    combiner IV values
    DC wiring loss at STC
  /]:::inputs
  combiner_power --> dc_wiring_inputs
  system --> dc_wiring_inputs

  dc_wiring[[
    proximal.dc_wiring_to_inverter
    TARGET LOSS AT STC
  ]]:::model
  dc_wiring_inputs --> dc_wiring --> dc_wiring_outputs

  dc_wiring_outputs([
    i_mp
    v_mp after wiring loss
    i_sc
    v_oc
  ]):::outputs

  combine_inverter_inputs[\
    combiner IV values
    combiner to inverter assignments
  /]:::inputs
  dc_wiring_outputs --> combine_inverter_inputs
  system --> combine_inverter_inputs

  combine_inverter[[
    proximal.combine_at_inverter
    ELECTRICAL AGGREGATION
  ]]:::model
  combine_inverter_inputs --> combine_inverter --> combine_inverter_outputs

  combine_inverter_outputs([
    inverter DC power
    inverter DC current
    inverter DC voltage
  ]):::outputs

  inverter_efficiency_inputs[\
    DC power
    DC voltage
    inverter parameters
  /]:::inputs
  combine_inverter_outputs --> inverter_efficiency_inputs
  inverter --> inverter_efficiency_inputs

  inverter_efficiency[[
    pvlib.inverter.sandia
    SANDIA
  ]]:::model
  click inverter_efficiency "https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.inverter.sandia.html"
  inverter_efficiency_inputs --> inverter_efficiency --> inverter_efficiency_outputs

  inverter_efficiency_outputs([
    AC power by inverter
  ]):::outputs

  ac_wiring_inputs[\
    inverter AC power
    nominal inverter AC power
  /]:::inputs
  inverter_efficiency_outputs --> ac_wiring_inputs
  inverter --> ac_wiring_inputs

  ac_wiring[[
    proximal.ac_wiring_to_transformer
    LOAD-DEPENDENT LOSS
  ]]:::model
  ac_wiring_inputs --> ac_wiring --> ac_wiring_outputs

  ac_wiring_outputs([
    AC power after wiring loss
  ]):::outputs

  combine_transformer_inputs[\
    inverter AC power
    inverter to transformer assignments
  /]:::inputs
  ac_wiring_outputs --> combine_transformer_inputs
  system --> combine_transformer_inputs

  combine_transformer[[
    proximal.combine_at_transformer
    SUM
  ]]:::model
  combine_transformer_inputs --> combine_transformer --> combine_transformer_outputs

  combine_transformer_outputs([
    input power by transformer
  ]):::outputs

  transformer_efficiency_inputs[\
    transformer input power
    rating
    no-load loss
    load loss
  /]:::inputs
  combine_transformer_outputs --> transformer_efficiency_inputs
  transformer --> transformer_efficiency_inputs

  transformer_efficiency[[
    pvlib.transformer.simple_efficiency
    SIMPLE EFFICIENCY
  ]]:::model
  click transformer_efficiency "https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.transformer.simple_efficiency.html"
  transformer_efficiency_inputs --> transformer_efficiency --> transformer_efficiency_outputs

  transformer_efficiency_outputs([
    AC power by transformer
  ]):::outputs

  poi_inputs[\
    transformer AC power
    POI limit
  /]:::inputs
  transformer_efficiency_outputs --> poi_inputs
  system --> poi_inputs

  poi[[
    proximal.point_of_interconnection
    SUM AND CLIP
  ]]:::model
  poi_inputs --> poi --> poi_outputs

  poi_outputs([
    expected power at POI
  ]):::outputs

Model Behavior

  • DC wiring loss from the combiner to the inverter is scaled from the configured loss at standard test conditions using the operating current.
  • Combiner currents are summed at each inverter, while combiner voltages are averaged.
  • The default inverter model is the Sandia inverter model. PVWatts is also supported.
  • Transformer efficiency accounts for transformer rating, no-load loss, and load loss.
  • Transformer power is summed at the project level and limited to the configured point of interconnection capacity. Negative power is limited to zero.

Edits and Additions

If you would like to see support for another algorithm or would like to suggest edits or additions to this documentation page, please open an issue on the Proximal GitHub repository.

Quality Control Docs

General

Even more important than the performance model (at times) are the quality control measures used to make sure that the input data to the model is correct. The following sections detail how input data is filtered in the proximal performance model.

Soiling Sensors

IndexPhysical IssueMitigation Strategy
1Some soiling measurement stations only take one measurement per day. These sensors by definition cannot characterize the IAM effect of the soiling on top of the module glass. The effect of incidence angle on soiling can be up to 10% relative to the absolute soiling amount. For example, a 30% soiled module can have an IAM effect up to around 3%.Proximal currently does not model the additional IAM effect
2Some soiling measurement stations report erroneous values such as 100% soiled for unknown reasons.Proximal filters out values with greater than 90% reported soiling.
3Optical soiling sensors cannot characterize the electrical effect of non-uniform soilingProximal does not account for this
4Single active component sensors cannot characterize the electrical effect of non-uniform snow soilingProximal does not account for this

Measurement Uncertainty

General

All data in the Proximal platform is inherently uncertain. This is due to the fact that sensors have inherent uncertainty and models have uncertainty on top of that. The following tables are a reference for users to use in order to understand the data and models being reported by the platform.

Defaults

By default all reported values below are:

  • 95% Uncertainty (Expanded) (U)

Irradiance Sensor Uncertainty

SensorMeasurement UncertaintyReference
Class A Pyranometer±2% (daily total absolute)1
Class A Pyranometer±3% (hourly total absolute)1

Soiling Sensor Uncertainty

SensorMeasurement UncertaintyReference
Optical±4-7% (relative)2
Cell-Cell±4-7% (relative)2
Cell-Module (power)±1-2% (relative)2
Cell-Module (current)±3-5% (relative)2
Module-Module±4-7% (relative)2
Cell-Cell±4-7% (relative)2

Notes

  • Optical sensors may not capture the IAM effects of soiling
  • Cell-Cell sensors will not capture the effects of non-uniform soiling
  • Cell-Cell sensors may have a different glass than the install PV modules and may soil differently

Inverter

SensorMeasurement UncertaintyReference
Class A Current Input±2% (absolute)3
Class A Voltage Input±2% (absolute)3
Class A Power Input±3% (absolute)3
Class A Current Output±2% (absolute)3
Class A Voltage Output±2% (absolute)3
Class A Power Output±3% (absolute)3

Meter

SensorMeasurement UncertaintyReference
Meter±0.2% (absolute)4

References

  1. WMO 1.7-12
  2. Atonometrics Whitepaper
  3. IEC 61724-1:2021 Section 11.1
  4. IEC 62053-22:2020

Changelog

2025-07-28

New Features

  • Unveiling the new Portfolio Calendar View! Visualize your project timelines and key dates across your entire portfolio at a glance.
  • Introducing dynamic Single Line Diagrams for projects, providing a clear visual representation of your electrical systems.
  • Welcome the brand-new Oriden theme for a fresh, customized look and feel.
  • Customize your workspace with the vibrant new Lightsource theme.

Improvements

  • Enhanced performance and stability when processing large datasets, ensuring a smoother and more reliable experience.

Bug Fixes

  • Resolved an edge-case issue to improve overall platform stability.

2025-07-07

Improvements

  • Enhanced the KPI project comparison plot to display full legend names, making it easier to identify and compare different projects.

2025-06-30

New Features

  • Added real-time data support for BESS (Battery Energy Storage Systems), enhancing visibility and operational insights.

Improvements

  • Refactored PV equipment logic for improved performance and maintainability.

Bug Fixes

  • Fixed an issue with the API endpoint for updating user projects in the admin module.

2025-06-23

New Features

  • Custom Theming: Added extensive theming capabilities to provide a more customized user experience.
  • KPI Portfolio Comparison: KPI reports can now include portfolio-level comparisons, enabling broader performance analysis across multiple projects.

Improvements

  • GIS Map: The GIS map on the project Home page now features a new layer selector, making it easier to switch between different map views.
  • Project Calendar: A Project calendar is now available for users to add project-related reporting deadlines, site visits and other items.
  • Performance: Optimized the loading of pages that display open event counts.
  • BESS Analysis: The date range selector for BESS Equipment Analysis has been updated for better usability.

Bug Fixes

  • Navigation: Corrected navigation links from the Equipment Analysis page to Project Energy KPI and from Uptime metrics to Data Browsing.
  • Real-Time Page: Added missing axis labels to heatmaps for improved clarity.
  • Data Visualization: Resolved an issue where plots would not update correctly after changing filter selections.
  • UI: Fixed a minor visual glitch in the calendar display.

2025-06-16

New Features

  • Real Time Page: Added a x-axis labels to graphs on the real time page

Bug Fixes

  • GIS Maps: Hovering over a met station no longer shows PCS data

2025-06-09

New Features

  • Weather & Forecast: Improved display and added appropriate attribution to OpenWeatherMap.

Bug Fixes

  • DC Amperage Report: Improved error handling to display feedback to user if the report fails to complete.
  • CMMS Tab: Corrected error handling that would cause the page to crash.

2025-06-02

New Features

  • Inverter Availability Report: A new report page has been added to monitor inverter availability across projects. The report is downloadable as an Excel file, allowing users to modify input parameters directly within the spreadsheet to perform custom analyses or generate updated availability metrics.

  • Admin User Management: Introduced a comprehensive admin dashboard for managing users, assigning projects, and more.

  • CMMS Tab for All Projects: All projects now have access to the CMMS tab, streamlining asset ticket management.

Other Improvements

  • Cleaned up UI in several report pages to improve clarity and consistency.