제가 천문에 관련된 프로그래밍을 조금 할줄 알다보니 태양의 위치 및 일출/일몰에 대한 문의가 자주 들어옵니다. 개인적인 소스는 있지만 높은 정확도를 위한 것이라 일반인들이 이해하기에는 수준이 높습니다.
출처 : http://very-bored.com/index.php?option=com_content&task=view&id=135&Itemid=29
대부분 문의유형을 살펴보면 태양전지판을 효율적으로 사용하기 위해 태양의 방향에 따라 입사각이 90도가 이뤄지도록 구동하는 장치를 개발을 해야한다던가 수족관의 전등을 일출/일몰 시간에 맞게 자동으로 On/Off시켜줘야 한다는 뭐 아주 간단하면서 정확도가 그리 중요하지 않은 수준의 구현을 요구하는 것들이 대부분 입니다.
일전에 관련되어 문의를 받았지만 요즘에는 개인적으로 너무 바쁘고 여유가 없어서 설명을 드리고 싶지만 드릴 수 있는 시간조차 없었습니다. 몇주가 답변을 못드리다가 잠깐 짬을 내어 답변을 드렸지요.
웹상에서 찾아보면 일몰/일출 시간 소스는 얼마든지 있습니다. 그 방법도 엄청 많이 나와있지요. 단지 어찌 찾아야하는 것인지 있어도 어찌 활용해야하는지 모르시는 분들이 대부분이라 생각합니다. 그래서 여기에 이 부분에 대해 설명한 사이트들을 소개하고 마지막으로 웹에 공개된 C++소스에 주석처리한 것을 공유하겠습니다.
태양위치 계산은 정확도에 따라서 계산방법은 천차만별입니다. 그러므로 완벽한 정답은 없습니다. 상황에 맞게 쓰시면 됩니다.
아래내용은 태양의 일출/일몰 계산 방법을 간략하게 소개하고 있습니다.
http://www.stargazing.net/kepler/sunrise.html
PHP 언어로 만들어진 일출/일몰 소스입니다.
http://www.phpschool.com/gnuboard4/bbs/board.php?bo_table=tipntech&wr_id=39302&sca=%C7%D4%BC%F6&page=29
C또는 C++로 만들어진 일출/일몰 소스입니다.
http://www.sci.fi/~benefon/stuff.html
아래 붙여놓은 소스는 여기에서 구현한 C++소스를 주석처리 해놓은 것 입니다. 참고하시고 main()함수부터 천천히 보세요. 이것으로 근사적 일출/일몰 시간을 계산할 수 있습니다.
구현하신다음 맞는지 확인하기 위해 아래 링크를 참고하세요.
http://www2009.kasi.re.kr/knowledge/solun_riset.aspx
// C++ program calculating the sunrise and sunset for // the current date and a fixed location(latitude,longitude) // Jarmo Lammi 1999 - 2000 // Last update January 6th, 2000 #include <iostream.h> #include <math.h> #include <time.h> extern double pi; double tpi = 2 * pi; double degs = 180.0/pi; double rads = pi/180.0; double L,g,daylen; double SunDia = 0.53; // Sunradius degrees(지구에서 본 태양의 반지름각. 단위:도) double AirRefr = 34.0/60.0; // athmospheric refraction degrees (지구대기 굴절각)// // Get the days to J2000 // h is UT in decimal hours // FNday only works between 1901 to 2099 - see Meeus chapter 7 // 이 함수는 J2000 1월 1일 12시 DT를 기준으로 날수(Day Number)를 구합니다. (Meeus의 책 챕터 7을 참고하세요) // J2000에 대해서는 제 블로그 http://blog.jidolstar.com/487 를 참고하세요. // 입력값은 년,월,일,시간(실수값)입니다. double FNday (int y, int m, int d, float h) { int luku = - 7 * (y + (m + 9)/12)/4 + 275*m/9 + d; // type casting necessary on PC DOS and TClite to avoid overflow luku+= (long int)y*367; return (double)luku - 730531.5 + h/24.0; }; // the function below returns an angle in the range // 0 to 2*pi // // 들어온 값을 항상 0~2pi 값안으로 normalize시킵니다. double FNrange (double x) { double b = x / tpi; double a = tpi * (b - (long)(b)); if (a < 0) a = tpi + a; return a; }; // Calculating the hourangle // 시간각을 계산합니다. double f0(double lat, double declin) { double fo,dfo; // Correction: different sign at S HS dfo = rads*(0.5*SunDia + AirRefr); if (lat < 0.0) dfo = -dfo; fo = tan(declin + dfo) * tan(lat*rads); if (fo>0.99999) fo=1.0; // to avoid overflow // fo = asin(fo) + pi/2.0; return fo; }; // Calculating the hourangle for twilight times // 박명시간에 대한 시간각을 계산합니다. double f1(double lat, double declin) { double fi,df1; // Correction: different sign at S HS df1 = rads * 6.0; if (lat < 0.0) df1 = -df1; fi = tan(declin + df1) * tan(lat*rads); if (fi>0.99999) fi=1.0; // to avoid overflow // fi = asin(fi) + pi/2.0; return fi; }; // Find the ecliptic longitude of the Sun // 태양의 황경을 구합니다. double FNsun (double d) { // mean longitude of the Sun (태양의 평균 황경) L = FNrange(280.461 * rads + .9856474 * rads * d); // mean anomaly of the Sun (태양의 평균근점이각) g = FNrange(357.528 * rads + .9856003 * rads * d); // Ecliptic longitude of the Sun (태양의 황경계산) return FNrange(L + 1.915 * rads * sin(g) + .02 * rads * sin(2 * g)); }; // Display decimal hours in hours and minutes // 이것은 실수(Real Number)로 표현된 시간을 시:분으로 표기 하기 위한 겁니다. void showhrmn(double dhr) { int hr,mn; hr=(int) dhr; mn = (dhr - (double) hr)*60; if (hr < 10) cout << '0'; cout << hr << ':'; if (mn < 10) cout << '0'; cout << mn; }; // 메인함수입니다. int main(void){ double y,m,day,h,latit,longit; time_t sekunnit; struct tm *p; // get the date and time from the user // read system date and extract the year // 사용자의 시스템에서부터 날짜와 시간을 얻습니다. /** First get time **/ time(&sekunnit); /** Next get localtime **/ p=localtime(&sekunnit); y = p->tm_year; //년 // this is Y2K compliant method y+= 1900; m = p->tm_mon + 1; //월 day = p->tm_mday; //일 h = 12; //낮 12시를 기준으로 계산합니다. //관측장소의 경도(단위 degree),위도(단위 degree),타임존(단위시간) 값을 입력받습니다. double tzone=2.0; cout << "Input latitude, longitude and timezone and month\n"; cin >> latit; cin >> longit; cin >> tzone; // testing // m=6; day=10; double d = FNday(y, m, day, h); // Use FNsun to find the ecliptic longitude of the // Sun // 태양의 황경 double lambda = FNsun(d); // Obliquity of the ecliptic (황도기울기 계산) double obliq = 23.439 * rads - .0000004 * rads * d; // Find the RA and DEC of the Sun (태양의 적경,적위 계산) double alpha = atan2(cos(obliq) * sin(lambda), cos(lambda)); //태양의 적경 double delta = asin(sin(obliq) * sin(lambda)); //태양의 적위 // Find the Equation of Time // in minutes // Correction suggested by David Smith // 균시차 계산 double LL = L - alpha; if (L < pi) LL += tpi; double equation = 1440.0 * (1.0 - LL / tpi); double ha = f0(latit,delta); double hb = f1(latit,delta); double twx = hb - ha; // length of twilight in radians (라디안 단위 박명길이) twx = 12.0*twx/pi; // length of twilight in hours (시간단위 박명길이) cout << "ha=" << ha << " hb=" << hb << endl; // Conversion of angle to hours and minutes (하루길이를 시간단위로 계산) // daylen = degs*ha/7.5; if (daylen<0.0001) {daylen = 0.0;} // arctic winter // double riset = 12.0 - 12.0 * ha/pi + tzone - longit/15.0 + equation/60.0; //뜨는시간 double settm = 12.0 + 12.0 * ha/pi + tzone - longit/15.0 + equation/60.0; //지는시간 double noont = riset + 12.0 * ha/pi; //정오 시간 //정오시에 태양의 고도(maximum altitude) double altmax = 90.0 + delta * degs - latit; // Correction for S HS suggested by David Smith // to express altitude as degrees from the N horizon if (latit < delta * degs) altmax = 180.0 - altmax; double twam = riset - twx; // morning twilight begin 시민박명(아침) double twpm = settm + twx; // evening twilight end 시민박명(저녁) if (riset > 24.0) riset-= 24.0; if (settm > 24.0) settm-= 24.0; cout << "\n Sunrise and set\n"; cout << "===============\n"; cout.setf(ios::fixed); cout.precision(0); cout << " year : " << y << '\n'; //년 cout << " month : " << m << '\n'; //월 cout << " day : " << day << "\n\n"; //일 cout << "Days until Y2K : " << d << '\n'; //J2000을 기준으로 센 날수 cout.precision(2); cout << "Latitude : " << latit << ", longitude: " << longit << '\n'; //관측자의 경도와 위도 출력 cout << "Timezone : " << tzone << "\n\n"; //타임존 출력 (한국은 UT+9h) cout << "Declination : " << delta * degs << '\n'; //태양의 적위 cout << "Daylength : "; showhrmn(daylen); cout << " hours \n"; //하루길이 //시민박명(아침) cout << "Civil twilight: "; showhrmn(twam); cout << '\n'; //일출시간 cout << "Sunrise : "; // showhrmn(riset); cout << '\n'; //정오때 태양 고도(Amendment by D. Smith) cout << "Sun altitude at noontime "; showhrmn(noont); cout << " = " << altmax << " degrees" << (latit>=0.0 ? " S" : " N") << endl; //일몰시간 cout << "Sunset : "; showhrmn(settm); cout << '\n'; //시민박명(저녁) cout << "Civil twilight: "; showhrmn(twpm); cout << '\n'; return 0; }
어떤가요? 조금만 공을 들이면 완벽히 이해는 못해도 구현은 얼마든지 가능합니다.
글쓴이 : 지돌스타 (http://blog.jidolstar.com/705)
'우주,천문,별 > 천문프로그래밍' 카테고리의 다른 글
이런 밤하늘 프로그램을 원한다. (12) | 2010.01.05 |
---|---|
[천문/우주]CDS에서 제공하는 개발자 코너 - XML 웹서비스에 대해 (0) | 2009.12.29 |
[천문] 적경,적위 좌표값으로부터 별자리 이름 찾기 (11) | 2009.11.17 |
[천문] 율리우스 적일(積日, Julian Date) 계산 방법 (10) | 2009.11.17 |
[천문] delta-T(ΔT) 계산하기 (1) | 2009.11.17 |