Расчет пути Солнца

Я пишу несколько методов, необходимых для вычисления пути Солнца по определенной точке. Я написал код, используя два разных источника для своих вычислений, и ни один из них не дает желаемого результата. Источниками являются: http://www.pveducation.org/pvcdrom/properties-of-sunlight/suns-position и http://www.esrl.noaa.gov/gmd/grad/solcalc/solareqns.PDF

Примечание: Степени для arcminutes - Deg * 60 мин.

  • localSolartime: я преобразовал долготу в "минуты", локальный стандартный меридиан времени (lstm), полученный из метода localStandardTimeMeridian, возвращает значение, равное "минутам", и значение уравнения OfTime, которое также возвращается в ' минут. Используя уравнение от pveducation, я вычислил временную коррекцию, которая учитывает небольшие вариации времени в пределах данного часового пояса. Когда я применяю этот результат и localTime, каждый в минутах, к локальному солнечному времени (1-го) уравнения, результат составляет 676,515 (на данный момент), что для меня не имеет никакого смысла. Местное солнечное время, как я понимаю, представляет собой время по отношению к Солнцу и когда оно находится на самой высокой точке в небе, локально считается солнечным полдень. 676.515 не имеет смысла. Кто-нибудь понимает, что может быть причиной этого.

  • HourAngle: Я надеюсь, что как только я исправлю метод localSolarTime, это не нужно исправлять.

Я выбрал Вашингтон для широты и долготы. Как показания Зенита, так и азимута должны быть положительными, а для моего региона на данный момент - 66 и 201 соответственно.

public class PathOfSun {
static LocalTime localTime = LocalTime.now();
static double dcLat = 38.83;
static double dcLong =  -77.02;
static DecimalFormat df = new DecimalFormat("#.0");

public static void main(String [] args) {
    int day = dayOfYear();
    double equationOfTime = equationOfTime(day);
    double lstm = localTimeMeridian();
    double lst = localSolarTime(equationOfTime, dcLong, lstm);
    double declination = declination(day);
    double hourAngle = hourAngle(lst);

    double zenith = zenith(dcLat, declination, hourAngle);
    double azimuth = azimuth(dcLong, declination, zenith, hourAngle); 

}

//Longitude of timezone meridian
public static double localTimeMeridian() {
    TimeZone gmt = TimeZone.getTimeZone("GMT");
    TimeZone est = TimeZone.getTimeZone("EST");
    int td = gmt.getRawOffset() - est.getRawOffset();
    double localStandardTimeMeridian = 15 * (td/(1000*60*60)); //convert td to hours
    //System.out.println("Local Time Meridian: " + localStandardTimeMeridian);
    return localStandardTimeMeridian;
}

//Get the number of days since Jan. 1
public static int dayOfYear() {
    Calendar localCalendar = Calendar.getInstance(TimeZone.getDefault());
    int dayOfYear = localCalendar.get(Calendar.DAY_OF_YEAR); 
    //System.out.println("Day: " + dayOfYear);
    return dayOfYear;
}

//Emperical equation to correct the eccentricity of Earth orbit and axial tilt
public static double equationOfTime (double day) {
    double d =(360.0/365.0)*(day - 81);
    d = Math.toRadians(d);
    double equationTime = 9.87*sin(2*d)-7.53*cos(d)-1.54*sin(d); 
    //System.out.println("Equation Of Time: " + equationTime);
    return equationTime;
}
//The angle between the equator and a line drawn from the center of the Sun(degrees)
public static double declination(int dayOfYear) {
    double declination = 23.5*sin((Math.toRadians(360.0/365.0))*(dayOfYear - 81));
    //System.out.println("Declination: " + df.format(declination));
    return declination;
}

//Add the number of minutes past midnight localtime//
public static double hourAngle(double localSolarTime) {
    double hourAngle = 15 * (localSolarTime - 13); 
    System.out.println("Hour Angle: " + df.format(hourAngle)); //(degrees)
    return hourAngle;
}

//Account for the variation within timezone - increases accuracy
public static double localSolarTime(double equationOfTime, double longitude, double lstm) { 
    //LocalSolarTime = 4min * (longitude + localStandardTimeMeridian) + equationOfTime
    //Time Correction is time variation within given time zone (minutes)
    //longitude = longitude/60; //convert degrees to arcminutes
    double localStandardTimeMeridian = lstm;
    double timeCorrection = (4 * (longitude + localStandardTimeMeridian) + equationOfTime);
    System.out.println("Time Correction: " + timeCorrection); //(in minutes)
    //localSolarTime represents solar time where noon represents sun is highest position 
    // in sky and the hour angle is 0 -- hour angle is negative in morning, and positive after solar noon.
    double localSolarTime = (localTime.toSecondOfDay() + (timeCorrection*60)); //(seconds)
    localSolarTime = localSolarTime/(60*60);  //convert from seconds to hours
    //Convert double to Time (HH:mm:ss) for console output
    int hours = (int) Math.floor(localSolarTime);
    int minutes = (int) ((localSolarTime - hours) * 60);
    //-1 for the daylight savings
    Time solarTime = new Time((hours-1), minutes, 0);
    System.out.println("Local Solar Time: " + solarTime); //hours

    return localSolarTime;
}

public static double azimuth(double lat, double declination, double zenith, double hourAngle) {
    double azimuthDegree = 0;
    double elevation = 90 - zenith;
    elevation = Math.toRadians(elevation);
    zenith = Math.toRadians(zenith);
    lat = Math.toRadians(lat);
    declination = Math.toRadians(declination);
    hourAngle = Math.round(hourAngle);
    hourAngle = Math.toRadians(hourAngle);

    //double azimuthRadian = -sin(hourAngle)*cos(declination) / cos(elevation);
    double azimuthRadian = ((sin(declination)*cos(lat)) - (cos(hourAngle)*cos(declination)*
            sin(lat)))/cos(elevation);

    //Account for time quadrants
    Calendar cal = Calendar.getInstance();
    int hour = cal.get(Calendar.HOUR_OF_DAY);
    if(hour > 0 && hour < 6) {
    azimuthDegree =  Math.toDegrees(acos(azimuthRadian));
    }
    else if(hour >= 6 && hour < 12) {
        azimuthDegree = Math.toDegrees(acos(azimuthRadian));
        azimuthDegree = 180 - azimuthDegree;
    } else if (hour >= 12 && hour < 18) {
        azimuthDegree = Math.toDegrees(acos(azimuthRadian));
        azimuthDegree = azimuthDegree - 180;
    } else if (hour >= 18 && hour < 24) {
        azimuthDegree = Math.toDegrees(acos(azimuthRadian));
        azimuthDegree = 360 - azimuthDegree;
    }

    System.out.println("Azimuth: " + df.format(azimuthDegree));
    return azimuthDegree;
}

public static double zenith(double lat, double declination, double hourAngle) {
    lat = Math.toRadians(lat);
    declination = Math.toRadians(declination);
    hourAngle = Math.round(hourAngle);
    hourAngle = Math.toRadians(hourAngle);
    //Solar Zenith Angle 
    double zenith = Math.toDegrees(acos(sin(lat)*sin(declination) + (cos(lat)*cos(declination)*cos(hourAngle))));
    //Solar Elevation Angle
    double elevation = Math.toDegrees(asin(sin(lat)*sin(declination) + (cos(lat)*cos(declination)*cos(hourAngle))));
    System.out.println("Elevation: " + df.format(elevation));
    System.out.println("Zenith: " + df.format(zenith));
    return zenith;
}

}

