FoV/FoV Detector Usage Problems

Hi all,

I am using the FoV Detector to find the time range when a point on earth is visible to the sensor on the spacecraft. However, the pass duration I get as a result is longer than I expect (I expect ~10s but get ~1.5 minutes).

I assume that this is caused by a misconfiguration of the FoV/FoV Detector but I did not figure out what I do wrong.

That’s my FoV declaration (rectangle, 5 degrees):

    final double viewAngle = 5.0;
    
    final var fov = new FieldOfView(Vector3D.PLUS_K, 
        Vector3D.PLUS_I, FastMath.toRadians(viewAngle / 2),
        Vector3D.PLUS_J, FastMath.toRadians(viewAngle / 2),
        0);

The FoV Detector:

final var tcf = new TopocentricFrame(earth, point, "point");
final var detector = new FieldOfViewDetector(tcf, fov).withMaxCheck(maxCheckingInterval).withHandler(new EventHandler<FieldOfViewDetector>() {

      private AbsoluteDate start;
      
      @Override
      public Action eventOccurred(SpacecraftState s, FieldOfViewDetector detector,
          boolean increasing) throws OrekitException {
        
        if (increasing) {
          // Leaving Area
          
          final var end = s.getDate();
          
          System.out.println("Pass duration: " + end.durationFrom(start));
          
          return Action.CONTINUE;
        } else {
          // Entering Area
          
          start = s.getDate();
          
          return Action.CONTINUE;
        }
}});

The propagation:

    final var logger = new EventsLogger();

    final var propagator = TLEPropagator.selectExtrapolator(...);

    final var attitudeProvider = new NadirPointing(propagator.getFrame(), earth);
    
    propagator.setAttitudeProvider(attitudeProvider);
    propagator.addEventDetector(logger.monitorDetector(detector));
    propagator.propagate(startDate, endDate);

Is there something wrong how I utilize the FoV/FoV Detector?

Thanks,
Jan

1 Like

The way you use this detector is correct. I think you have found a bug in Orekit!
Looking back at the test case for FieldOfViewDetector, the test pass but the way
it is written is wrong, we failed to notice the detector did not work properly since
at least version 7.2 :fearful:

Could you open a bug report at https://gitlab.orekit.org/orekit/orekit/issues ?

If you could add your own test configuration to the bug report (with your FoV definition, attitude definition,
the TLE data and the search time range), it would help us a lot.

I looked again at the test and improved it, but the library behavior was in fact correct in this
case, so I am not sure anymore there is a bug. We need to have some data to check.

Could you try to copy the dihedraAngles/dihedraAngle functions from https://gitlab.orekit.org/orekit/orekit/blob/develop/src/test/java/org/orekit/propagation/events/FieldOfViewDetectorTest.java#L170 and
call them in your code to monitor the angles and see when your target crosses the FoV boundary?

Thank you for your answers!

I have implemented the dihedraAngle methods to monitor the angles. For reference, this is the pass I find:

Pass Start:    2018-11-20T03:51:13.836;
Pass End:      2018-11-20T03:54:03.062;
Pass duration: 169.22639302270034

These are the angles in the relevant time frame: angles.dat (18.1 KB)

If I am not mistaken, the boundaries of the FoV are 2.5 degress (~0.0436 rad). When I look through the list of angles, I cannot see that the target crosses the FoV boundary. Does this help?

I have also attached the code snipped with the TLE data to test:

The Snipped

    final var tle = new TLE("1 33314U 08040C   18325.13536407  .00000020  00000-0  93127-5 0  9993",
        "2 33314  97.7735  35.5590 0025404 105.4992 254.9034 14.79911945552555");
    
    final var startDate = new AbsoluteDate(2018, 11, 20, 3, 0, 0, TimeScalesFactory.getUTC());
    final var endDate = new AbsoluteDate(2018, 11, 20, 4, 0, 0, TimeScalesFactory.getUTC());

    final var maxCheckingInterval = 5.0;

    final var ecef = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
    final var earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
        Constants.WGS84_EARTH_FLATTENING, ecef);

    final double viewAngle = 5.0;

    final var fov = new FieldOfView(Vector3D.PLUS_K, Vector3D.PLUS_I,
        FastMath.toRadians(viewAngle / 2), Vector3D.PLUS_J, FastMath.toRadians(viewAngle / 2), 0);

    final var point = new GeodeticPoint(40.205842983848484, -92.58639608631753, 40.205842983848484);
    
    final var tcf = new TopocentricFrame(earth, point, "point");
    final var detector = new FieldOfViewDetector(tcf, fov).withMaxCheck(maxCheckingInterval)
        .withHandler(new EventHandler<FieldOfViewDetector>() {

          private AbsoluteDate start;

          @Override
          public Action eventOccurred(SpacecraftState s, FieldOfViewDetector detector,
              boolean increasing) throws OrekitException {

            if (increasing) {
              // Leaving Area

              final var end = s.getDate();

              final var duration = end.durationFrom(start);
              
              System.out.println("Pass duration: " + duration);

              return Action.CONTINUE;
            } else {
              // Entering Area

              start = s.getDate();

              return Action.CONTINUE;
            }
          }
        });

    final var logger = new EventsLogger();

    final var propagator = TLEPropagator.selectExtrapolator(tle);

    final var attitudeProvider = new NadirPointing(propagator.getFrame(), earth);

    propagator.setAttitudeProvider(attitudeProvider);
    propagator.addEventDetector(logger.monitorDetector(detector));
    propagator.propagate(startDate, endDate);

