2015-05-04 15 views
10

Sto scrivendo diversi metodi necessari per calcolare il percorso del Sole attraverso un punto specifico. Ho scritto il codice usando due fonti diverse per i miei calcoli e nessuno dei due sta producendo il risultato desiderato. Le fonti sono: http://www.pveducation.org/pvcdrom/properties-of-sunlight/suns-position e http://www.esrl.noaa.gov/gmd/grad/solcalc/solareqns.PDFCalcoli del percorso del Sole

Nota: la Degrees to arcminutes è Deg * 60 min.

  1. localSolartime: Ho convertito la longitudine a 'minuti', l'ora meridiana locale standard (LSTM) derivato dal metodo localStandardTimeMeridian restituisce un valore che è in 'minuti', e l'equationOfTime che è anche restituito in 'minuti'. Usando l'equazione dalla pveducazione, ho calcolato la correzione temporale che tiene conto delle piccole variazioni temporali all'interno di un dato fuso orario. Quando applico questo risultato e il tempo locale, ciascuno in minuti, all'equazione solare locale (lst), il risultato è 676.515 (in questo momento), che per me non ha alcun senso. L'ora solare locale, a quanto ho capito, rappresenta il tempo rispetto al Sole e quando si trova nel punto più alto del cielo, localmente, è considerato mezzogiorno solare. 676.515 non ha senso. Qualcuno capisce cosa potrebbe causare questo.

  2. HourAngle: Spero che una volta risolto il metodo localSolarTime, non sarà necessario correggerlo.

Ho scelto Washington DC per latitudine e longitudine. Sia le letture Zenit e Azimuth dovrebbero essere valori positivi, e per la mia regione in questo momento, sono rispettivamente 66 e 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's 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's 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; 
} 

}

solo ribadire, il giorno, l'ora locale meridiano sono esattamente corretto, e l'equazione del tempo e declinazione sono accurate, ma non è esatto. ---- ---- UPDATE USCITA new output

sensor program

----- ----- AGGIORNAMENTO Utilizzato lo scatterchart per visualizzare il sole elevazione/azimuth per tutto il giorno. Sto ancora avendo problemi a capire l'output di azimuth. È corretto per molto tempo, ma poi cambierà da crescente e inizierà a diminuire (~ 270 -> 0). Sarò sicuro di aggiornare il codice una volta che finalmente avrò l'output giusto.

+1

Difficile capire quale sia l'esatto problema dovuto alla dicitura. Dici che dovrebbe produrre minuti e poi dare i risultati in pochi minuti; perché?? Tu dici che i due dovrebbero essere positivi e quindi dare risultati positivi; perché?? Hai effettuato il debug di questo per mettere in relazione gli input e gli output? – ChiefTwoPencils

+0

Le funzioni zenith() e azimuth() non riflettono le formule fornite nelle citazioni fornite. Hai provato a semplificarli? – BadZen

+0

Inoltre, si prega di notare che si dovranno modare i risultati [0,2 * Pi] per ottenere un angolo "normalizzato" (non negativo). – BadZen

risposta

3

Si passa la longitudine a localSolarTime() come gradi e quindi lo si divide per 60, con un commento che afferma che è necessario convertirlo in minuti di arco. Questo è sbagliato; i tuoi calcoli successivi richiedono gradi, e anche se avessi bisogno di minuti di arco, moltiplichi per 60, non dividi.

Questa divisione errata comporta una longitudine di -1,3 ° e, quando si individua l'angolo tra il meridiano dell'ora locale e la posizione, si ottiene un angolo ampio (circa 75 °). Dovrebbe essere un piccolo angolo, generalmente & plusmn; 7.5 °. L'ampio angolo comporta una correzione di grandi dimensioni e getta via tutto.


Aggiornamento: Nella versione aggiornata del metodo azimuth(), la selezione quadrante dovrebbe essere basata sulla angolo orario del sole, o, equivalentemente, in tempo solare locale, piuttosto che il tempo orologio da parete standard.Inoltre, l'angolo dell'ora utilizzato in tutti i calcoli non deve essere arrotondato. Invece di testare quattro quadranti diversi, il metodo potrebbe essere la seguente:

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; 
} 

Infine, si passa dcLong come parametro lat del metodo azimuth(); questo dovrebbe essere dcLat.

Si consiglia di utilizzare internamente i radianti e di convertire solo da e verso gradi su input e output. Ciò aiuterà a prevenire gli errori e ridurrà gli errori di arrotondamento e il disordine non necessario.

+0

Grazie erickson per averlo indicato. Regolerò il codice e spero che produrrà qualcosa di un po 'più piacevole! – wellington

+0

Ho risolto il problema e ora i metodi funzionano correttamente, tranne il calcolo finale: l'angolo dell'azimut non è corretto. Al mattino, l'intervallo dell'angolo di azimut è 0-180 (da 0-12) e 180-360 nel pomeriggio (12-24 ore). Detto questo, ho bisogno di regolare il valore all'interno di acos() per considerare il cambio di segno per ogni quadrante del cerchio unitario. Ho provato a utilizzare due equazioni diverse, entrambe da http://en.wikipedia.org/wiki/Solar_azimuth_angle, ma l'output delle seconde equazioni produce un '?'. La prima equazione è abbastanza vicina ma è circa 10 gradi diversa dal reale. – wellington

+0

@wellington Se hai bisogno di ulteriore aiuto, aggiungi un aggiornamento al tuo post con il tuo attuale metodo azimuth e esempi di input e risultati attesi. – erickson

Problemi correlati