Calculation of Satellite Coordinates in CGCS2000 Geodetic Coordinate System Based on Satellite Ephemeris

Table of contents

1. Beidou system overview

1. Space Constellation

2. Coordinate system

3. Time system

2. The purpose of the experiment

3. Experimental content

4. Experimental process

5. Experimental results


1. Beidou system overview

1. Space Constellation

The Beidou satellite navigation system is referred to as the Beidou system, and the English abbreviation is BDS. Its space constellation consists of 5 geostationary orbit (GEO) satellites, 27 medium earth orbit (MEO) satellites and 3 inclined geosynchronous orbit (IGSO) satellites. GEO satellites orbit at an altitude of 35,786 kilometers, fixed at 58.75 degrees, 80 degrees, 110.5 degrees, 140 degrees and 160 degrees east longitude respectively; MEO satellites orbit at an altitude of 21,528 kilometers with an orbital inclination of 55 degrees; 55 degrees.

2. Coordinate system

The Beidou system adopts the 2000 China Geodetic Coordinate System (CGCS2000). The definition of the CGCS2000 geodetic coordinate system is as follows: the origin is located at the center of mass of the earth; the Z axis points to the direction of the reference pole (IRP) defined by the International Earth Rotation Service (IERS); The intersection line of the equatorial plane perpendicular to the Z axis; the Y axis and the Z and X axes form a right-handed rectangular coordinate system. The CGCS2000 origin is also used as the geometric center of the CGCS2000 ellipsoid, and the Z axis is used as the axis of rotation of the spheroid. The basic constants defined by CGCS2000 reference ellipsoid are:

semi-major axis: a = 6378137.0 m
Earth (including atmosphere) gravitational constant:

\mu = 3.986004418\times 10^{14} m^{3}/s^{2}

Flat rate: f = 1/298.257222101
Earth's rotation rate: \Omega e = 7.2921150\times 10^{-5} rad/s

3. Time system

The time reference of the Beidou system is Beidou Time (BDT). BDT uses the International System of Units (SI) second as the basic unit for continuous accumulation, without leap seconds, and the starting epoch is January 1, 2006 at 00:00:00 UTC Coordinated Universal Time (UTC), and counts the seconds of the week and the week . BDT is connected with international UTC through UTC (NTSC), and the deviation between BDT and UTC is kept within 100 nanoseconds (modulo 1 second). Leap second information between BDT and UTC is broadcast in the navigation message.

2. The purpose of the experiment

The satellite ephemeris is a set of parameters describing the orbital motion of the satellite, and the real-time position of the satellite can be calculated according to the satellite ephemeris. Through this experiment, I am familiar with the form, basic parameters and meaning of the Beidou satellite ephemeris, and can calculate the satellite position according to the satellite ephemeris.

3. Experimental content

Using the given satellite ephemeris data (badata.txt) and referring to "Beidou Satellite Navigation System Signal-in-Space Interface Control Document - Open Service Signal (Version 2.1)", the coordinate calculation of the satellite in the CGCS2000 geodetic coordinate system is realized based on programming.

4. Experimental process

Satellite positions are calculated from satellite almanac data. Satellite almanac data includes satellite orbit parameters, time information and other related parameters. From these data, we can deduce the exact position of the satellite at a specific point in time.

1. First, the code opens an input file and reads the contents of the file into a string using a buffered stream. This input file contains satellite almanac data, which may be in a row-by-line format, or in some other form of text.

2. Next, the code uses data structures such as linked lists and hash maps to store satellite almanac data. A linked list is used to store each set of data sequentially, while a hash map is used to quickly find a specific satellite data. Each set of data contains information such as satellite number, time, and orbital elements.

3. The code then uses the stored data to perform a satellite position calculation. It calculates the satellite's orbital parameters through a series of mathematical formulas and iterative algorithms. These orbital parameters include semi-major axis, eccentricity, orbital inclination, right ascension of ascending node, etc. These parameters are important information describing the shape and position of satellite orbits.

4. According to the calculated orbit parameters, the code further calculates the position coordinates of the satellite in three-dimensional space. This process involves the conversion of the coordinate system, the calculation of time and vector operations, etc.

5. Finally, the code writes the calculated satellite position results to an output file. The output file usually contains the number of the satellite and the corresponding position coordinate information. In this way, the user can obtain the exact position of the satellite at a specific point in time by reading the output file.

