mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-10-08 15:26:38 +00:00
Add PVForecastAkkudoktorLocal, which runs the modelling chain inside EOS on raw Open-Meteo irradiance instead of calling a forecast service: solar position, horizon shading, plane transposition, incidence-angle modifier, cell temperature, PVWatts DC and inverter AC. It needs no API key and serves up to 16 days at 15-minute resolution from a single hourly request, which is what keeps `optimization.tail_horizon_hours` fed - services wrapping Open-Meteo cut the horizon much shorter. Several Open-Meteo models can be listed in `weather_models` and are averaged per variable at no extra request cost. With `calibration_enabled` the provider fits itself against `measurement.pv_production_emr_keys` over the past `calibration_days`: a global scale factor plus optional per-solar-azimuth factors, each weighted by modelled energy, shrunk toward the global factor by `calibration_prior_kwh` and clamped to `[calibration_min_factor, calibration_max_factor]`. The comparison runs on past intervals, where Open-Meteo serves analysed rather than forecast weather, so it corrects the error of the PV model and not that of the weather forecast. Calibration is a scale factor on the output and never touches `userhorizon`, `surface_tilt`, `surface_azimuth` or `peakpower`. The docs say so, and say why a short window and a plant fault inside it are the two ways to end up with a misleading factor. Also add `Measurement.pv_production_total_kwh()` alongside the existing load total, and `scripts/pvforecast_backtest.py`, which scores configuration variants against the stored meter readings without waiting for new forecasts to come true.
529 lines
21 KiB
Markdown
529 lines
21 KiB
Markdown
## PV Forecast Configuration
|
|
|
|
<!-- pyml disable line-length -->
|
|
:::{table} pvforecast
|
|
:widths: 10 20 10 5 5 30
|
|
:align: left
|
|
|
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
|
| max_planes | `EOS_PVFORECAST__MAX_PLANES` | `Optional[int]` | `rw` | `0` | Maximum number of planes that can be set |
|
|
| planes | `EOS_PVFORECAST__PLANES` | `Optional[list[akkudoktoreos.prediction.pvforecast.PVForecastPlaneSetting]]` | `rw` | `None` | Plane configuration. |
|
|
| planes_azimuth | | `List[float]` | `ro` | `N/A` | Compute a list of the azimuths per active planes. |
|
|
| planes_inverter_paco | | `Any` | `ro` | `N/A` | Compute a list of the maximum power rating of the inverter per active planes. |
|
|
| planes_peakpower | | `List[float]` | `ro` | `N/A` | Compute a list of the peak power per active planes. |
|
|
| planes_tilt | | `List[float]` | `ro` | `N/A` | Compute a list of the tilts per active planes. |
|
|
| planes_userhorizon | | `Any` | `ro` | `N/A` | Compute a list of the user horizon per active planes. |
|
|
| provider | `EOS_PVFORECAST__PROVIDER` | `Optional[str]` | `rw` | `None` | PVForecast provider id of provider to be used. |
|
|
| provider_settings | `EOS_PVFORECAST__PROVIDER_SETTINGS` | `PVForecastCommonProviderSettings` | `rw` | `required` | Provider settings |
|
|
| providers | | `list[str]` | `ro` | `N/A` | Available PVForecast provider ids. |
|
|
:::
|
|
<!-- pyml enable line-length -->
|
|
|
|
<!-- pyml disable no-emphasis-as-heading -->
|
|
**Example Input**
|
|
<!-- pyml enable no-emphasis-as-heading -->
|
|
|
|
<!-- pyml disable line-length -->
|
|
```json
|
|
{
|
|
"pvforecast": {
|
|
"provider": "PVForecastAkkudoktor",
|
|
"provider_settings": {
|
|
"PVForecastImport": null,
|
|
"PVForecastVrm": null,
|
|
"PVForecastPVNode": null,
|
|
"PVForecastForecastSolar": null,
|
|
"PVForecastSolcast": null,
|
|
"PVForecastAkkudoktorLocal": null
|
|
},
|
|
"planes": [
|
|
{
|
|
"surface_tilt": 10.0,
|
|
"surface_azimuth": 180.0,
|
|
"userhorizon": [
|
|
10.0,
|
|
20.0,
|
|
30.0
|
|
],
|
|
"peakpower": 5.0,
|
|
"pvtechchoice": "crystSi",
|
|
"mountingplace": "free",
|
|
"loss": 14.0,
|
|
"trackingtype": 0,
|
|
"optimal_surface_tilt": false,
|
|
"optimalangles": false,
|
|
"albedo": null,
|
|
"module_model": null,
|
|
"inverter_model": null,
|
|
"inverter_paco": 6000,
|
|
"modules_per_string": 20,
|
|
"strings_per_inverter": 2
|
|
},
|
|
{
|
|
"surface_tilt": 20.0,
|
|
"surface_azimuth": 90.0,
|
|
"userhorizon": [
|
|
5.0,
|
|
15.0,
|
|
25.0
|
|
],
|
|
"peakpower": 3.5,
|
|
"pvtechchoice": "crystSi",
|
|
"mountingplace": "free",
|
|
"loss": 14.0,
|
|
"trackingtype": 1,
|
|
"optimal_surface_tilt": false,
|
|
"optimalangles": false,
|
|
"albedo": null,
|
|
"module_model": null,
|
|
"inverter_model": null,
|
|
"inverter_paco": 4000,
|
|
"modules_per_string": 20,
|
|
"strings_per_inverter": 2
|
|
}
|
|
],
|
|
"max_planes": 1
|
|
}
|
|
}
|
|
```
|
|
<!-- pyml enable line-length -->
|
|
|
|
<!-- pyml disable no-emphasis-as-heading -->
|
|
**Example Output**
|
|
<!-- pyml enable no-emphasis-as-heading -->
|
|
|
|
<!-- pyml disable line-length -->
|
|
```json
|
|
{
|
|
"pvforecast": {
|
|
"provider": "PVForecastAkkudoktor",
|
|
"provider_settings": {
|
|
"PVForecastImport": null,
|
|
"PVForecastVrm": null,
|
|
"PVForecastPVNode": null,
|
|
"PVForecastForecastSolar": null,
|
|
"PVForecastSolcast": null,
|
|
"PVForecastAkkudoktorLocal": null
|
|
},
|
|
"planes": [
|
|
{
|
|
"surface_tilt": 10.0,
|
|
"surface_azimuth": 180.0,
|
|
"userhorizon": [
|
|
10.0,
|
|
20.0,
|
|
30.0
|
|
],
|
|
"peakpower": 5.0,
|
|
"pvtechchoice": "crystSi",
|
|
"mountingplace": "free",
|
|
"loss": 14.0,
|
|
"trackingtype": 0,
|
|
"optimal_surface_tilt": false,
|
|
"optimalangles": false,
|
|
"albedo": null,
|
|
"module_model": null,
|
|
"inverter_model": null,
|
|
"inverter_paco": 6000,
|
|
"modules_per_string": 20,
|
|
"strings_per_inverter": 2
|
|
},
|
|
{
|
|
"surface_tilt": 20.0,
|
|
"surface_azimuth": 90.0,
|
|
"userhorizon": [
|
|
5.0,
|
|
15.0,
|
|
25.0
|
|
],
|
|
"peakpower": 3.5,
|
|
"pvtechchoice": "crystSi",
|
|
"mountingplace": "free",
|
|
"loss": 14.0,
|
|
"trackingtype": 1,
|
|
"optimal_surface_tilt": false,
|
|
"optimalangles": false,
|
|
"albedo": null,
|
|
"module_model": null,
|
|
"inverter_model": null,
|
|
"inverter_paco": 4000,
|
|
"modules_per_string": 20,
|
|
"strings_per_inverter": 2
|
|
}
|
|
],
|
|
"max_planes": 1,
|
|
"providers": [
|
|
"PVForecastAkkudoktor",
|
|
"PVForecastVrm",
|
|
"PVForecastPVNode",
|
|
"PVForecastForecastSolar",
|
|
"PVForecastSolcast",
|
|
"PVForecastImport",
|
|
"PVForecastAkkudoktorLocal"
|
|
],
|
|
"planes_peakpower": [
|
|
5.0,
|
|
3.5
|
|
],
|
|
"planes_azimuth": [
|
|
180.0,
|
|
90.0
|
|
],
|
|
"planes_tilt": [
|
|
10.0,
|
|
20.0
|
|
],
|
|
"planes_userhorizon": [
|
|
[
|
|
10.0,
|
|
20.0,
|
|
30.0
|
|
],
|
|
[
|
|
5.0,
|
|
15.0,
|
|
25.0
|
|
]
|
|
],
|
|
"planes_inverter_paco": [
|
|
6000.0,
|
|
4000.0
|
|
]
|
|
}
|
|
}
|
|
```
|
|
<!-- pyml enable line-length -->
|
|
|
|
### Common settings for the local (pvlib) PV forecast provider
|
|
|
|
<!-- pyml disable line-length -->
|
|
:::{table} pvforecast::provider_settings::PVForecastAkkudoktorLocal
|
|
:widths: 10 10 5 5 30
|
|
:align: left
|
|
|
|
| Name | Type | Read-Only | Default | Description |
|
|
| ---- | ---- | --------- | ------- | ----------- |
|
|
| albedo | `float` | `rw` | `0.25` | Ground albedo used for planes that do not set their own. |
|
|
| apply_iam | `bool` | `rw` | `True` | Apply the ASHRAE incidence-angle modifier to the beam component. |
|
|
| calibration_azimuth_bin_degrees | `int` | `rw` | `15` | Width of the solar-azimuth bins for the correction. 0 fits a single global factor only. |
|
|
| calibration_days | `int` | `rw` | `30` | Length of the measurement window used to fit the correction. |
|
|
| calibration_enabled | `bool` | `rw` | `False` | Correct systematic model error against measured PV production. Requires `measurement.pv_production_emr_keys` to be configured and fed. Fits a global scale factor plus per-solar-azimuth factors, which is what catches near-field shading the horizon profile misses. |
|
|
| calibration_max_factor | `float` | `rw` | `1.5` | Upper clamp on any fitted correction factor. |
|
|
| calibration_min_factor | `float` | `rw` | `0.5` | Lower clamp on any fitted correction factor. |
|
|
| calibration_prior_kwh | `float` | `rw` | `5.0` | Shrinkage strength: a bin needs this much modelled energy before its own factor outweighs the global one. Higher is more conservative. |
|
|
| forecast_days | `Optional[int]` | `rw` | `None` | Forecast horizon in days (1-16). Leave empty to derive it from `prediction.hours`, which is what keeps the optimizer's tail horizon fed. |
|
|
| inverter_efficiency | `float` | `rw` | `0.96` | Nominal inverter efficiency (PVWatts eta_inv_nom). |
|
|
| past_days | `Optional[int]` | `rw` | `None` | Days of past data to request (0-92). Leave empty to derive it from `prediction.historic_hours`. |
|
|
| resolution_minutes | `int` | `rw` | `15` | Forecast resolution in minutes. 15 requests Open-Meteo's `minutely_15` block (natively resolved over Central Europe and North America, interpolated from hourly elsewhere); 60 requests the `hourly` block. |
|
|
| shift_to_interval_start | `bool` | `rw` | `True` | Open-Meteo stamps an interval mean with the interval END. EOS labels an interval by its START, so records are shifted back by one interval. Disable only to compare like-for-like against a provider that does not. |
|
|
| temperature_coefficient | `float` | `rw` | `-0.36` | Module power temperature coefficient in %/degC (negative). Matches the `cellCoEff` the akkudoktor.net forecast uses. |
|
|
| transposition_model | `str` | `rw` | `perez` | pvlib sky-diffuse transposition model: isotropic, klucher, haydavies, reindl, king or perez. |
|
|
| weather_models | `list[str]` | `rw` | `['best_match']` | Open-Meteo weather models to request. Listing more than one turns the input into a poor-man's ensemble: the members are averaged per variable, which is the cheapest reliable way to cut irradiance forecast error. Costs no extra API calls. |
|
|
:::
|
|
<!-- pyml enable line-length -->
|
|
|
|
<!-- pyml disable no-emphasis-as-heading -->
|
|
**Example Input/Output**
|
|
<!-- pyml enable no-emphasis-as-heading -->
|
|
|
|
<!-- pyml disable line-length -->
|
|
```json
|
|
{
|
|
"pvforecast": {
|
|
"provider_settings": {
|
|
"PVForecastAkkudoktorLocal": {
|
|
"resolution_minutes": 15,
|
|
"forecast_days": null,
|
|
"past_days": null,
|
|
"weather_models": [
|
|
"best_match"
|
|
],
|
|
"transposition_model": "perez",
|
|
"albedo": 0.25,
|
|
"inverter_efficiency": 0.96,
|
|
"temperature_coefficient": -0.36,
|
|
"apply_iam": true,
|
|
"shift_to_interval_start": true,
|
|
"calibration_enabled": true,
|
|
"calibration_days": 30,
|
|
"calibration_azimuth_bin_degrees": 15,
|
|
"calibration_prior_kwh": 5.0,
|
|
"calibration_min_factor": 0.5,
|
|
"calibration_max_factor": 1.5
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
<!-- pyml enable line-length -->
|
|
|
|
### Common settings for the Solcast PV forecast provider
|
|
|
|
<!-- pyml disable line-length -->
|
|
:::{table} pvforecast::provider_settings::PVForecastSolcast
|
|
:widths: 10 10 5 5 30
|
|
:align: left
|
|
|
|
| Name | Type | Read-Only | Default | Description |
|
|
| ---- | ---- | --------- | ------- | ----------- |
|
|
| api_key | `str` | `rw` | `` | Solcast API key (Bearer auth). Required. |
|
|
| site_id | `str` | `rw` | `` | Solcast rooftop site (resource) id. Required. |
|
|
:::
|
|
<!-- pyml enable line-length -->
|
|
|
|
<!-- pyml disable no-emphasis-as-heading -->
|
|
**Example Input/Output**
|
|
<!-- pyml enable no-emphasis-as-heading -->
|
|
|
|
<!-- pyml disable line-length -->
|
|
```json
|
|
{
|
|
"pvforecast": {
|
|
"provider_settings": {
|
|
"PVForecastSolcast": {
|
|
"api_key": "your-solcast-key",
|
|
"site_id": "abcd-1234-efgh-5678"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
<!-- pyml enable line-length -->
|
|
|
|
### Common settings for the Forecast.Solar PV forecast provider
|
|
|
|
<!-- pyml disable line-length -->
|
|
:::{table} pvforecast::provider_settings::PVForecastForecastSolar
|
|
:widths: 10 10 5 5 30
|
|
:align: left
|
|
|
|
| Name | Type | Read-Only | Default | Description |
|
|
| ---- | ---- | --------- | ------- | ----------- |
|
|
| api_key | `Optional[str]` | `rw` | `None` | Forecast.Solar API key. Optional — the public endpoint works without a key (lower rate limit). |
|
|
:::
|
|
<!-- pyml enable line-length -->
|
|
|
|
<!-- pyml disable no-emphasis-as-heading -->
|
|
**Example Input/Output**
|
|
<!-- pyml enable no-emphasis-as-heading -->
|
|
|
|
<!-- pyml disable line-length -->
|
|
```json
|
|
{
|
|
"pvforecast": {
|
|
"provider_settings": {
|
|
"PVForecastForecastSolar": {
|
|
"api_key": null
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
<!-- pyml enable line-length -->
|
|
|
|
### Common settings for the pvnode.com PV forecast provider
|
|
|
|
<!-- pyml disable line-length -->
|
|
:::{table} pvforecast::provider_settings::PVForecastPVNode
|
|
:widths: 10 10 5 5 30
|
|
:align: left
|
|
|
|
| Name | Type | Read-Only | Default | Description |
|
|
| ---- | ---- | --------- | ------- | ----------- |
|
|
| api_key | `str` | `rw` | `` | pvnode.com API key (Bearer auth). Required. |
|
|
| forecast_days | `int` | `rw` | `2` | Forecast horizon in days (1-7, capped by the pvnode plan). |
|
|
| site_id | `Optional[str]` | `rw` | `None` | pvnode.com site id of the saved plant ('Anlagen-ID'). When set, the saved (possibly calibrated) site is used. Leave empty to send the configured pvforecast.planes inline instead. |
|
|
:::
|
|
<!-- pyml enable line-length -->
|
|
|
|
<!-- pyml disable no-emphasis-as-heading -->
|
|
**Example Input/Output**
|
|
<!-- pyml enable no-emphasis-as-heading -->
|
|
|
|
<!-- pyml disable line-length -->
|
|
```json
|
|
{
|
|
"pvforecast": {
|
|
"provider_settings": {
|
|
"PVForecastPVNode": {
|
|
"api_key": "pvn_live_xxxxxxxxxxxxxxxx",
|
|
"site_id": "abcd-1234",
|
|
"forecast_days": 2
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
<!-- pyml enable line-length -->
|
|
|
|
### Common settings for PV forecast VRM API
|
|
|
|
<!-- pyml disable line-length -->
|
|
:::{table} pvforecast::provider_settings::PVForecastVrm
|
|
:widths: 10 10 5 5 30
|
|
:align: left
|
|
|
|
| Name | Type | Read-Only | Default | Description |
|
|
| ---- | ---- | --------- | ------- | ----------- |
|
|
| pvforecast_vrm_idsite | `int` | `rw` | `12345` | VRM-Installation-ID |
|
|
| pvforecast_vrm_token | `str` | `rw` | `your-token` | Token for Connecting VRM API |
|
|
:::
|
|
<!-- pyml enable line-length -->
|
|
|
|
<!-- pyml disable no-emphasis-as-heading -->
|
|
**Example Input/Output**
|
|
<!-- pyml enable no-emphasis-as-heading -->
|
|
|
|
<!-- pyml disable line-length -->
|
|
```json
|
|
{
|
|
"pvforecast": {
|
|
"provider_settings": {
|
|
"PVForecastVrm": {
|
|
"pvforecast_vrm_token": "your-token",
|
|
"pvforecast_vrm_idsite": 12345
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
<!-- pyml enable line-length -->
|
|
|
|
### Common settings for pvforecast data import from file or JSON string
|
|
|
|
<!-- pyml disable line-length -->
|
|
:::{table} pvforecast::provider_settings::PVForecastImport
|
|
:widths: 10 10 5 5 30
|
|
:align: left
|
|
|
|
| Name | Type | Read-Only | Default | Description |
|
|
| ---- | ---- | --------- | ------- | ----------- |
|
|
| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | Path to the file to import PV forecast data from. |
|
|
| import_json | `Optional[str]` | `rw` | `None` | JSON string, dictionary of PV forecast value lists. |
|
|
:::
|
|
<!-- pyml enable line-length -->
|
|
|
|
<!-- pyml disable no-emphasis-as-heading -->
|
|
**Example Input/Output**
|
|
<!-- pyml enable no-emphasis-as-heading -->
|
|
|
|
<!-- pyml disable line-length -->
|
|
```json
|
|
{
|
|
"pvforecast": {
|
|
"provider_settings": {
|
|
"PVForecastImport": {
|
|
"import_file_path": null,
|
|
"import_json": "{\"pvforecast_ac_power\": [0, 8.05, 352.91]}"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
<!-- pyml enable line-length -->
|
|
|
|
### PV Forecast Provider Configuration
|
|
|
|
<!-- pyml disable line-length -->
|
|
:::{table} pvforecast::provider_settings
|
|
:widths: 10 10 5 5 30
|
|
:align: left
|
|
|
|
| Name | Type | Read-Only | Default | Description |
|
|
| ---- | ---- | --------- | ------- | ----------- |
|
|
| PVForecastForecastSolar | `Optional[akkudoktoreos.prediction.pvforecastforecastsolar.PVForecastForecastSolarCommonSettings]` | `rw` | `None` | PVForecastForecastSolar settings |
|
|
| PVForecastImport | `Optional[akkudoktoreos.prediction.pvforecastimport.PVForecastImportCommonSettings]` | `rw` | `None` | PVForecastImport settings |
|
|
| PVForecastAkkudoktorLocal | `Optional[akkudoktoreos.prediction.pvforecastlocal.PVForecastAkkudoktorLocalCommonSettings]` | `rw` | `None` | PVForecastAkkudoktorLocal settings |
|
|
| PVForecastPVNode | `Optional[akkudoktoreos.prediction.pvforecastpvnode.PVForecastPVNodeCommonSettings]` | `rw` | `None` | PVForecastPVNode settings |
|
|
| PVForecastSolcast | `Optional[akkudoktoreos.prediction.pvforecastsolcast.PVForecastSolcastCommonSettings]` | `rw` | `None` | PVForecastSolcast settings |
|
|
| PVForecastVrm | `Optional[akkudoktoreos.prediction.pvforecastvrm.PVForecastVrmCommonSettings]` | `rw` | `None` | PVForecastVrm settings |
|
|
:::
|
|
<!-- pyml enable line-length -->
|
|
|
|
<!-- pyml disable no-emphasis-as-heading -->
|
|
**Example Input/Output**
|
|
<!-- pyml enable no-emphasis-as-heading -->
|
|
|
|
<!-- pyml disable line-length -->
|
|
```json
|
|
{
|
|
"pvforecast": {
|
|
"provider_settings": {
|
|
"PVForecastImport": null,
|
|
"PVForecastVrm": null,
|
|
"PVForecastPVNode": null,
|
|
"PVForecastForecastSolar": null,
|
|
"PVForecastSolcast": null,
|
|
"PVForecastAkkudoktorLocal": null
|
|
}
|
|
}
|
|
}
|
|
```
|
|
<!-- pyml enable line-length -->
|
|
|
|
### PV Forecast Plane Configuration
|
|
|
|
<!-- pyml disable line-length -->
|
|
:::{table} pvforecast::planes::list
|
|
:widths: 10 10 5 5 30
|
|
:align: left
|
|
|
|
| Name | Type | Read-Only | Default | Description |
|
|
| ---- | ---- | --------- | ------- | ----------- |
|
|
| albedo | `Optional[float]` | `rw` | `None` | Proportion of the light hitting the ground that it reflects back. |
|
|
| inverter_model | `Optional[str]` | `rw` | `None` | Model of the inverter of this plane. |
|
|
| inverter_paco | `Optional[int]` | `rw` | `None` | AC power rating of the inverter [W]. |
|
|
| loss | `Optional[float]` | `rw` | `14.0` | Sum of PV system losses in percent |
|
|
| module_model | `Optional[str]` | `rw` | `None` | Model of the PV modules of this plane. |
|
|
| modules_per_string | `Optional[int]` | `rw` | `None` | Number of the PV modules of the strings of this plane. |
|
|
| mountingplace | `Optional[str]` | `rw` | `free` | Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated. |
|
|
| optimal_surface_tilt | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt angle. Ignored for two-axis tracking. |
|
|
| optimalangles | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking. |
|
|
| peakpower | `Optional[float]` | `rw` | `None` | Nominal power of PV system in kW. |
|
|
| pvtechchoice | `Optional[str]` | `rw` | `crystSi` | PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'. |
|
|
| strings_per_inverter | `Optional[int]` | `rw` | `None` | Number of the strings of the inverter of this plane. |
|
|
| surface_azimuth | `Optional[float]` | `rw` | `180.0` | Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270). |
|
|
| surface_tilt | `Optional[float]` | `rw` | `30.0` | Tilt angle from horizontal plane. Ignored for two-axis tracking. |
|
|
| trackingtype | `Optional[int]` | `rw` | `None` | Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south. |
|
|
| userhorizon | `Optional[List[float]]` | `rw` | `None` | Elevation of horizon in degrees, at equally spaced azimuth clockwise from north. |
|
|
:::
|
|
<!-- pyml enable line-length -->
|
|
|
|
<!-- pyml disable no-emphasis-as-heading -->
|
|
**Example Input/Output**
|
|
<!-- pyml enable no-emphasis-as-heading -->
|
|
|
|
<!-- pyml disable line-length -->
|
|
```json
|
|
{
|
|
"pvforecast": {
|
|
"planes": [
|
|
{
|
|
"surface_tilt": 10.0,
|
|
"surface_azimuth": 180.0,
|
|
"userhorizon": [
|
|
10.0,
|
|
20.0,
|
|
30.0
|
|
],
|
|
"peakpower": 5.0,
|
|
"pvtechchoice": "crystSi",
|
|
"mountingplace": "free",
|
|
"loss": 14.0,
|
|
"trackingtype": 0,
|
|
"optimal_surface_tilt": false,
|
|
"optimalangles": false,
|
|
"albedo": null,
|
|
"module_model": null,
|
|
"inverter_model": null,
|
|
"inverter_paco": 6000,
|
|
"modules_per_string": 20,
|
|
"strings_per_inverter": 2
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
<!-- pyml enable line-length -->
|