Orekit学习笔记一

870 阅读8分钟

Orekit,一个用 Java 编写的低级空间动力学库,已经获得了 自从它在开源下发布以来,它得到了广泛的认可 2008年获得许可。

官网:www.orekit.org/

        maven依赖
        <dependency>
            <groupId>org.orekit</groupId>
            <artifactId>orekit</artifactId>
            <version>11.3.3</version>
        </dependency>

作为航天动力学库,Orekit 最基本的功能性算法就是对航天器状态矢量进行预报,该功能由 org.orekit.propagation 包提供。Orekit 有三种预报方式,一是解析法预报,由 org.orekit.propagation.analytical 实现;二是数值法预报,由 org.orekit.propagation.numericalorg.orekit.propagation.integration 实现;三是半解析法预报,由 org.orekit.propagation.semianalytical.dsst 实现。

解析法预报速度快,但精度随时间下降快,且需要平根或拟平根作为预报输入,即需要事先定轨;数值法通过求解轨道动力学方程实现,模型精确的情况下,预报精度高,但由于必须递推中间过程量,故需消耗较多的计算资源;半解析法速度和精度都介于解析法和数值法之间,一般用于卫星轨道寿命与离轨分析

Orekit 中的轨道描述由 org.orekit.orbits 包提供,该包是构建航天动力学相关程序的基础。从 v3.0 开始,Orekit 就支持多种轨道描述,包括:经典开普勒轨道 KeplerianOrbit圆轨道 CircularOrbit赤道轨道 EquinoctialOrbit 以及三维状态矢量 CartesianOrbit

  • 经典开普勒轨道描述: KeplerianOrbit 1). a:轨道半场轴(m) 2). e:轨道偏心率(NAN) 3). i:轨道倾角(rad) 4). ω:近地点幅角(rad) 5). Ω:升交点赤经(rad) 6). ν,E or M:真近角、偏近角或平近角(rad)
  • 圆轨道描述: CircularOrbit 1). a:轨道半场轴(m) 2). ex:偏心率矢量 X 分量(NAN),ex=e×cos(ω) 3). ey:偏心率矢量 Y 分量(NAN),ey=e×sin(ω) 4). i:轨道倾角(rad) 5). Ω:升交点赤经(rad) 6). ,uE or uM:真纬度幅角(ω+ν)、偏纬度幅角(ω+E)和平纬度幅角(ω+M)(rad)
  • 赤道轨道: EquinoctialOrbit 1). a:轨道半场轴(m) 2). ex:偏心率矢量 X 分量(NAN),ex=e×cos(ω) 3). ey:偏心率矢量 Y 分量(NAN),ey=e×sin(ω) 4). ix:倾角矢量 X 分量(NAN),hx=tan(i/2)×cos(Ω) 5). iy:倾角矢量 Y 分量(NAN),hy=tan(i/2)×sin(Ω) 5). Ω:升交点赤经(rad) 6). ,lE or lM:真纬度幅角(ω+ν+Ω)、偏纬度幅角(ω+E+Ω)和平纬度幅角(ω+M+Ω)(rad)
  • 三维状态矢量: CartesianOrbit 1). X,Y,Z:位置矢量(m) 2). Vx,Vy,Vz:速度矢量(m/s)

轨道预报流程

1.添加动力学建模数据

动力学建模数据包含了 Orekit 建立动力学模型、进行时间和参考架转换以及星历计算所需要的重要参数,必须在调用 Orekit 下属类库之前加载,配置代码如下所示。代码中的文件路径根据具体情况修改。

// configure Orekit
File home       = new File("D:/CodeProjects/eclipse_java/Orekit");
File orekitData = new File(home, "orekit-data");
if (!orekitData.exists()) {
    System.err.format(Locale.US, "Failed to find %s folder%n",
            orekitData.getAbsolutePath());
    System.err.format(Locale.US, "You need to download %s from the %s page and unzip it in %s for this tutorial to work%n",
            "orekit-data.zip", "https://www.orekit.org/forge/projects/orekit/files",
            home.getAbsolutePath());
    System.exit(1);
    }
DataProvidersManager manager = DataProvidersManager.getInstance();
manager.addProvider(new DirectoryCrawler(orekitData));

