def test_backtrack(): apparent_zenith = pd.Series([80]) apparent_azimuth = pd.Series([90]) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=90, backtrack=False, gcr=2.0/7.0) expect = pd.DataFrame({'aoi': 0, 'surface_azimuth': 90, 'surface_tilt': 80, 'tracker_theta': 80}, index=[0], dtype=np.float64) assert_frame_equal(expect, tracker_data) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=90, backtrack=True, gcr=2.0/7.0) expect = pd.DataFrame({'aoi': 52.5716, 'surface_azimuth': 90, 'surface_tilt': 27.42833, 'tracker_theta': 27.4283}, index=[0], dtype=np.float64) assert_frame_equal(expect, tracker_data)
def test_axis_tilt(): apparent_zenith = pd.Series([30]) apparent_azimuth = pd.Series([135]) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=30, axis_azimuth=180, max_angle=90, backtrack=True, gcr=2.0/7.0) expect = pd.DataFrame({'aoi': 7.286245, 'surface_azimuth': 142.65730, 'surface_tilt': 35.98741, 'tracker_theta': -20.88121}, index=[0], dtype=np.float64) expect = expect[SINGLEAXIS_COL_ORDER] assert_frame_equal(expect, tracker_data) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=30, axis_azimuth=0, max_angle=90, backtrack=True, gcr=2.0/7.0) expect = pd.DataFrame({'aoi': 47.6632, 'surface_azimuth': 50.96969, 'surface_tilt': 42.5152, 'tracker_theta': 31.6655}, index=[0], dtype=np.float64) expect = expect[SINGLEAXIS_COL_ORDER] assert_frame_equal(expect, tracker_data)
def test_backtrack(): apparent_zenith = pd.Series([80]) apparent_azimuth = pd.Series([90]) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=90, backtrack=False, gcr=2.0/7.0) expect = pd.DataFrame({'aoi': 0, 'surface_azimuth': 90, 'surface_tilt': 80, 'tracker_theta': 80}, index=[0], dtype=np.float64) expect = expect[SINGLEAXIS_COL_ORDER] assert_frame_equal(expect, tracker_data) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=90, backtrack=True, gcr=2.0/7.0) expect = pd.DataFrame({'aoi': 52.5716, 'surface_azimuth': 90, 'surface_tilt': 27.42833, 'tracker_theta': 27.4283}, index=[0], dtype=np.float64) expect = expect[SINGLEAXIS_COL_ORDER] assert_frame_equal(expect, tracker_data)
def test_azimuth_north_south(): apparent_zenith = pd.Series([60]) apparent_azimuth = pd.Series([90]) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=180, max_angle=90, backtrack=True, gcr=2.0 / 7.0) expect = pd.DataFrame( { 'aoi': 0, 'surface_azimuth': 90, 'surface_tilt': 60, 'tracker_theta': -60 }, index=[0], dtype=np.float64) assert_frame_equal(expect, tracker_data) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=90, backtrack=True, gcr=2.0 / 7.0) expect['tracker_theta'] *= -1 assert_frame_equal(expect, tracker_data)
def test_axis_tilt(): apparent_zenith = pd.Series([30]) apparent_azimuth = pd.Series([135]) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=30, axis_azimuth=180, max_angle=90, backtrack=True, gcr=2.0/7.0) expect = pd.DataFrame({'aoi': 7.286245, 'surface_azimuth': 142.65730, 'surface_tilt': 35.98741, 'tracker_theta': -20.88121}, index=[0], dtype=np.float64) expect = expect[SINGLEAXIS_COL_ORDER] assert_frame_equal(expect, tracker_data) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=30, axis_azimuth=0, max_angle=90, backtrack=True, gcr=2.0/7.0) expect = pd.DataFrame({'aoi': 47.6632, 'surface_azimuth': 50.96969, 'surface_tilt': 42.5152, 'tracker_theta': 31.6655}, index=[0], dtype=np.float64) expect = expect[SINGLEAXIS_COL_ORDER] assert_frame_equal(expect, tracker_data)
def test_axis_azimuth(): apparent_zenith = pd.Series([30]) apparent_azimuth = pd.Series([90]) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=90, max_angle=90, backtrack=True, gcr=2.0/7.0) expect = pd.DataFrame({'aoi': 30, 'surface_azimuth': 180, 'surface_tilt': 0, 'tracker_theta': 0}, index=[0], dtype=np.float64) expect = expect[SINGLEAXIS_COL_ORDER] assert_frame_equal(expect, tracker_data) apparent_zenith = pd.Series([30]) apparent_azimuth = pd.Series([180]) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=90, max_angle=90, backtrack=True, gcr=2.0/7.0) expect = pd.DataFrame({'aoi': 0, 'surface_azimuth': 180, 'surface_tilt': 30, 'tracker_theta': 30}, index=[0], dtype=np.float64) expect = expect[SINGLEAXIS_COL_ORDER] assert_frame_equal(expect, tracker_data)
def test_nans(): apparent_zenith = np.array([10, np.nan, 10]) apparent_azimuth = np.array([180, 180, np.nan]) with np.errstate(invalid='ignore'): tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=90, backtrack=True, gcr=2.0/7.0) expect = {'tracker_theta': np.array([0, nan, nan]), 'aoi': np.array([10, nan, nan]), 'surface_azimuth': np.array([90, nan, nan]), 'surface_tilt': np.array([0, nan, nan])} for k, v in expect.items(): assert_allclose(tracker_data[k], v) # repeat with Series because nans can differ apparent_zenith = pd.Series(apparent_zenith) apparent_azimuth = pd.Series(apparent_azimuth) with np.errstate(invalid='ignore'): tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=90, backtrack=True, gcr=2.0/7.0) expect = pd.DataFrame(np.array( [[ 0., 10., 90., 0.], [nan, nan, nan, nan], [nan, nan, nan, nan]]), columns=['tracker_theta', 'aoi', 'surface_azimuth', 'surface_tilt']) assert_frame_equal(tracker_data, expect)
def test_nans(): apparent_zenith = np.array([10, np.nan, 10]) apparent_azimuth = np.array([180, 180, np.nan]) with np.errstate(invalid='ignore'): tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=90, backtrack=True, gcr=2.0/7.0) expect = {'tracker_theta': np.array([0, nan, nan]), 'aoi': np.array([10, nan, nan]), 'surface_azimuth': np.array([90, nan, nan]), 'surface_tilt': np.array([0, nan, nan])} for k, v in expect.items(): assert_allclose(tracker_data[k], v, atol=1e-7) # repeat with Series because nans can differ apparent_zenith = pd.Series(apparent_zenith) apparent_azimuth = pd.Series(apparent_azimuth) with np.errstate(invalid='ignore'): tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=90, backtrack=True, gcr=2.0/7.0) expect = pd.DataFrame(np.array( [[ 0., 10., 90., 0.], [nan, nan, nan, nan], [nan, nan, nan, nan]]), columns=['tracker_theta', 'aoi', 'surface_azimuth', 'surface_tilt']) assert_frame_equal(tracker_data, expect)
def test_slope_aware_backtracking(): """ Test validation data set from https://www.nrel.gov/docs/fy20osti/76626.pdf """ index = pd.date_range('2019-01-01T08:00', '2019-01-01T17:00', freq='h') index = index.tz_localize('Etc/GMT+5') expected_data = pd.DataFrame(index=index, data=[ (2.404287, 122.79177, -84.440, -10.899), (11.263058, 133.288729, -72.604, -25.747), (18.733558, 145.285552, -59.861, -59.861), (24.109076, 158.939435, -45.578, -45.578), (26.810735, 173.931802, -28.764, -28.764), (26.482495, 189.371536, -8.475, -8.475), (23.170447, 204.13681, 15.120, 15.120), (17.296785, 217.446538, 39.562, 39.562), (9.461862, 229.102218, 61.587, 32.339), (0.524817, 239.330401, 79.530, 5.490), ], columns=[ 'ApparentElevation', 'SolarAzimuth', 'TrueTracking', 'Backtracking' ]) expected_axis_tilt = 9.666 expected_slope_angle = -2.576 slope_azimuth, slope_tilt = 180.0, 10.0 axis_azimuth = 195.0 axis_tilt = tracking.calc_axis_tilt(slope_azimuth, slope_tilt, axis_azimuth) assert np.isclose(axis_tilt, expected_axis_tilt, rtol=1e-3, atol=1e-3) cross_axis_tilt = tracking.calc_cross_axis_tilt(slope_azimuth, slope_tilt, axis_azimuth, axis_tilt) assert np.isclose(cross_axis_tilt, expected_slope_angle, rtol=1e-3, atol=1e-3) sat = tracking.singleaxis(90.0 - expected_data['ApparentElevation'], expected_data['SolarAzimuth'], axis_tilt, axis_azimuth, max_angle=90.0, backtrack=True, gcr=0.5, cross_axis_tilt=cross_axis_tilt) assert_series_equal(sat['tracker_theta'], expected_data['Backtracking'].rename('tracker_theta'), check_less_precise=True) truetracking = tracking.singleaxis(90.0 - expected_data['ApparentElevation'], expected_data['SolarAzimuth'], axis_tilt, axis_azimuth, max_angle=90.0, backtrack=False, gcr=0.5, cross_axis_tilt=cross_axis_tilt) assert_series_equal(truetracking['tracker_theta'], expected_data['TrueTracking'].rename('tracker_theta'), check_less_precise=True)
def test_arrays_multi(): apparent_zenith = np.array([[10, 10], [10, 10]]) apparent_azimuth = np.array([[180, 180], [180, 180]]) # singleaxis should fail for num dim > 1 with pytest.raises(ValueError): tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=90, backtrack=True, gcr=2.0/7.0)
def time_singleaxis(self): with np.errstate(invalid='ignore'): tracking.singleaxis(self.solar_position.apparent_zenith, self.solar_position.azimuth, axis_tilt=0, axis_azimuth=0, max_angle=60, backtrack=True, gcr=0.45)
def test_slope_aware_backtracking(): """ Test validation data set from https://www.nrel.gov/docs/fy20osti/76626.pdf """ expected_data = np.array( [('2019-01-01T08:00-0500', 2.404287, 122.79177, -84.440, -10.899), ('2019-01-01T09:00-0500', 11.263058, 133.288729, -72.604, -25.747), ('2019-01-01T10:00-0500', 18.733558, 145.285552, -59.861, -59.861), ('2019-01-01T11:00-0500', 24.109076, 158.939435, -45.578, -45.578), ('2019-01-01T12:00-0500', 26.810735, 173.931802, -28.764, -28.764), ('2019-01-01T13:00-0500', 26.482495, 189.371536, -8.475, -8.475), ('2019-01-01T14:00-0500', 23.170447, 204.13681, 15.120, 15.120), ('2019-01-01T15:00-0500', 17.296785, 217.446538, 39.562, 39.562), ('2019-01-01T16:00-0500', 9.461862, 229.102218, 61.587, 32.339), ('2019-01-01T17:00-0500', 0.524817, 239.330401, 79.530, 5.490)], dtype=[('Time', '<M8[h]'), ('ApparentElevation', '<f8'), ('SolarAzimuth', '<f8'), ('TrueTracking', '<f8'), ('Backtracking', '<f8')]) expected_axis_tilt = 9.666 expected_slope_angle = -2.576 slope_azimuth, slope_tilt = 180.0, 10.0 axis_azimuth = 195.0 axis_tilt = tracking.calc_axis_tilt(slope_azimuth, slope_tilt, axis_azimuth) assert np.isclose(axis_tilt, expected_axis_tilt, rtol=1e-3, atol=1e-3) cross_axis_tilt = tracking.calc_cross_axis_tilt(slope_azimuth, slope_tilt, axis_azimuth, axis_tilt) assert np.isclose(cross_axis_tilt, expected_slope_angle, rtol=1e-3, atol=1e-3) sat = tracking.singleaxis(90.0 - expected_data['ApparentElevation'], expected_data['SolarAzimuth'], axis_tilt, axis_azimuth, max_angle=90.0, backtrack=True, gcr=0.5, cross_axis_tilt=cross_axis_tilt) np.testing.assert_allclose(sat['tracker_theta'], expected_data['Backtracking'], rtol=1e-3, atol=1e-3) truetracking = tracking.singleaxis(90.0 - expected_data['ApparentElevation'], expected_data['SolarAzimuth'], axis_tilt, axis_azimuth, max_angle=90.0, backtrack=False, gcr=0.5, cross_axis_tilt=cross_axis_tilt) np.testing.assert_allclose(truetracking['tracker_theta'], expected_data['TrueTracking'], rtol=1e-3, atol=1e-3)
def test_index_mismatch(): apparent_zenith = pd.Series([30]) apparent_azimuth = pd.Series([90,180]) with pytest.raises(ValueError): tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=90, max_angle=90, backtrack=True, gcr=2.0/7.0)
def test_index_mismatch(): apparent_zenith = pd.Series([30]) apparent_azimuth = pd.Series([90,180]) with pytest.raises(ValueError): tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=90, max_angle=90, backtrack=True, gcr=2.0/7.0)
def test_arrays_multi(): apparent_zenith = np.array([[10, 10], [10, 10]]) apparent_azimuth = np.array([[180, 180], [180, 180]]) # singleaxis should fail for num dim > 1 with pytest.raises(ValueError): tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=90, backtrack=True, gcr=2.0/7.0)
def test_arrays(): apparent_zenith = np.array([10]) apparent_azimuth = np.array([180]) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=90, backtrack=True, gcr=2.0/7.0) assert isinstance(tracker_data, dict) expect = {'tracker_theta': 0, 'aoi': 10, 'surface_azimuth': 90, 'surface_tilt': 0} for k, v in expect.items(): assert_allclose(tracker_data[k], v)
def test_scalars(): apparent_zenith = 10 apparent_azimuth = 180 tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=90, backtrack=True, gcr=2.0/7.0) assert isinstance(tracker_data, dict) expect = {'tracker_theta': 0, 'aoi': 10, 'surface_azimuth': 90, 'surface_tilt': 0} for k, v in expect.items(): assert np.isclose(tracker_data[k], v)
def test_arrays(): apparent_zenith = np.array([10]) apparent_azimuth = np.array([180]) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=90, backtrack=True, gcr=2.0/7.0) assert isinstance(tracker_data, dict) expect = {'tracker_theta': 0, 'aoi': 10, 'surface_azimuth': 90, 'surface_tilt': 0} for k, v in expect.items(): assert_allclose(tracker_data[k], v, atol=1e-7)
def test_low_sun_angles(): # GH 656, 824 result = tracking.singleaxis( apparent_zenith=80, apparent_azimuth=338, axis_tilt=30, axis_azimuth=180, max_angle=60, backtrack=True, gcr=0.35) expected = { 'tracker_theta': np.array([60.0]), 'aoi': np.array([80.420987]), 'surface_azimuth': np.array([253.897886]), 'surface_tilt': np.array([64.341094])} for k, v in result.items(): assert_allclose(expected[k], v)
def test_max_angle(): apparent_zenith = pd.Series([60]) apparent_azimuth = pd.Series([90]) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=45, backtrack=True, gcr=2.0/7.0) expect = pd.DataFrame({'aoi': 15, 'surface_azimuth': 90, 'surface_tilt': 45, 'tracker_theta': 45}, index=[0], dtype=np.float64) assert_frame_equal(expect, tracker_data)
def test_horizon_tilted(): # GH 569 solar_azimuth = np.array([0, 180, 359]) solar_zenith = np.full_like(solar_azimuth, 45) solar_azimuth = pd.Series(solar_azimuth) solar_zenith = pd.Series(solar_zenith) out = tracking.singleaxis(solar_zenith, solar_azimuth, axis_tilt=90, axis_azimuth=180, backtrack=False, max_angle=180) expected = pd.DataFrame(np.array( [[ 180., 45., 0., 90.], [ 0., 45., 180., 90.], [ 179., 45., 359., 90.]]), columns=['tracker_theta', 'aoi', 'surface_azimuth', 'surface_tilt']) assert_frame_equal(out, expected)
def get_orientation(self, solar_zenith, solar_azimuth): # Different trackers update at different rates; in this example we'll # assume a relatively slow update interval of 15 minutes to make the # effect more visually apparent. zenith_subset = solar_zenith.resample('15min').first() azimuth_subset = solar_azimuth.resample('15min').first() tracking_data_15min = tracking.singleaxis( zenith_subset, azimuth_subset, self.axis_tilt, self.axis_azimuth, self.max_angle, self.backtrack, self.gcr, self.cross_axis_tilt) # propagate the 15-minute positions to 1-minute stair-stepped values: tracking_data_1min = tracking_data_15min.reindex(solar_zenith.index, method='ffill') return tracking_data_1min
def test_max_angle(): apparent_zenith = pd.Series([60]) apparent_azimuth = pd.Series([90]) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=45, backtrack=True, gcr=2.0/7.0) expect = pd.DataFrame({'aoi': 15, 'surface_azimuth': 90, 'surface_tilt': 45, 'tracker_theta': 45}, index=[0], dtype=np.float64) expect = expect[SINGLEAXIS_COL_ORDER] assert_frame_equal(expect, tracker_data)
def test_horizon_tilted(): # GH 569 solar_azimuth = np.array([0, 180, 359]) solar_zenith = np.full_like(solar_azimuth, 45) solar_azimuth = pd.Series(solar_azimuth) solar_zenith = pd.Series(solar_zenith) out = tracking.singleaxis(solar_zenith, solar_azimuth, axis_tilt=90, axis_azimuth=180, backtrack=False, max_angle=180) expected = pd.DataFrame(np.array( [[-180., 45., 0., 90.], [ 0., 45., 180., 90.], [ 179., 45., 359., 90.]]), columns=['tracker_theta', 'aoi', 'surface_azimuth', 'surface_tilt']) assert_frame_equal(out, expected)
def test_solar_noon(): index = pd.date_range(start='20180701T1200', freq='1s', periods=1) apparent_zenith = pd.Series([10], index=index) apparent_azimuth = pd.Series([180], index=index) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=90, backtrack=True, gcr=2.0/7.0) expect = pd.DataFrame({'tracker_theta': 0, 'aoi': 10, 'surface_azimuth': 90, 'surface_tilt': 0}, index=index, dtype=np.float64) expect = expect[SINGLEAXIS_COL_ORDER] assert_frame_equal(expect, tracker_data)
def test_solar_noon(): index = pd.date_range(start='20180701T1200', freq='1s', periods=1) apparent_zenith = pd.Series([10], index=index) apparent_azimuth = pd.Series([180], index=index) tracker_data = tracking.singleaxis(apparent_zenith, apparent_azimuth, axis_tilt=0, axis_azimuth=0, max_angle=90, backtrack=True, gcr=2.0/7.0) expect = pd.DataFrame({'tracker_theta': 0, 'aoi': 10, 'surface_azimuth': 90, 'surface_tilt': 0}, index=index, dtype=np.float64) expect = expect[SINGLEAXIS_COL_ORDER] assert_frame_equal(expect, tracker_data)
def test_horizon_flat(): # GH 569 solar_azimuth = np.array([0, 180, 359]) solar_zenith = np.array([100, 45, 100]) solar_azimuth = pd.Series(solar_azimuth) solar_zenith = pd.Series(solar_zenith) # depending on platform and numpy versions this will generate # RuntimeWarning: invalid value encountered in > < >= out = tracking.singleaxis(solar_zenith, solar_azimuth, axis_tilt=0, axis_azimuth=180, backtrack=False, max_angle=180) expected = pd.DataFrame(np.array( [[ nan, nan, nan, nan], [ 0., 45., 270., 0.], [ nan, nan, nan, nan]]), columns=['tracker_theta', 'aoi', 'surface_azimuth', 'surface_tilt']) assert_frame_equal(out, expected)
def test_horizon_flat(): # GH 569 solar_azimuth = np.array([0, 180, 359]) solar_zenith = np.array([100, 45, 100]) solar_azimuth = pd.Series(solar_azimuth) solar_zenith = pd.Series(solar_zenith) # depending on platform and numpy versions this will generate # RuntimeWarning: invalid value encountered in > < >= out = tracking.singleaxis(solar_zenith, solar_azimuth, axis_tilt=0, axis_azimuth=180, backtrack=False, max_angle=180) expected = pd.DataFrame(np.array( [[ nan, nan, nan, nan], [ 0., 45., 270., 0.], [ nan, nan, nan, nan]]), columns=['tracker_theta', 'aoi', 'surface_azimuth', 'surface_tilt']) assert_frame_equal(out, expected)
def test_low_sun_angles(): # GH 656 result = tracking.singleaxis(apparent_zenith=80, apparent_azimuth=338, axis_tilt=30, axis_azimuth=180, max_angle=60, backtrack=True, gcr=0.35) expected = { 'tracker_theta': np.array([-50.31051385]), 'aoi': np.array([61.35300178]), 'surface_azimuth': np.array([112.53615425]), 'surface_tilt': np.array([56.42233095]) } for k, v in result.items(): assert_allclose(expected[k], v)
def test_calc_axis_tilt(): # expected values expected_axis_tilt = 2.239 # [degrees] expected_side_slope = 9.86649274360294 # [degrees] expected = DATA_DIR / 'singleaxis_tracker_wslope.csv' expected = pd.read_csv(expected, index_col='timestamp', parse_dates=True) # solar positions starttime = '2017-01-01T00:30:00-0300' stoptime = '2017-12-31T23:59:59-0300' lat, lon = -27.597300, -48.549610 times = pd.DatetimeIndex(pd.date_range(starttime, stoptime, freq='H')) solpos = pvlib.solarposition.get_solarposition(times, lat, lon) # singleaxis tracker w/slope data slope_azimuth, slope_tilt = 77.34, 10.1149 axis_azimuth = 0.0 max_angle = 75.0 # Note: GCR is relative to horizontal distance between rows gcr = 0.33292759 # GCR = length / horizontal_pitch = 1.64 / 5 / cos(9.86) # calculate tracker axis zenith axis_tilt = tracking.calc_axis_tilt(slope_azimuth, slope_tilt, axis_azimuth=axis_azimuth) assert np.isclose(axis_tilt, expected_axis_tilt) # calculate cross-axis tilt and relative rotation cross_axis_tilt = tracking.calc_cross_axis_tilt(slope_azimuth, slope_tilt, axis_azimuth, axis_tilt) assert np.isclose(cross_axis_tilt, expected_side_slope) sat = tracking.singleaxis(solpos.apparent_zenith, solpos.azimuth, axis_tilt, axis_azimuth, max_angle, backtrack=True, gcr=gcr, cross_axis_tilt=cross_axis_tilt) np.testing.assert_allclose(sat['tracker_theta'], expected['tracker_theta'], atol=1e-7) np.testing.assert_allclose(sat['aoi'], expected['aoi'], atol=1e-7) np.testing.assert_allclose(sat['surface_azimuth'], expected['surface_azimuth'], atol=1e-7) np.testing.assert_allclose(sat['surface_tilt'], expected['surface_tilt'], atol=1e-7)
import matplotlib.pyplot as plt tz = 'US/Eastern' lat, lon = 40, -80 times = pd.date_range('2019-01-01', '2019-01-02', closed='left', freq='5min', tz=tz) solpos = solarposition.get_solarposition(times, lat, lon) truetracking_angles = tracking.singleaxis( apparent_zenith=solpos['apparent_zenith'], apparent_azimuth=solpos['azimuth'], axis_tilt=0, axis_azimuth=180, max_angle=90, backtrack=False, # for true-tracking gcr=0.5) # irrelevant for true-tracking truetracking_position = truetracking_angles['tracker_theta'].fillna(0) truetracking_position.plot(title='Truetracking Curve') plt.show() #%% # Backtracking # ------------- # # Because truetracking yields steep tilt angle in morning and afternoon, it # will cause row to row shading as the shadows from adjacent rows fall on each
df_monthly = pd.DataFrame() # fixed-tilt: for tilt in range(0, 50, 10): # we will hardcode azimuth=180 (south) for all fixed-tilt cases poa_irradiance = calculate_poa(tmy, solar_position, tilt, 180) column_name = "FT-{}".format(tilt) # TMYs are hourly, so we can just sum up irradiance [W/m^2] to get # insolation [Wh/m^2]: df_monthly[column_name] = poa_irradiance.resample('m').sum() # single-axis tracking: orientation = tracking.singleaxis( solar_position['apparent_zenith'], solar_position['azimuth'], axis_tilt=0, # flat array axis_azimuth=180, # south-facing azimuth max_angle=60, # a common maximum rotation backtrack=True, # backtrack for a c-Si array gcr=0.4) # a common ground coverage ratio poa_irradiance = calculate_poa(tmy, solar_position, orientation['surface_tilt'], orientation['surface_azimuth']) df_monthly['SAT-0.4'] = poa_irradiance.resample('m').sum() # calculate the percent difference from GHI ghi_monthly = tmy['GHI'].resample('m').sum() df_monthly = 100 * (df_monthly.divide(ghi_monthly, axis=0) - 1) df_monthly.plot() plt.xlabel('Month of Year')
def smarts_spectrum_with_single_axis_tracker(time_range, cache_1='cache1.h5', cache_2='cache2.h5', force_restart=False, norm_2pass=True): """ Generate spectrum with single axis tracker :param time_range: a datetime-like array :param cache_1: :param cache_2: :param force_restart: :param norm_2pass: :return: """ if force_restart == False and os.path.exists(cache_2) == True: print("Load data from cache.") df = pd.read_hdf(cache_2, key='spec_df') out_df = pd.read_hdf(cache_2, key='param_df') return df, out_df # Run the first pass to calculate the solar position df, out_df = get_clear_sky(time_range, extend_dict={'TILT': -999}) df.to_hdf(cache_1, key='spec_df', mode='a') out_df.to_hdf(cache_1, key='param_df', mode='a') tracker_angle = singleaxis(apparent_azimuth=out_df['azimuth'], apparent_zenith=out_df['zenith'], backtrack=False) # Add tracker angle into the parameter datatframe out_df = pd.concat([out_df, tracker_angle], axis=1) # Rename the tracker azimuth and tilt in order to feed them into 2nd pass SMARTS out_df = out_df.rename(index=str, columns={ "surface_azimuth": "WAZIM", "surface_tilt": "TILT" }) # Do the second pass to calculate the output spectrum by using single axis tracker df, n_out_df = get_clear_sky(time_range, extend_df=out_df[['TILT', 'WAZIM']]) # Renormalize the direct normal incidence if norm_2pass == True: n_out_df['direct_norm_factor'] = n_out_df['direct_tilt'] / n_out_df[ 'direct_normal'] df = pd.merge(left=df, right=n_out_df, left_index=True, right_index=True) df['BEAM_NORMAL'] = df['BEAM_NORMAL'] * df['direct_norm_factor'] df.to_hdf(cache_2, key='spec_df', mode='a') n_out_df.to_hdf(cache_2, key='param_df', mode='a') return df, n_out_df
lat, lon = 40, -80 gcr = 0.4 # calculate the solar position times = pd.date_range('2019-01-01 06:00', '2019-01-01 18:00', closed='left', freq='1min', tz=tz) solpos = solarposition.get_solarposition(times, lat, lon) # compare the backtracking angle at various terrain slopes fig, ax = plt.subplots() for cross_axis_tilt in [0, 5, 10]: tracker_data = tracking.singleaxis( apparent_zenith=solpos['apparent_zenith'], apparent_azimuth=solpos['azimuth'], axis_tilt=0, # flat because the axis is perpendicular to the slope axis_azimuth=180, # N-S axis, azimuth facing south max_angle=90, backtrack=True, gcr=gcr, cross_axis_tilt=cross_axis_tilt) # tracker rotation is undefined at night backtracking_position = tracker_data['tracker_theta'].fillna(0) label = 'cross-axis tilt: {}°'.format(cross_axis_tilt) backtracking_position.plot(label=label, ax=ax) plt.legend() plt.title('Backtracking Curves') plt.show() # %%
def find_clearsky_poa(df, lat, lon, irradiance_poa_key='irradiance_poa_o_###', mounting='fixed', tilt=0, azimuth=180, altitude=0): loc = Location(lat, lon, altitude=altitude) CS = loc.get_clearsky(df.index) df['csghi'] = CS.ghi df['csdhi'] = CS.dhi df['csdni'] = CS.dni if mounting.lower() == "fixed": sun = get_solarposition(df.index, lat, lon) fixedpoa = get_total_irradiance(tilt, azimuth, sun.zenith, sun.azimuth, CS.dni, CS.ghi, CS.dhi) df['cspoa'] = fixedpoa.poa_global if mounting.lower() == "tracking": sun = get_solarposition(df.index, lat, lon) # default to axis_tilt=0 and axis_azimuth=180 tracker_data = singleaxis(sun.apparent_zenith, sun.azimuth, axis_tilt=tilt, axis_azimuth=azimuth, max_angle=50, backtrack=True, gcr=0.35) track = get_total_irradiance(tracker_data['surface_tilt'], tracker_data['surface_azimuth'], sun.zenith, sun.azimuth, CS.dni, CS.ghi, CS.dhi) df['cspoa'] = track.poa_global # the following code is assuming clear sky poa has been generated per pvlib, aligned in the same # datetime index, and daylight savings or any time shifts were previously corrected # the inputs below were tuned for POA at a 15 minute frequency # note that detect_clearsky has a scaling factor but I still got slightly different results when I scaled measured poa first df['poa'] = df[irradiance_poa_key] / df[irradiance_poa_key].quantile( 0.98) * df.cspoa.quantile(0.98) # inputs for detect_clearsky measured = df.poa.copy() clear = df.cspoa.copy() dur = 60 lower_line_length = -41.416 upper_line_length = 77.789 var_diff = .00745 mean_diff = 80 max_diff = 90 slope_dev = 3 is_clear_results = detect_clearsky(measured.values, clear.values, df.index, dur, mean_diff, max_diff, lower_line_length, upper_line_length, var_diff, slope_dev, return_components=True) clearSeries = pd.Series(index=df.index, data=is_clear_results[0]) clearSeries = clearSeries.reindex(index=df.index, method='ffill', limit=3) return clearSeries
times = pd.date_range('2021-06-21', '2021-06-22', freq='1T', tz=tz) # create location object and get clearsky data site_location = location.Location(lat, lon, tz=tz, name='Greensboro, NC') cs = site_location.get_clearsky(times) # get solar position data solar_position = site_location.get_solarposition(times) # set ground coverage ratio and max_angle to # pull orientation data for a single-axis tracker gcr = 0.35 max_phi = 60 orientation = tracking.singleaxis(solar_position['apparent_zenith'], solar_position['azimuth'], max_angle=max_phi, backtrack=True, gcr=gcr) # set axis_azimuth, albedo, pvrow width and height, and use # the pvfactors engine for both front and rear-side absorbed irradiance axis_azimuth = 180 pvrow_height = 3 pvrow_width = 4 albedo = 0.2 # explicity simulate on pvarray with 3 rows, with sensor placed in middle row # users may select different values depending on needs irrad = pvfactors_timeseries(solar_position['azimuth'], solar_position['apparent_zenith'], orientation['surface_azimuth'],
# Compute the diffuse irradiance on the panel, from the sky: S_d_sky = irradiance.klucher(surface_tilt, surface_azimuth, I_d_hor, I_hor, ephem_data['zenith'], ephem_data['azimuth']) # Compute the angles between the panel and the sun: aoi = irradiance.aoi(surface_tilt, surface_azimuth, ephem_data['zenith'], ephem_data['azimuth']) # Compute the global irradiance on the panel: S = irradiance.globalinplane(aoi, DNI, S_d_sky, S_d_reflect) # Second case: with tracking (axis is supposed to be north-south): S_track = tracking.singleaxis(ephem_data['apparent_zenith'], ephem_data['azimuth'], axis_tilt=0, axis_azimuth=0, max_angle=360, backtrack=True) S['Direct with tracking'] = DNI * np.cos(np.radians(S_track.aoi)) S = S.fillna(0) S.plot() #S.to_excel('data/incidentPV.xlsx') # Adding temperature to the dataframe: S['T'] = T # print S with w 15min time resolution: index15 = pd.DatetimeIndex(start='2015-01-01 00:00', end='2015-12-31 23:59:00',
sp_df = pd.DataFrame() for sl in siteLat: sp_df = sp.get_solarposition(time = dateTimeSpanUTC, latitude = sl, longitude = siteLong, altitude = siteElev, temperature = aveTemp) # convert the solar position data index back to local timestamp sp_df.index = dateTimeSpan solPos.append(sp_df) # create dataframes for tracking angle using pvlib trackAngl = [] tr_df = pd.DataFrame() for s in solPos: tr_df = trk.singleaxis(s['apparent_zenith'], s['azimuth'], axis_tilt = 0, axis_azimuth = 0, max_angle = rom, backtrack = True, gcr = gcRatio) tr_df['tracker_theta'] = -1.0 * tr_df['tracker_theta'] trackAngl.append(tr_df) trdiff_ls = [] durmx_ls = [] colnames = ['btmdur', 'lmdur', 'trdur', 'ladur', 'btadur', 'mxdifftime', 'mxdiffdur'] si = 0 for tr in trackAngl: # remove NA's from trackAngl tr.dropna(inplace = True) # trdiff is the delta between data points