6. In addition to the main position calculation part, the code also includes some auxiliary functions. These functions are used for time-related calculations such as calculating Julian Day, as well as basic mathematical operations such as matrix multiplication.

source code:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.LinkedList;

public class Test_GNSS {
    public static void main(String[] args) throws IOException {

        double miu = 3.986004418e+14;           //CGCS2000 坐标系下的地球引力常数
        double OmegaEdot = 7.2921150e-5;        //CGCS2000 坐标系下的地球旋转速率
        double DayToSecond = 24.0 * 3600.0d;    //天秒数

        //创建字符输入输对象来访问文件
        FileReader fileReader = new FileReader("D:\\juechen\\badata.txt");
        FileWriter fileWriter = new FileWriter("D:\\juechen\\badata_result.txt");

        //创建输入对象的缓冲流
        BufferedReader bufferedReader = new BufferedReader(fileReader);

        //将缓冲流写入字符串
        String inputData = bufferedReader.readLine();
        //System.out.println(inputData);

        //创建字符可变的字符串用来记录计算结果
        StringBuilder outputDta = new StringBuilder("PRN\tx\ty\tz\n");

        //创建相应的数据结构用来保存原始数据
        LinkedList<HashMap<String, String>> linkedList = new LinkedList<>();

        //将卫星星历数据存储在LinkedList中的计算过程
        for (int i = 0; i < 13; i++) {
            inputData = bufferedReader.readLine();

            //将读入的字符串保存在字符串数组中,当匹配到两个及以上的空格时,分割
            String[] newLineArray = inputData.split("[ ]{2,}");

            //将列名和所对应的数据存储在HashMap中
            HashMap<String, String> newLineHashMap = new HashMap<>();
            newLineHashMap.put("Epoch", newLineArray[0]);
            newLineHashMap.put("PRN", newLineArray[1]);
            newLineHashMap.put("WN", newLineArray[2]);
            newLineHashMap.put("toe", newLineArray[3]);

            //对超过16位有效位的数用BigDecimal进行有效存储,提高精度
            BigDecimal db = new BigDecimal(newLineArray[4]);
            newLineHashMap.put("SqrtA", db.toPlainString());
            db = new BigDecimal(newLineArray[5]);
            newLineHashMap.put("e", db.toPlainString());
            db = new BigDecimal(newLineArray[6]);
            newLineHashMap.put("i", db.toPlainString());
            db = new BigDecimal(newLineArray[7]);
            newLineHashMap.put("Omega0", db.toPlainString());
            db = new BigDecimal(newLineArray[8]);
            newLineHashMap.put("w", db.toPlainString());
            db = new BigDecimal(newLineArray[9]);
            newLineHashMap.put("M", db.toPlainString());
            db = new BigDecimal(newLineArray[10]);
            newLineHashMap.put("deltaN", db.toPlainString());
            db = new BigDecimal(newLineArray[11]);
            newLineHashMap.put("OmegaDot", db.toPlainString());
            db = new BigDecimal(newLineArray[12]);
            newLineHashMap.put("idot", db.toPlainString());
            newLineHashMap.put("Crs", newLineArray[13]);
            newLineHashMap.put("Crc", newLineArray[14]);
            db = new BigDecimal(newLineArray[15]);
            newLineHashMap.put("Cus", db.toPlainString());
            db = new BigDecimal(newLineArray[16]);
            newLineHashMap.put("Cuc", db.toPlainString());
            db = new BigDecimal(newLineArray[17]);
            newLineHashMap.put("Cis", db.toPlainString());
            db = new BigDecimal(newLineArray[18]);
            newLineHashMap.put("Cic", db.toPlainString());
            newLineHashMap.put("toc", newLineArray[19]);
            db = new BigDecimal(newLineArray[20]);
            newLineHashMap.put("a0", db.toPlainString());
            db = new BigDecimal(newLineArray[21]);
            newLineHashMap.put("a1", db.toPlainString());
            db = new BigDecimal(newLineArray[22]);
            newLineHashMap.put("a3", db.toPlainString());

            //保存原始数据
            linkedList.add(newLineHashMap);
        }

        //用linkList存储的每一组卫星星历数据来计算卫星位置
        for (int i = 0; i < 13; i++) {
            HashMap<String, String> calculateHashMap = linkedList.get(i);

            //计算观测时间的儒略日
            String[] date_time = calculateHashMap.get("Epoch").split(" ");
            String date = date_time[0];
            String time = date_time[1];
            double[] timeD = new double[]{Double.parseDouble(date.split("-")[0]), Double.parseDouble(date.split("-")[1]), Double.parseDouble(date.split("-")[2])};
            double[] timeH = new double[]{Double.parseDouble(time.split(":")[0]), Double.parseDouble(time.split(":")[1]), Double.parseDouble(time.split(":")[2])};
            double EpochT = calculateJD(timeD[0], timeD[1], timeD[2], timeH[0], timeH[1], timeH[2]) - calculateJD(2006d, 1d, 1d, 0, 0, 0);

            //计算半长轴
            double A = Math.pow(Double.parseDouble(calculateHashMap.get("SqrtA")), 2);

            //计算卫星平均角速度
            double n0 = Math.sqrt(miu / Math.pow(A, 3));

            //计算观测历元到参考历元的时间差
            double tk = (EpochT - Double.parseDouble(calculateHashMap.get("WN")) * 7.0d) * DayToSecond - Double.parseDouble(calculateHashMap.get("toe"));

            //计算改正平均角速度
            double n = n0 + Double.parseDouble(calculateHashMap.get("deltaN"));

            //计算平近点角
            double Mk = Double.parseDouble(calculateHashMap.get("M")) + n * tk;

            //迭代计算偏近点角
            double delta = 1.0D;
            double Ek = Mk;
            double k = 0L;
            double e = Double.parseDouble(calculateHashMap.get("e"));
            while (Math.abs(delta) > 0.0000001D && k <= 1000l) {
                Ek = Ek - delta / (1 - e * Math.cos(Ek));
                delta = Ek - e * Math.sin(Ek) - Mk;
                k = k + 1;
            }

            //计算真近点角
            double sinvk = (Math.sqrt(1 - Math.pow(e, 2)) * Math.sin(Ek)) / (1 - e * Math.cos(Ek));
            double cosvk = (Math.cos(Ek) - e) / (1 - e * Math.cos(Ek));

            //计算vk
            double vk = 0;
            if (sinvk >= 0 && cosvk >= 0) {
                vk = Math.asin(sinvk);
            } else if (sinvk >= 0 && cosvk < 0) {
                vk = Math.PI - Math.asin(sinvk);
            } else if (sinvk < 0 && cosvk >= 0) {
                vk = Math.PI * 2 + Math.asin(sinvk);
            } else if (sinvk < 0 && cosvk < 0) {
                vk = Math.PI - Math.asin(sinvk);
            }

            //计算纬度幅角参数faik
            double faik = vk + Double.parseDouble(calculateHashMap.get("w"));

            //计算纬度幅角改正项duk、径向改正项drk、轨道倾角改正项dik
            double duk = Double.parseDouble(calculateHashMap.get("Cus")) * Math.sin(2 * faik) + Double.parseDouble(calculateHashMap.get("Cus")) * Math.cos(2 * faik);
            double drk = Double.parseDouble(calculateHashMap.get("Crs")) * Math.sin(2 * faik) + Double.parseDouble(calculateHashMap.get("Crs")) * Math.cos(2 * faik);
            double dik = Double.parseDouble(calculateHashMap.get("Cis")) * Math.sin(2 * faik) + Double.parseDouble(calculateHashMap.get("Cis")) * Math.cos(2 * faik);

            //计算改正后的纬度幅角uk
            double uk = faik + duk;

            //计算改正后的径向rk
            double rk = A * (1 - e * Math.cos(Ek)) + drk;

            //计算改正后的轨道倾角ik
            double ik = Double.parseDouble(calculateHashMap.get("i")) + Double.parseDouble(calculateHashMap.get("idot")) * tk + dik;

            //计算卫星在轨道平面内的坐标(xk,yk)
            double xk = rk * Math.cos(uk);
            double yk = rk * Math.sin(uk);

            //计算历元升交点赤经(地固系)
            //计算 MEO/IGSO 卫星在 CGCS2000 坐标系中的坐标(Xk,Yk,Zk)
            double Omegak = 0;
            double Xk = 0;
            double Yk = 0;
            double Zk = 0;
            if (Double.parseDouble(calculateHashMap.get("i")) > 0) {
                Omegak = Double.parseDouble(calculateHashMap.get("Omega0")) + (Double.parseDouble(calculateHashMap.get("OmegaDot")) - OmegaEdot) * tk - OmegaEdot * Double.parseDouble(calculateHashMap.get("toe"));
                Xk = xk * Math.cos(Omegak) - yk * Math.cos(ik) * Math.sin(Omegak);
                Yk = xk * Math.sin(Omegak) + yk * Math.cos(ik) * Math.cos(Omegak);
                Zk = yk * Math.sin(ik);
            }

            //计算历元升交点的赤经(惯性系)
            //计算 GEO 卫星在自定义坐标系系中的坐标(Xgk,Ygk,Zgk)
            //计算 GEO 卫星在 CGCS2000 坐标系中的坐标(Xk,Yk,Zk)
            double Xgk = 0;
            double Ygk = 0;
            double Zgk = 0;
            double Rxf = 0;
            double Rzf = 0;
            double[][] Rz = null;
            double[][] Rx = null;
            double[][] Rgk = null;
            double[][] XYZ = null;
            if (Double.parseDouble(calculateHashMap.get("i")) == 0) {
                Omegak = Double.parseDouble(calculateHashMap.get("Omega0")) + Double.parseDouble(calculateHashMap.get("OmegaDot")) * tk - OmegaEdot * Double.parseDouble("toe");
                Xgk = xk * Math.cos(Omegak) - yk * Math.cos(ik) * Math.sin(Omegak);
                Ygk = xk * Math.sin(Omegak) + yk * Math.cos(ik) * Math.cos(Omegak);
                Zgk = yk * Math.sin(ik);
                Rxf = -5.0 * Math.PI / 180.0D;
                Rzf = OmegaEdot * tk;
                Rx = new double[][]{
   
   {1D, 0D, 0D}, {0D, Math.cos(Rxf), Math.sin(Rxf)}, {0d, -Math.sin(Rxf), Math.cos(Rxf)}};
                Rz = new double[][]{
   
   {Math.cos(Rzf), Math.sin(Rzf), 0d}, {-Math.sin(Rzf), Math.cos(Rzf), 0d}, {0d, 0d, 1d}};
                Rgk = new double[][]{
   
   {Xgk}, {Ygk}, {Zgk}};
                XYZ = matrixMultiplication(matrixMultiplication(Rz, Rx), Rgk);
                Xk = XYZ[0][0];
                Yk = XYZ[0][1];
                Zk = XYZ[0][2];
            }

            //将计算结果添加到字符串
            outputDta.append(calculateHashMap.get("PRN") + "\t" + Xk + "\t" + Yk + "\t" + Zk + "\n");
        }

        //将字符串写入输出对象文件
        fileWriter.write(outputDta.toString());

        //回收资源
        bufferedReader.close();
        fileReader.close();
        fileWriter.close();
    }