2.创建轨道

四种轨道描述方法定义的轨道根数都可以作为轨道预报的输入,采用 Orbit 关键字进行定义。开普勒轨道根数定义方法如下:

double mu      = 3.986004415e+14;
Orbit kepOrbit = new KeplerianOrbit(a, e, i, omega, raan, M, PositionAngle.MEAN, Frame, Date, mu);

代码中,M 对应 PositionAngle.MEAN,即表示平近角,真近角和偏近角分别用 PositionAngle.TUREPositionAngle.ECCENTRIC 表示;mu 为中心天体引力常数,Frame 为参考架,J2000 坐标系用 FramesFactory.getEME2000() 表示,遵循 IERS 2010 约定的地球固连坐标系,简称地固系,用 FramesFactory.getTIRF(IERSConventions.IERS_2010) 表示;Date 为时间,采用如下代码初始化:

AbsoluteDate Date = new AbsoluteDate(yr, mt, day, hr, min, sec, TimeScalesFactory.getUTC());

类似地,圆轨道根数定义方法如下:

double mu      = 3.986004415e+14;
Orbit cirOrbit = new CircularOrbit(a, ex, ey, i, raan, u, PositionAngle.MEAN, Frame, Date, mu);

赤道轨道根数定义方法如下:

double mu      = 3.986004415e+14;
Orbit equOrbit = new EquinoctialOrbit(a, ex, ey, hx, hy, l, PositionAngle.MEAN, Frame, Date, mu);

三维状态矢量定义方法如下:

double mu           = 3.986004415e+14;
PVCoordinates catPV = new PVCoordinates(new Vector3D, new Vector3D);
Orbit catOrbit      = new CartesianOrbit(catPV, Frame, Date, mu);

代码中,catPV 为状态矢量。根据轨道数据的来源,选择对应的轨道描述方式。

3.建立轨道预报器

Orekit 提供多种解析法预报器,由 org.orekit.propagation.analytical 包实现,最简单的为基于 二体模型 的解析法预报器:

KeplerianPropagator tbProp = new KeplerianPropagator(Orbit initialOrbit);

较为复杂的解析法预报器基于 EcksteinHechler 模型:

double referenceRadius = 6378136.3;
double mu  =  3.986004415e+14;
double c20 = -0.484165143790815e-03;
double c30 =  0.957161207093473e-06;
double c40 =  0.539965866638991e-06;
double c50 =  0.686702913736681e-07;
double c60 = -0.149953927978527e-06
EcksteinHechlerPropagator ehProp = 
        new EcksteinHechlerPropagator(Orbit initialOrbit, referenceRadius, mu, c20, c30, c40, c50, c60);

Orekit 数值预报器由 org.orekit.propagation.numerical 包实现,定义方法如下:

NumericalPropagator propagator = new NumericalPropagator(integrator);

参数 integrator 较具有多种选择,通用型高精度积分器可选择 PD 系列中的 DormandPrince853Integrator,定义方法如下:

final double minStep = 0.001;
final double maxstep = 100.0;
final double positionTolerance = 1.0e-13;
final OrbitType propagationType = OrbitType.KEPLERIAN;
final double[][] tolerances = 
        NumericalPropagator.tolerances(positionTolerance, initialOrbit, propagationType);
AdaptiveStepsizeIntegrator integrator = 
        new DormandPrince853Integrator(minStep, maxstep, tolerances[0], tolerances[1]);

此外,数值轨道预报,还需要设置动力学模型,一般只考虑地球引力场:

final NormalizedSphericalHarmonicsProvider provider =
        GravityFieldFactory.getNormalizedProvider(20, 20);
ForceModel holmesFeatherstone = 
        new HolmesFeatherstoneAttractionModel(FramesFactory.getITRF(IERSConventions.IERS_2010, true), provider);

更多力学模型的设置参考 API 文档中的 NumericalPropagator 类:orekit-9.2-javadoc/org/ orekit/propagation/numerical/NumericalPropagator.html

轨道预报流程那部分内容出自spacefan.github.io/2019/01/25/…

轨道六根数转换成笛卡尔积

代码:

