/*
*************************************************************
*file: SolarCalculator.c
*company:
*describe: 算出某个点位与太阳相关信息
*时差(分钟
*太阳赤纬(以°)
*日出时间(HH:MM)
*正午时刻(HH:MM:SS)
*日落时间(HH:MM)
*方位角/高度角(以°)
*author:janzou date:2023.08.11
*************************************************************
*/
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include "SolarCalculator.h"
/*
******************************************************************************
*变量定义区
*******************************************************************************
*/
static RTMP_INFO rtmp;
/*
******************************************************************************
*UTC时间转换成本地时间
*tm->UTC时间
*timezone ->时区
*******************************************************************************
*/
static void UTCTOLocalTime(TIMEInfo* tm, char timezone)
{
short year,month,day,hour;
short lastday = 0;// 月的最后一天的日期
short lastlastday = 0;// 上月的最后一天的日期
year = tm->year;
month =tm->moth;
day = tm->day;
hour = tm->hour + timezone;
if(month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12)
{
lastday = 31;
if(month == 3)
{
//判断是否为闰年,年号能被400整除或年号能被4整除,而不能被100整除为闰年
if(IsLeapYear(year))
{
lastlastday = 29;// 闰年的2月为29天,平年为28天
}
else
{
lastlastday = 28;
}
}
if(month == 8)
{
lastlastday = 31;
}
}
else if(month == 4 || month == 6 || month == 9 || month == 11)
{
lastday = 30;
lastlastday = 31;
}
else
{
lastlastday = 31;
if(IsLeapYear(year))//闰年的2月为29天,平年为28天
{
lastday = 29;
}
else
{
lastday = 28;
}
}
if(hour >= 24)
{//当算出的区时大于或等于24:00时,应减去24:00,日期加一天
hour -= 24;
day += 1;
// 当算出的日期大于该月最后一天时,应减去该月最后一天的日期,月份加上一个月
if(day > lastday)
{
day -= lastday;
month += 1;
// 当算出的月份大于12时,应减去12,年份加上一年
if(month > 12)
{
month -= 12;
year += 1;
}
}
}
// 当算出的区时为负数时,应加上24:00,日期减一天
if(hour < 0)
{
hour += 24;
day -= 1;
//当算出的日期为0时,日期变为上一月的最后一天,月份减去一个月
if(day < 1)
{
// 当算出的月份为0时,月份变为12月,年份减去一年
day = lastlastday;
month -= 1;
if(month < 1)
{
month = 12;
year -= 1;
}
}
}
//得到转换后的本地时间
tm->year = year;
tm->moth = month;
tm->day = day;
tm->hour = hour;
return;
}
/*
******************************************************************************
* timeString returns a zero-padded string (HH:MM:SS) given time in minutes
* flag=2 for HH:MM, 3 for HH:MM:SS
*******************************************************************************
*/
static int timeString(float minutes, unsigned char flag, SC_TIME* tm)
{
if ( (minutes >= 0) && (minutes < 1440) )
{
float ftmp;
unsigned int hour,minute,second;
ftmp = minutes / 60.0;
hour = (unsigned int)ftmp;
ftmp = 60.0 * (ftmp - hour);
minute = (unsigned int)(ftmp);
ftmp = 60.0 * (ftmp -minute);
second = (unsigned int)(ftmp + 0.5);
if (second > 59)
{
second = 0;
minute += 1;
}
if ((flag == 2) && (second >= 30)) minute++;
if (minute > 59)
{
minute = 0;
hour += 1;
}
if(flag > 2)
{
tm->hour = hour;
tm->min = minute;
tm->sec = second;
}
else
{
tm->hour = hour;
tm->min = minute;
}
}
else
{
return 1;
}
return 0;
}
/*
******************************************************************************
* 获取世纪值
*******************************************************************************
*/
static float calcTimeJulianCent(float tmp)
{
return (tmp - 2451545.0)/36525.0;
}
/*
******************************************************************************
* 时间转换成分钟(今天过了多少分钟)
*******************************************************************************
*/
static float GetTimeMin(unsigned int h, unsigned int m, unsigned int s)
{
return (h * 60.0 + m + s/60.0);
}
/*
******************************************************************************
* 弧度转角度
*******************************************************************************
*/
static float radToDeg(float angleRad)
{
return (180.0 * angleRad / MATH_PAI_VAL);
}
/*
******************************************************************************
* 角度转弧度
*******************************************************************************
*/
static float degToRad(float angleDeg)
{
return (MATH_PAI_VAL * angleDeg / 180);
}
/*
************************************************************************
* 计算地球轨道偏心率(eccentricity [e])
* 数学上称为“离心率”
* 对于椭圆 => 两焦点间的距离(2c)和长轴长度(2a)的比值,即 e=c/a
************************************************************************
*/
static float calcEccentricityEarthOrbit(float t)
{
float e = 0.016708634 - t * (0.000042037 + 0.0000001267 * t);
return e;
}
/*
**************************************************************************************
* 计算太阳的平近点角(mean anomaly [M])
* 平近点角:轨道上的物体在辅助圆上相对于中心点的运行角度
* 参考:https://en.wikipedia.org/wiki/Mean_anomaly
**************************************************************************************
*/
static float calcGeomMeanAnomalySun(float t)
{
float M = 357.52911 + t * (35999.05029 - 0.0001537 * t);
return M;
}
/*
***********************************************************************
* t => Julian century(经过的世纪数)
* 计算太阳的平黄经(geometric mean longitude [L0])
* 黄经:天球黄道坐标系中的经度 => 用来确定天体在天球上的位置
***********************************************************************
*/
static float calcGeomMeanLongSun(float t)
{
float L0 = 280.46646 + t * (36000.76983 + t*(0.0003032));
while(L0 > 360.0)
{
L0-= 360.0;
}
while(L0 < 0.0)
{
L0+= 360.0;
}
return L0;
}
/*
*********************************************************************************************
* 圆心方程(Equation of the Center)
* 计算角差(椭圆轨道上实际位置与它在同一周期的圆形轨道上匀速运动时所占位置之间的角差)
* 参考 https://en.wikipedia.org/wiki/Equation_of_the_center
*********************************************************************************************
*/
static float calcSunEqOfCenter(float t)
{
float m,sinm,sin2m,sin3m;
m = calcGeomMeanAnomalySun(t);
m = degToRad(m);
sinm = sin(m);
sin2m = sin(m+m);
sin3m = sin(m+m+m);
m = sinm * (1.914602 - t * (0.004817 + 0.000014 * t)) + sin2m * (0.019993 - 0.000101 * t) + sin3m * 0.000289;
return m;
}
/*
******************************************************************************
*计算太阳真实经度(True Longitude)
*******************************************************************************
*/
static float calcSunTrueLong(float t)
{
float l0,c;
l0 = calcGeomMeanLongSun(t);
c = calcSunEqOfCenter(t);
c= l0 + c;
return c;
}
/*
*************************************************************************************
* 计算太阳表观经度
* 参考 https://en.wikipedia.org/wiki/Apparent_longitude
**************************************************************************************
*/
static float calcSunApparentLong(float t)
{
float o,omega;
o = calcSunTrueLong(t);
omega = 125.04 - 1934.136 * t;
omega = o - 0.00569 - 0.00478 *sin(degToRad(omega));
retur