    //计算儒略日
    static double calculateJD(double y, double mon, double d, double h, double miu, double s) {
        double day = d + (h * 3600 + miu * 60 + s) / 86400;
        double year = y + 4800;
        double m = mon;
        if (m < 2) {
            m = m + 12;
            year = year - 1;
        }
        double a = Math.floor(30.6 * (m + 1));
        double b = 0;
        if (y < 1582 || (y == 1582 && mon < 10) || (y == 1582 && mon == 10 && d < 5)) {
            b = -38;
        } else {
            b = Math.floor((y / 400) - (y / 100));
        }
        double c = Math.floor(365.25 * year);
        return (a + b + c + day);
    }

    //矩阵乘法
    static double[][] matrixMultiplication(double[][] A, double[][] B) {
        int line = A.length;        //矩阵A第一维长度(行)
        int column = B[0].length;   //矩阵B第二维长度(列)
        double[][] result = new double[line][column];   //定位结果矩阵大小
        for (int i = 0; i < A.length; i++) {            //矩阵A的行数
            for (int j = 0; j < B[0].length; j++) {     //矩阵B的列数
                double sum = 0;

                //矩阵的每一行乘以每一列
                for (int k = 0; k < B.length; k++) {
                    sum += A[i][k] * B[k][j];
                }
                result[i][j] = sum;
            }
        }
        return result;
    }
}

5. Experimental results

have to be aware of is:

Ensure the consistency of the coordinate system and units used in the program. Make sure that the correct time expression and related algorithms are used in the calculation process to avoid calculation errors caused by time errors. Make sure your code is readable, using good coding practices and comments.

Guess you like

Origin blog.csdn.net/qq_57342311/article/details/131176134