It seems like that I detect my point on the Earth from the other side of the Earth. Is there a way to ensure that the spacecraft is not looking through the Earth?

Hi,
You should try to define your geodetic point with values in radians, it seems like you define it from degrees.
With your data taken as radians, the point is really on the other side of the Earth.

Hi Pascal,

thank you for your hint. I have already found this issue and I am now using radians :slight_smile:

I am also printing the coordinates of the spacecraft when entering/leaving the FoV. Then I can clearly see, that the long passes occurr when the spacecraft is on the other side of the earth, e.g.: (target point is lat 40.205842983848484 deg, -92.58639608631753 deg

ENTERED AREA: Coordinates: {lat: -34.3587029374 deg, lon: 82.1396448256 deg, alt: 649,328.5215795665}
LEFT AREA: Coordinates: {lat: -35.7311629575 deg, lon: 81.7684635422 deg, alt: 650,284.1510598025}
Pass Start: 2018-11-22T04:33:09.362; Pass End: 2018-11-22T04:33:31.961; Pass duration: 22.599076402965427

ENTERED AREA: Coordinates: {lat: 40.0049667931 deg, lon: -92.4574443255 deg, alt: 626,048.0720118146}
LEFT AREA: Coordinates: {lat: 40.4853524324 deg, lon: -92.6020127858 deg, alt: 626,022.2770822175}
Pass Start: 2018-11-23T04:06:39.104; Pass End: 2018-11-23T04:06:46.982; Pass duration: 7.877661127777468

Now I need basically a way to distinguish those passes. Is there already something in Orekit that does the trick?

The easiest way is to combine your FieldOfViewDetector with an ElevationDetector thanks to the BooleanDetector. You could try something like:

final FieldOfViewDetector fd = new FieldOfViewDetector(tcf, fov);
final ElevationDetector ed = new ElevationDetector(tcf).withConstantElevation(0.);
final BooleanDetector detector = BooleanDetector.andCombine(ed, BooleanDetector.notCombine(fd)).withMaxCheck(maxCheckingInterval).withHandler(new EventHandler<BooleanDetector>() {
    private AbsoluteDate start;
    @Override
    public Action eventOccurred(SpacecraftState s, BooleanDetector detector, boolean increasing) throws OrekitException {
        if (increasing) {
            // Entering Area
            start = s.getDate();
            return Action.CONTINUE;
        } else {
            // Leaving Area
            final double duration = s.getDate().durationFrom(start);
            System.out.println("Pass duration: " + duration);
            return Action.CONTINUE;
        }
    }
});

Note that the boolean combination of the detectors requires to change the sign of the g function from the FieldOfViewDetector, which is done through BooleanDetector.notCombine(fd).

With your data, no pass is found, but with a wider timespan, I’ve got the following pass:

Start visibility: 2018-11-23T04:06:39.373
End visibility: 2018-11-23T04:06:47.250
Pass duration: 7.877595829517514

Thank you for your help. I wasn’t aware of the ElevationDetector. And thank you for the explanations regarding the g function sign :slight_smile:

That solved my problem :partying_face:

You’re welcome. Glad I could help.

Hi!I have been reading about this post.It’s useful to my work.
But I have a problem,when compute the access of a sensor on a satellite to a sation on the ground.Why do we bind the fov to the station frame rather than the satellite frame?

 final var tcf = new TopocentricFrame(earth, point, "point");
    final var detector = new FieldOfViewDetector(tcf, fov).withMaxCheck(maxCheckingInterval)
        .withHandler(new EventHandler<FieldOfViewDetector>()

Hi! I think the TopocentricFrame is used here only as a provider for the target PVCoordinates. The fov is attached to the spacecraft frame in the evaluation of the detector during the propagation

Hello, I am having a similar issue. I have the same goal, but using that method I get no passes. Could you please see here? Visibility of Location with FOV

In looking through the FieldOfViewDetector API documentation, the switching function is defined as becoming negative when a target enters the FOV, and then back positive again when the target leaves. (So, negative response with FOV inclusion.)

In opposition, the ElevationDetector is worded more cryptically, but appears to switch positive when its target (satellite in this case) is above the elevation threshold.

However, the BooleanDetector.andCombine function expects to AND two positive switching functions (which the FOV detector is not). Therefore, I believe it might be necessary to use the BooleanDetector.notCombine function on the FOV detector before applying it to the elevation combination for correct usage in this case.

Thoughts? Am I correct?

If so, perhaps there might be some examples that may also require this fix.

Thanks!

You are correct about the signs. For elevation detector, the sign of the g function is just satellite elevation minus mask (i.e. profile of the surroundings, like mountains, as seen from the ground station), hence it is positive when satellite is visible.

So you are also correct for the combination: you need to use notCombine on the FOV detector.