#[allow(clippy::too_many_arguments)]
pub fn singleaxis(
solar_zenith: f64,
solar_azimuth: f64,
axis_tilt: f64,
axis_azimuth: f64,
max_angle: f64,
backtrack: bool,
gcr: f64,
cross_axis_tilt: f64,
) -> (f64, f64, f64) {
use crate::shading::projected_solar_zenith_angle;
use crate::irradiance::aoi as irr_aoi;
if solar_zenith >= 90.0 {
return (f64::NAN, f64::NAN, f64::NAN);
}
let mut tracker_theta = projected_solar_zenith_angle(
solar_zenith,
solar_azimuth,
axis_tilt,
axis_azimuth,
);
if backtrack && gcr > 0.0 {
let axes_distance = 1.0 / (gcr * cross_axis_tilt.to_radians().cos());
let temp = (axes_distance * (tracker_theta - cross_axis_tilt).to_radians().cos()).abs();
if temp < 1.0 {
let omega_correction = -tracker_theta.signum() * temp.acos().to_degrees();
tracker_theta += omega_correction;
}
}
tracker_theta = tracker_theta.clamp(-max_angle, max_angle);
let (surface_tilt, surface_azimuth) =
calc_surface_orientation(tracker_theta, axis_tilt, axis_azimuth);
let aoi = irr_aoi(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth);
(surface_tilt, surface_azimuth, aoi)
}
pub fn calc_axis_tilt(slope_azimuth: f64, slope_tilt: f64, axis_azimuth: f64) -> f64 {
let sa_rad = slope_azimuth.to_radians();
let st_rad = slope_tilt.to_radians();
let aa_rad = axis_azimuth.to_radians();
let axis_tilt_rad = (st_rad.tan() * (aa_rad - sa_rad).cos()).atan();
axis_tilt_rad.to_degrees()
}
pub fn calc_surface_orientation(tracker_theta: f64, axis_tilt: f64, axis_azimuth: f64) -> (f64, f64) {
let tt_rad = tracker_theta.to_radians();
let at_rad = axis_tilt.to_radians();
let surface_tilt_rad = (tt_rad.cos() * at_rad.cos()).clamp(-1.0, 1.0).acos();
let surface_tilt = surface_tilt_rad.to_degrees();
let sin_st = surface_tilt_rad.sin();
let azimuth_delta = if sin_st.abs() < 1e-10 {
90.0
} else {
let raw = (tt_rad.sin() / sin_st).clamp(-1.0, 1.0).asin().to_degrees();
if tracker_theta.abs() < 90.0 {
raw
} else {
-raw + tracker_theta.signum() * 180.0
}
};
let surface_azimuth = (axis_azimuth + azimuth_delta).rem_euclid(360.0);
(surface_tilt, surface_azimuth)
}
pub fn calc_cross_axis_tilt(slope_azimuth: f64, slope_tilt: f64, axis_azimuth: f64, axis_tilt: f64) -> f64 {
let sa_rad = slope_azimuth.to_radians();
let st_rad = slope_tilt.to_radians();
let aa_rad = axis_azimuth.to_radians();
let at_rad = axis_tilt.to_radians();
let cross_axis_tilt_rad = (st_rad.tan() * (aa_rad - sa_rad).sin() * at_rad.cos()).atan();
cross_axis_tilt_rad.to_degrees()
}