File file = new File("C:/SoftwareInstallationPackage/orekit-data-master/");
        DataProvidersManager manager = DataContext.getDefault().getDataProvidersManager();
        manager.addProvider(new DirectoryCrawler(file));
        double a=7275435.324;  //轨道半长轴
        double e=0.0019976693; //轨道偏心率
        double i=89.0603273252; //轨道倾角
        double omega=72.2698073713;  //近地点幅角
        double raan=26.9856045949;  //升交点赤经
        double m=174.4969934001;  //平近点角
        //double mu = 3.986004415e+14;
        double mu = 398600441500000.000;
        //AbsoluteDate absoluteDate = new AbsoluteDate(new Date(), TimeScalesFactory.getUTC());
        LocalDateTime time = LocalDateTime.now(Clock.systemUTC());
        String format = time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"));
        AbsoluteDate absoluteDate = new AbsoluteDate(format, TimeScalesFactory.getUTC());
        AbsoluteDate end = new AbsoluteDate("2023-08-18T18:04:00", TimeScalesFactory.getUTC());
        FactoryManagedFrame frame = FramesFactory.getEME2000();   //J2000坐标系
        KeplerianOrbit keplerianOrbit = new KeplerianOrbit(a, e, i, omega, raan, m, PositionAngle.MEAN, frame, absoluteDate, mu);

        double[][] tolerances = NumericalPropagator.tolerances(1, keplerianOrbit, OrbitType.KEPLERIAN);
        DormandPrince853Integrator integrator = new DormandPrince853Integrator(0.001, 100, tolerances[0], tolerances[1]);
        NumericalPropagator propagator = new NumericalPropagator(integrator);   //创建数值预报器

        final NormalizedSphericalHarmonicsProvider provider = GravityFieldFactory.getNormalizedProvider(20, 20);
        HolmesFeatherstoneAttractionModel holmesFeatherstoneAttractionModel = new HolmesFeatherstoneAttractionModel(FramesFactory.getTIRF(IERSConventions.IERS_2010, true), provider);

        propagator.setOrbitType(OrbitType.KEPLERIAN);   //设置轨道类型
        propagator.addForceModel(holmesFeatherstoneAttractionModel);
        propagator.addForceModel(new NewtonianAttraction(keplerianOrbit.getMu()));
        propagator.addForceModel(new ThirdBodyAttraction(CelestialBodyFactory.getEarth()));
        propagator.addForceModel(new ThirdBodyAttraction(CelestialBodyFactory.getMoon()));
        propagator.addForceModel(new ThirdBodyAttraction(CelestialBodyFactory.getJupiter()));
        propagator.addForceModel(new ThirdBodyAttraction(CelestialBodyFactory.getMars()));

        propagator.setInitialState(new SpacecraftState(keplerianOrbit));
        //EphemerisGenerator generator = propagator.getEphemerisGenerator();
        //propagator.propagate(absoluteDate.shiftedBy(Time.daysToSeconds(Time.DAYS_PER_YEAR) * 1))
        //BoundedPropagator generatedEphemeris = generator.getGeneratedEphemeris();

        /*while (absoluteDate.isBefore(end)) {
            TimeStampedPVCoordinates pvc = propagator.propagate(absoluteDate).getPVCoordinates();
            Vector3D position = pvc.getPosition();
            Vector3D velocity = pvc.getVelocity();
            System.out.println("x: "+position.getX()+" y: "+position.getY()+" z:"+position.getZ());
            System.out.println("vx: "+velocity.getX()+" vy: "+velocity.getY()+" vz:"+velocity.getZ());
            System.out.println("--------------------------------------------------");
        }*/

        TimeStampedPVCoordinates pvc = propagator.propagate(absoluteDate).getPVCoordinates();
        Vector3D position = pvc.getPosition();
        Vector3D velocity = pvc.getVelocity();
        System.out.println("x: "+position.getX()+" y: "+position.getY()+" z:"+position.getZ());
        System.out.println("vx: "+velocity.getX()+" vy: "+velocity.getY()+" vz:"+velocity.getZ());
        System.out.println("--------------------------------------------------");

预报某一地面站能观测到某一卫星的时间

代码如下:

