利用广播星历计算卫星在ECEF下的坐标

#define  _CRT_SECURE_NO_WARNINGS 1
#include 
#include 
#include 
#define SIZE 36
#define pi 3.1415926535898
#define Omegae 7.2921151467e-5   //地球自转角速度
double n,xk_s,yk_s,omegak;
struct s_position       //定义结构体s_position用来存放计算得到的卫星的位置
{
	double x;
	double y;
	double z;
}s_ecef;

int main()
{
	struct s_position* calculation(float array[SIZE], double t);
	FILE *fp;
	if ((fp = fopen("ephemeris.txt", "r")) == NULL)    //使用fopen()函数以只读的方式打开星历,若打开故障,则返回一个空指针,并提示文件打开出错
	{
		printf("cannot open this file\n");
		exit(0);
	}
	double dataarray[SIZE];          //定义双精度浮点型数组存储从星历中读取的参数
	for (int i = 0; i < SIZE; i++)
	{
		fscanf(fp, "%lf", &dataarray[i]);
	}

	struct s_position* p = calculation(dataarray, dataarray[18]);

	int PRN = (int)dataarray[0];
	printf("定位系统:GPS 卫星PRN编号:%d 长半径:%lf 平均角速度:%lf\n",PRN,pow(dataarray[17],2),n);
	printf("卫星在轨道平面直角坐标系中的位置:x = %lf  y = %lf  升交点赤经:%lf\n", xk_s, yk_s, omegak);
	printf("卫星在地心地固坐标系中的位置为:\nx = %lf\ny = %lf\nz = %lf\n", p->x, p->y, p->z);

	return 0;
}

struct s_position* calculation(double array[SIZE],double t)
{
	double toe = array[18];       //星历参考时间
	double sqrt_a = array[17];     //轨道长半径的平方根
	double es = array[15];         //轨道偏心率
	double io = array[22];        //toe时的轨道倾角
	double omega0 = array[20];      //周内时等于0时的轨道升交点赤经
	double omg = array[24];         //轨道近地角距
	double Mo = array[13];         //toe时的平近点角
	double delta_n = array[12];      //平均运动角速度校正值
	double I = array[26];           //轨道倾角对时间的变化率
	double OMEGA = array[25];       //轨道升交点赤经对时间的变化率
	double Cuc = array[14];           //升交点角距余弦调和校正振幅
	double Cus = array[16];           //升交点角距正弦调和校正振幅
	double Crc = array[23];           //轨道半径余弦调和校正振幅
	double Crs = array[11];            //轨道半径正弦调和校正振幅
	double Cic = array[19];            //轨道倾角余弦调和校正振幅
	double Cis = array[21];             //轨道倾角正弦调和校正振幅

	double tk = t - toe;  //计算规化时间
	if (tk > 302400)
	{
		tk = tk - 604800;
	}
	else if (tk < -302400)
	{
	tk = tk + 604800;
    }
	double const GM = 3.986005e+14;     //计算卫星的平均角速度n
	double n0 = sqrt((GM) / (pow(sqrt_a, 6)));
	 n = n0 + delta_n;

	double Mk = Mo + n * tk;       //计算信号发射时刻的平近点角Mk;
	if (Mk < 0)
	{
		Mk = Mk + 2 * pi;
	}
	else if (Mk > 2 * pi)
	{
		Mk = Mk - 2 * pi;
	}

	double E0 = Mk;              //使用迭代法求解观测时刻tk的偏近点角Ek
	double Ek = Mk + es * sin(E0);
	while (abs(Ek - E0) > 10e-12) 
	{
		E0 = Ek;
		Ek = Mk + es * sin(E0);
	}

	double cosvk = (cos(Ek) - es) / (1 - es * cos(Ek));     //计算观测时刻tk的真近点角vk
	double sinvk = (sqrt(1 - (es)*(es))*sin(Ek)) / (1 - es * cos(Ek));
	double vk;
	if (cosvk == 0)          //由于分母不能为0.因此在使用atan()函数前先判断余弦值是否为0
	{
		if (sinvk > 0)
		{
			vk = pi / 2;
		}
		else
		{
			vk = -pi / 2;
		}
	}
	else
	{
		vk = atan(sinvk / cosvk);
	}

	if (cosvk < 0)          //判断角的象限,以及做出调整
	{
		if (sinvk >= 0) {
			vk += pi;
		}
		else {
			vk -= pi;
		}
	}
	
	double faik = vk + omg;     //计算观测时刻tk的升交点角距

	double delta_uk = Cus * sin(2 * faik) + Cuc * cos(2 * faik);   //计算观测时刻tk的摄动校正项
	double delta_rk = Crs * sin(2 * faik) + Crc * cos(2 * faik);
	double delta_ik = Cis * sin(2 * faik) + Cic * cos(2 * faik);

	double uk = faik + delta_uk;                //计算摄动校正后的升交点角距,卫星矢径长度以及轨道倾角
	double rk = pow(sqrt_a, 2)*(1 - es * cos(Ek)) + delta_rk;
	double ik = io + I * tk + delta_ik;

	
	 xk_s = rk * cos(uk);     //计算观测时刻卫星在轨道平面的位置
	 yk_s = rk * sin(uk);
	double zk_s = 0;

	 omegak = omega0 + (OMEGA - Omegae)*tk - Omegae * toe;     //计算观测时刻的升交点赤经
	s_ecef.x = xk_s * cos(omegak) - yk_s * cos(ik)*sin(omegak);
	s_ecef.y = xk_s * sin(omegak) + yk_s * cos(ik)*cos(omegak);
	s_ecef.z = yk_s * sin(ik);

	struct s_position* p = &s_ecef;
	return(p);
	
}

运行结果:

利用广播星历计算卫星在ECEF下的坐标_第1张图片

精密星历中对应时刻GPS3号卫星位置: 

 原始数据:

从导航电文中截取3号卫星的星历,将D改为e,存放在新建的txt文件中:

利用广播星历计算卫星在ECEF下的坐标_第2张图片

利用广播星历计算卫星在ECEF下的坐标_第3张图片

为了方便与精密星历做比较,此处t = toe ,计算的就是星历参考时刻卫星的位置

 

 

你可能感兴趣的:(c语言,gnss)