Чтобы повторить, день, локальный меридиан времени точно верен, а уравнение времени и склонения точны, но не точны. ---- UPDATE OUTPUT ---- new output

sensor program

----- UPDATE ----- Использовал диаграмму рассеяния для отображения высоты/азимута солнца в течение дня. У меня все еще возникают проблемы с выводом азимута. Это правильно в течение длительного времени, но тогда оно изменится с увеличения и начнет уменьшаться (~ 270 → 0). Я обязательно обновлю код, как только я получу правильный результат.

Ответ 1

Вы передаете долготу в localSolarTime() как градусы, а затем разделите ее на 60, с комментарием, утверждающим, что это необходимо для преобразования в минуты дуги. Это не верно; ваши более поздние вычисления требуют степени, и даже если вам нужны минуты дуги, вы умножаетесь на 60, а не разделяете.

Это ошибочное деление приводит к долготе -1,3 & deg;, и когда вы находите угол между вашим местным меридианом времени и вашим положением, вы получаете большой угол (около 75 & deg;). Это должен быть небольшой угол, обычно & plusmn; 7.5 & deg;. Большой угол приводит к большой коррекции времени и отбрасывает все.


Обновление. В обновленной версии метода azimuth() выбор квадранта должен основываться на часовом угле солнца или, что то же самое, на местном солнечном времени, а не на стандартном времени настенных часов. И часовой угол, используемый во всех расчетах, не должен округляться. Вместо того, чтобы тестировать четыре разных квадранта, метод может выглядеть следующим образом:

public static double azimuth(double lat, double declination, double zenith, double hourAngle)
{
  double elevation = Math.toRadians(90 - zenith);
  lat = Math.toRadians(lat);
  declination = Math.toRadians(declination);
  hourAngle = Math.toRadians(hourAngle);
  double azimuthRadian = acos(((sin(declination) * cos(lat)) - (cos(hourAngle) * cos(declination) * sin(lat))) / cos(elevation));
  double azimuthDegree = Math.toDegrees(azimuthRadian);
  if (hourAngle > 0)
    azimuthDegree = 360 - azimuthDegree;
  System.out.println("Azimuth: " + df.format(azimuthDegree));
  return azimuthDegree;
}

Наконец, вы передаете dcLong в качестве параметра lat метода azimuth(); это должно быть dcLat.

Я бы рекомендовал использовать радиан внутри внутри и только конвертировать из и в градусы на входе и выходе. Это поможет предотвратить ошибки и сократить ошибки округления и ненужный беспорядок.