File file = new File("C:/SoftwareInstallationPackage/orekit-data-master/");
        DataProvidersManager manager = DataContext.getDefault().getDataProvidersManager();
        manager.addProvider(new DirectoryCrawler(file));
        // Initial state definition : date, orbit
        final AbsoluteDate initialDate = new AbsoluteDate(2023, 9, 15, 4, 0, 00.000, TimeScalesFactory.getUTC());
        final double mu = 3.986004415e+14; // gravitation coefficient
        final Frame inertialFrame = FramesFactory.getEME2000(); // inertial frame for orbit definition
        final Vector3D position = new Vector3D(2797914.567, -2288195.171, 6012468.374);
        final Vector3D velocity = new Vector3D(-6089.132, 2403.774, 3732.121);
        final PVCoordinates pvCoordinates = new PVCoordinates(position, velocity);
        final Orbit initialOrbit = new KeplerianOrbit(pvCoordinates, inertialFrame, initialDate, mu);

        // Earth and frame
        final Frame earthFrame = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
        final BodyShape earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
                Constants.WGS84_EARTH_FLATTENING, earthFrame);

        // Station
        final double longitude = FastMath.toRadians(75.9797);
        final double latitude = FastMath.toRadians(39.4547);
        final double altitude = 0.;
        final GeodeticPoint station1 = new GeodeticPoint(latitude, longitude, altitude);
        final TopocentricFrame sta1Frame = new TopocentricFrame(earth, station1, "喀什");

        // Defining rectangular field of view
        double halfApertureAlongTrack = FastMath.toRadians(50);
        double halfApertureAcrossTrack = FastMath.toRadians(50);

        FieldOfView fov = new DoubleDihedraFieldOfView(Vector3D.MINUS_I, // From satellite to body center
                Vector3D.PLUS_K, halfApertureAcrossTrack, // Across track direction
                Vector3D.PLUS_J, halfApertureAlongTrack, // Along track direction
                0); // Angular margin

        // Defining attitude provider
        AttitudeProvider attitudeProvider = new LofOffset(inertialFrame, LOFType.QSW);

        // Defining your propagator and setting up the attitude provider
        Propagator propagator = new KeplerianPropagator(initialOrbit);
        propagator.setAttitudeProvider(attitudeProvider);

        // Event definition
        final double maxcheck = 60.0;
        final double threshold = 0.001;
        final double elevation = FastMath.toRadians(5.0);
        final EventDetector sta1Visi = new ElevationDetector(maxcheck, threshold, sta1Frame)
                .withConstantElevation(elevation).withHandler((s, detector, increasing) -> {
                    if (increasing) {
                        System.out.println("Visibility begins on " + detector.getTopocentricFrame().getName() + " at "
                                + s.getDate());
                    } else {
                        System.out.println("Visibility ends on " + detector.getTopocentricFrame().getName() + " at "
                                + s.getDate());
                    }
                    return Action.CONTINUE; // Continue processing the event
                });

        // Add event to be detected
        propagator.addEventDetector(sta1Visi);

        // Propagate from the initial date to the first raising or for the fixed
        // duration
        final SpacecraftState finalState = propagator.propagate(initialDate.shiftedBy(14400.));

        System.out.println(" Final state : " + finalState.getDate().durationFrom(initialDate));

说明

final Frame earthFrame = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
final BodyShape earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
                Constants.WGS84_EARTH_FLATTENING, earthFrame);

上面代码是创建一个地球模型,参考系是地固系,OneAxisEllipsoid的参数一代表赤道半径,参数二代表扁平化,参数三代表参考系。

        final double longitude = FastMath.toRadians(75.9797);  //经度
        final double latitude = FastMath.toRadians(39.4547);   //纬度
        final double altitude = 0.;  //高度
        final GeodeticPoint station1 = new GeodeticPoint(latitude, longitude, altitude);
        final TopocentricFrame sta1Frame = new TopocentricFrame(earth, station1, "喀什");

上面代码是创建地面站

        double halfApertureAlongTrack = FastMath.toRadians(50);
        double halfApertureAcrossTrack = FastMath.toRadians(50);

        FieldOfView fov = new DoubleDihedraFieldOfView(Vector3D.MINUS_I, // From satellite to body center
                Vector3D.PLUS_K, halfApertureAcrossTrack, // Across track direction
                Vector3D.PLUS_J, halfApertureAlongTrack, // Along track direction
                0); // Angular margin

