bifacialvf icon indicating copy to clipboard operation
bifacialvf copied to clipboard

Unpredictable "swapping" of sensor readings for SAT in afternoon

Open kandersolar opened this issue 7 months ago • 1 comments

The logic to flip around sensors in the afternoon relies on surface azimuth values being exactly 270.0:

https://github.com/NREL/bifacialvf/blob/107a7775cc263bfd641b369c01ad0dbd61a409f0/bifacialvf/bifacialvf.py#L551-L555

sazm does equal 270.0 sometimes, but other times it has values like 269.999984. That results in the sensors not being swapped and strange oscillations showing up in the simulated afternoon irradiance:

Image

Zooming in, it's clear that the east and west sensors are swapping back and forth:

Image

The problem is resolved by introducing a tolerance into that check, e.g. abs(sazm - 270.0) < 1e-3 instead of sazm == 270.0.

Code to reproduce the above plot:

# pvlib.__version__: '0.12.0'
# bifacialvf.__version__: '0.1.9'

import bifacialvf
import pandas as pd
import numpy as np
import pvlib

import os

# IO Files
testfolder = r"C:\Users\ksande\TEMP\bifacialvf"
if not os.path.exists(testfolder):
    os.makedirs(testfolder)

meta = {'latitude': 40, 'longitude': -80, 'TZ': -5.0, 'Name': 'test location'}
times = pd.date_range("2020-06-01", "2020-06-01 23:59", freq="1min", tz="Etc/GMT+5")

location = pvlib.location.Location(meta['latitude'], meta['longitude'])
sp = location.get_solarposition(times)
cs = location.get_clearsky(times, solar_position=sp)

df = pd.DataFrame({
    'DNI': cs['dni'],
    'DHI': cs['dhi'],
    'zenith': np.radians(sp['zenith']),
    'elevation': np.radians(sp['elevation']),
    'azimuth': np.radians(sp['azimuth']),
}, index=times)

writefiletitle = os.path.join(testfolder, 'testresults.csv')

bifacialvf.simulate(df, meta, writefiletitle=writefiletitle, 
         sazm=180, pitch=1/0.4, hub_height=1.5, 
         rowType="interior", transFactor=0, sensorsy=10, 
         PVfrontSurface="glass", PVbackSurface="glass", 
         albedo=0.2, tracking=True, backtrack=True, 
         limit_angle=60)

(data, metadata) = bifacialvf.loadVFresults(writefiletitle)
data.set_index(pd.to_datetime(data['date']), inplace=True, drop=True)

cols = ['No_1_RowBackGTI', 'No_10_RowBackGTI']
data[cols].plot()

kandersolar avatar Jun 10 '25 15:06 kandersolar

Can I make two suggestions?

  1. Instead of checking if the azimuth is either 270° or not (assumed equivalent to 90° condition) I recommend checking the sign of np.sin(sazm) which will be negative for all sine values pointing west and positive for east. This also partially addresses the TODO comment in the code, but not entirely. Therefore, 269, 270, and 261 are all negative, which should solve the problem I believe.

  2. Minor nit. I prefer to use ‘np.isclose()` vs rolling my own tolerance checker, which perhaps is a moot point if you like my first suggestion.

mikofski avatar Jun 11 '25 02:06 mikofski