Satellite footprint when beam pointed to specific ground station

I’d found this post and implemented it with NadirPointing

As expected it results in a circle below the spacecraft.

On a spacecraft with flat panels or mechanically steered dishes the beam can be pointed to a target ground station without changing satellite attitude.

How could I alter the code from the linked question such that the resulting location isn’t tied to satellite attitude but instead by a ground station target location?

Hi @JarrodSears welcome!

This can be achieved by twicking the fovToBody Transform that is passed as first argument to the getFootprint call.

As written in the post you refer too (and also in various test methods in PolygonalFieldOfViewTest), this transform is computed directly from satellite state (i.e. taking into account attitude between satellite frame and inertial frame), combined with body frame (i.e Earth orientation with respect to inertial frame). If you were using a polygonal field of view, I would have suggested to start from this and append the transform between satellite frame and sensor frame taking the steering mechanism behavior into account. However, since you have a circular field of view, there is a much simpler approach: compute the Line Of Sight vector from satellite to ground target in Earth frame and then compute the rotation that transform fov central vector (say Z axis for example) to this vector . This would be something along these lines:

  Vector3D targetEarth = earth.transform(geodeticPoint); // this can be computed once as it does not depend on date
  Vector3D losEarth    = target.subtract(spacecraftState.getPosition(earth.getBodyFrame()));
  Transform fovToBody  = new Transform(date, new Rotation(Vector3D.Z, losEarth));

Dear Orekit community,
@luc and @JarrodSears

I wanted to ask a similar question, but since someone has just asked it, I would not open a new Topic. I’d like to determine the time when the ISS enters the field of view of a specified point on the ground.

I don’t fully understand the physics behind it yet, but I’m working on it. :slight_smile:

Based on the answer, I created a code, but I get an error. @luc could you please take a look at it, I tried to do what you wrote. Unfortunately, I still don’t fully understand it, so I’m not sure if I succeeded :slight_smile: :slight_smile:

Here is my code

// ISS
        TLE tle = new TLE(
                "1 25544U 98067A   23208.30934329  .00015800  00000+0  28347-3 0  9998",
                "2 25544  51.6413 129.7314 0000554  64.5675  79.5453 15.50079229408012",

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

        // predict
        final TLEPropagator propagator = TLEPropagator.selectExtrapolator(tle);
        AbsoluteDate target = new AbsoluteDate(new Date(), TimeScalesFactory.getUTC());
        SpacecraftState state = propagator.propagate(target);
        Vector3D satPoint = state.getPVCoordinates().getPosition();
        GeodeticPoint geoPoint = earth.transform(satPoint, state.getFrame(), state.getDate());

//        Transform inertToBody = state.getFrame().getTransformTo(earthFrame, state.getDate());

//        Transform fovToBody = new Transform(state.getDate(),
//                state.toTransform().getInverse(),
//                inertToBody);

        //create gps point on earth frame
        final double longitude = FastMath.toRadians(48.21791046918412);
        final double latitude  = FastMath.toRadians(16.397910223220432);
        final double altitude  = 0.;

        GeodeticPoint gpsPoint = new GeodeticPoint(latitude, longitude, altitude);
        Vector3D targetEarth = earth.transform(gpsPoint); // this can be computed once as it does not depend on date
        Vector3D losEarth    = targetEarth.subtract(state.getPVCoordinates(earthFrame).getPosition());
        Transform fovToBody  = new Transform(target, new Rotation(Vector3D.PLUS_K, losEarth));

        CircularFieldOfView cfov =
                new CircularFieldOfView(Vector3D.PLUS_K, FastMath.toRadians(50.), 0.);

        List<List<GeodeticPoint>> footprint =
                cfov.getFootprint(fovToBody, (OneAxisEllipsoid) earth, 0.1);

        List<GeodeticPoint> list = footprint.get(0);
        for (GeodeticPoint point : list) {
            System.out.println("[" + FastMath.toDegrees(point.getLongitude()) + "," +
                    FastMath.toDegrees(point.getLatitude()) + "],");

and exception:
Exception in thread “main” org.orekit.errors.OrekitException: point is inside ellipsoid

Could you tell me which point is inside the ellipsoid and why?

I have one more question.
I tried to calculate the field of view based on the following article: Field of View Sat Event Detector Example
I started with Evan’s code and used TLE propagator to define the orbit. The values I got weren’t appropriate and I found this post.

I think that both solutions could be used to determine getting into the field of view. (Am I getting this right?)
How do the two implementations differ?

Thank you for your help in advance. Looking forward to your reply.

I think I made an error and you found it!
With what I suggested, fovToBody is a simple rotation, without a translation, so its origin is at the center of the Earth. This origin is used in the first few lines of getFootprint, as it was supposed to be centered on satellite. Obviously, the center of the Earth is within the Earth :woozy_face:

So you have to create a Transform that is a composition of two lower level transforms: the rotation I already mentioned, and a translation that accounts for satellite position. The trick is to put them in the correct order and direction.

Beware also that a fov centered on a satellite and a field of view centered on a ground point are really different things.

Are there examples available in the documentation or elsewhere that show how this would be done?

Not really…

Try this:

  Transform fovToBody  = new Transform(date,
                                       new Transform(date, spacecraftState.getPosition(earth.getBodyFrame()).negate()),
                                       new Transform(date, new Rotation(Vector3D.Z, losEarth));

I’m not sure I got it in the correct direction and composition order though.

I’ve checked this problem and verified it.

 #get current Date
  date = self.endState.getDate()
 #Caculate the los in ECF frame
  target_geodeticPoint = GeodeticPoint(FastMath.toRadians(pos_lat), FastMath.toRadians(pos_lon), 0.0);
  targetEarth =
  los_sat2target_ecf   = targetEarth.subtract(self.endState.getPVCoordinates(self.earthFrame).getPosition())
  #get the transform from J2000 to ECF
  inertToBody = self.endState.getFrame().getTransformTo(, date)
  #get the transform from satellite body frame to ECF frame
  satBody2ecf = Transform(date, self.endState.toTransform().getInverse(), inertToBody)
  #transform the los into the satellite body frame

Then ,you can use this vector in for example getfootprint().

  fov = CircularFieldOfView(losPointing_body, math.radians(alpha),  math.radians(margin))
  footprint=fov.getFootprint(bodyToECF, earth, 0.1)

Good Luck!

1 Like

Thank you! That worked great. I converted it to java and added some conversions to JTS objects and used those to output GeoJSON. I included the full setup of the ground station location, the Keplerian orbit, propagator, etc for a geostationary satellite to make it easy.

I went ahead and threw that code into an examples project here:

1 Like