上面的代码是创建矩形的传感器

        // Defining attitude provider
        AttitudeProvider attitudeProvider = new LofOffset(inertialFrame, LOFType.QSW);

        // Defining your propagator and setting up the attitude provider
        Propagator propagator = new KeplerianPropagator(initialOrbit);
        propagator.setAttitudeProvider(attitudeProvider);

上面代码是预报器设置姿态信息

 // Event definition
        final double maxcheck = 60.0;
        final double threshold = 0.001;
        final double elevation = FastMath.toRadians(5.0);
        final EventDetector sta1Visi = new ElevationDetector(maxcheck, threshold, sta1Frame)
                .withConstantElevation(elevation).withHandler((s, detector, increasing) -> {
                    if (increasing) {
                        System.out.println("Visibility begins on " + detector.getTopocentricFrame().getName() + " at "
                                + s.getDate());
                    } else {
                        System.out.println("Visibility ends on " + detector.getTopocentricFrame().getName() + " at "
                                + s.getDate());
                    }
                    return Action.CONTINUE; // Continue processing the event
                });

        // Add event to be detected
        propagator.addEventDetector(sta1Visi);

轨道预报器设置卫星事件。ElevationDetector用来设置事件,其参数一代表最大间隔时间(秒),参数二代表收敛阈值(秒),参数三代表事件时间搜索的最大迭代次数.

使用HolmesFeatherstoneAttractionModel模型进行轨道预报

代码如下:

 File file = new File("C:/SoftwareInstallationPackage/orekit-data-master/");
        DataProvidersManager manager = DataContext.getDefault().getDataProvidersManager();
        manager.addProvider(new DirectoryCrawler(file));
        UTCScale utc = TimeScalesFactory.getUTC();
        AbsoluteDate initDate = new AbsoluteDate(2023, 9, 12, 04, 00, 00.000, utc);

        double a = 6675900;
        double e = 0.01256;
        double i = FastMath.toRadians(28.482);
        double omega = FastMath.toRadians(0);
        double rann = FastMath.toRadians(0);
        double mean = FastMath.toRadians(0);

        Orbit initOrbit = new KeplerianOrbit(a,e,i,omega,rann, mean, PositionAngle.MEAN,
                FramesFactory.getEME2000(), initDate,Constants.IERS2010_EARTH_MU);

        double dp = 1.0E-6;
        double minStep = 0.00001;
        double maxStep = 10000.0;
        ODEIntegrator integrator = new DormandPrince853IntegratorBuilder(minStep, maxStep, dp)
                .buildIntegrator(initOrbit, OrbitType.KEPLERIAN);

        // Initialize a NumericalPropagator
        NumericalPropagator propagator = new NumericalPropagator(integrator);
        propagator.setMu(Constants.EGM96_EARTH_MU);
        SpacecraftState initState = new SpacecraftState(initOrbit, 1000);
        propagator.setInitialState(initState);
        propagator.setPositionAngleType(PositionAngle.MEAN);

        // Create a HolmesFeatherstoneAttractionModel
        NormalizedSphericalHarmonicsProvider nshp = GravityFieldFactory.getNormalizedProvider(2, 0);
        HolmesFeatherstoneAttractionModel gravityField = new HolmesFeatherstoneAttractionModel(
                CelestialBodyFactory.getEarth().getBodyOrientedFrame(), nshp);

        // Add the force model
        propagator.addForceModel(gravityField);

        AbsoluteDate start = new AbsoluteDate(2023, 9, 12, 04, 00, 00.000, utc);
        AbsoluteDate end = new AbsoluteDate(2023, 9, 12, 05, 00, 00.000, utc);

        // Start forecasting    一分钟执行一次预报
        while (start.isBefore(end)){
            TimeStampedPVCoordinates pvCoordinates = propagator.getPVCoordinates(start, FramesFactory.getEME2000());
            System.out.println(pvCoordinates);
            start = start.shiftedBy(60);  
        }

以上仅是自己的学习笔记