Advice on the Usage of PolygonalFieldOfView Class

Greetings everyone :artificial_satellite:

I’ve been working around with different detectos and different FoV shapes for quite some time now and thanks to this amazing community, I’ve come so far with your help. Before moving on to other topics included in Orekit, I would like to consider a custom satellite FoV by using PolygonalFieldOfView method in the detection of an area-of-interest on the surface of earth.

Well as you know PolygonalFieldOfView method accepts a SphericalPolygonSet, which I manage to provide with latitude and longitute (similar to what I’ve used them to create an area-of-interest on earth). However, area crossings are somewhat off.

I think this is due to the fact that, as the satellite propagates in its orbit, this polygonal FoV is not moving with the satellite. I am not sure but this is inherently already calculated in other FoV methods such as CircularFieldOfView or DoubleDihedraFieldOfView.

Is there any way of overcoming this problem that you know of? Or should I somehow try to manage and update the footprint of the satellite FoV as it propagates through its orbit?

Any advice would be mostly appreciated, thank you in advance for valuable discussions :face_holding_back_tears:
Baris

Well unfortunately, the topic did not recieve any answers, however, in the meantime I’ve managed to discover few things. So basically what I’ve said above is not actually correct. The created PolygonalFieldOfView does move with the s/c.

Yet there is a peculiar thing here… The custom polygonal zone I created for FoV is slightly changed after I requested the corresponding footprints with getFootPrint method. The code snipped is as following:

# Create a random Field-Of-View
pattern = [(49.2715, -163.7803), (49.0127, -163.7604), (48.9927, -163.3820), 
           (49.2915, -163.382), (49.2715, -163.7803)]

geodeticPoints3 = []
for lat3, lon3 in pattern:
    geodeticPoints3.append(GeodeticPoint(radians(lat3), radians(lon3), 0.0))

fov_polygon = EllipsoidTessellator.buildSimpleZone(hyperplaneThickness, geodeticPoints3)

imagerFOV1 = PolygonalFieldOfView(fov_polygon, fov_margin)            # ← margin

sampling_step = 1000.0

# Define FootprintOverlapDetector and add it to the propagator
FPODetector = FootprintOverlapDetector(imagerFOV1, earth, 
                                        region_polygon0, 
                                        sampling_step).withHandler(ContinueOnEvent())

A custom zone for the FoV of the spacecraft is created with lat/long values given in pattern variable.

pos = []                                                       # position vector array to be filled.
footPrintList = []

print(initialDate)
###Start SGP4 propagation from initialDate up until finalDate
while (initialDate.compareTo(finalDate) <= 0.0):
    SGP4_pv = SGP4.getPVCoordinates(initialDate, ECI)          # Get PV coordinates
    posSGP4 = SGP4_pv.getPosition()                            # But we only want position vector.
    pos.append((posSGP4.getX(),posSGP4.getY(),posSGP4.getZ())) # Get individual elements of position
    posSGP4 = pos
    
    initialCartesianOrbit = CartesianOrbit(SGP4_pv, ECI, initialDate, Mu_earth)
    state = SpacecraftState(initialCartesianOrbit, satellite_mass)
    inertToBody = state.getFrame().getTransformTo(earth.getBodyFrame(), state.getDate())
    fovToBody = Transform(state.getDate(),
                      state.toTransform().getInverse(),
                      inertToBody)
    footprint = imagerFOV1.getFootprint(fovToBody, earth, radians(10.0))
    footPrintList.append(footprint)
    
    initialDate = initialDate.shiftedBy(60.0)                  # Propagate with 60 sec intervals.

The first element of the footPrintList array turns out to be the following lat/long values, which differ from what we entered as our custom zone at the first place:

[[{lat: 51.0573950815 deg, lon: -167.9919077077 deg, alt: 0}, 
  {lat: 51.0392380545 deg, lon: -167.9489124275 deg, alt: 0}, 
  {lat: 51.0577525 deg, lon: -167.9260072997 deg, alt: 0}, 
  {lat: 51.0777877091 deg, lon: -167.9765747604 deg, alt: 0}]]

Since the zone is changed here (somehow), my results become wrong. What causes this change, any ideas?

Hi @Echulion,

Sorry that no one answered your post, I guess it’s a bit of a hard question.

Speaking of that, I’m not sure I fully understand what you’re trying to achieve.

Beware that the FoV are “defined on the unit sphere centered on the spacecraft” (excerpt from Javadoc).
But here you define it using lat/lon as if it was a zone around Earth.

And then you project this polygonal FoV on ground at a given date on the orbit.

To be frank I don’t even understand how you came so close to the original zone you were looking for, unless your spacecraft frame happens to be somehow anti-aligned with the Earth frame at this date ?

Could you define a bit more what you’re trying to achieve ?
And/or provide a fully working code for this ?

Maxime

Hello @MaximeJ, thanks for your reply! This problem was really giving me trouble :face_with_spiral_eyes:

I was working with different FoV detectors. While I managed to utilize all other detector types, I was stuck at PolygonalFieldOfView method.

So step by step what I am trying to do is:

  • I create a zone-of-interest on the surface of the earth.
  • Then I define my satellite, propagator etc etc.
  • Finally I again create a zone for the FoV of the satellite at a specific time (which is defined from a set of geodetic points).
  • Then I set up the FootPrintOverlapDetector method to check if the satellites PolygonalFieldOfView enters the defined zone-of-interest or not.

As you said for other FoV methods such as CircularFieldOfView and DoubleDihedraFieldOfView we do not need lat/long values when defining them. However, for PolygonalFieldOfView, we require these geodetic points.

The polygonal FoV I created in my code is this:

fovpattern = [(49.5122, -163.1627), (49.5122, -163.9141), (48.9301, -163.9141), 
                     (48.9301, -163.1627), (49.5122, -163.1627)]

But when I try to check whether my created FoV is really correct or not (via the code bit I shared in my previous reply), I get these coordinates:

[[{lat: 51.0573950815 deg, lon: -167.9919077077 deg, alt: 0}, 
  {lat: 51.0392380545 deg, lon: -167.9489124275 deg, alt: 0}, 
  {lat: 51.0577525 deg, lon: -167.9260072997 deg, alt: 0}, 
  {lat: 51.0777877091 deg, lon: -167.9765747604 deg, alt: 0}]]

Which are not aligning with what I created with the fovpattern at that specific time.

I am also sharing my full code in Jupyter Notebook since I was working on that environment. I am hoping that it would clarify things better.
Footprint Detector Polygon FoV.ipynb (70.3 KB)

Thank you for your time and valuable discussions @MaximeJ :face_holding_back_tears:
Baris

You are very welcome @Echulion.

What I meant to say before is that, if you look closely at the Javadoc of PolygonalFieldOfView, the ‘zone’ you need to define must be defined on the unit sphere centered on the spacecraft, not on Earth ellipsoid.

So it seems like you’re defining a geographical zone on Earth but then you’re actually using the GeodeticPoints on a fictitious ellipsoid centered on the Spacecraft, which, I think, cannot make sense.

That being said, I may be wrong, I’ll look into your code when I have time.

Maxime

1 Like

Hi @Echulion ,

I think you have been misled by the SphericalPolygonSet parameter. In the case of the GeographicZoneDetector, it allows to define a geographic area on the Earth, while for the PolygonalFieldOfView, it defines the field of view as a cap on a sphere centered on the satellite.

1 Like

Hello @MaximeJ,

Thank you yes. I’ve already skimmed through the Javadoc you shared, but I may have missed some crucial points since I have no knowledge in Java. I will definitely examine it in detail and make the most of it. By the way, the following constructor:

PolygonalFieldOfView(Vector3D center, PolygonalFieldOfView.DefiningConeType coneType, Vector3D meridian, double radius, int n, double margin)

works perfectly well which uses the frame unit sphere centered on the spacecraft inherently.

I think I understand what you mean. My polygon fovpattern should not be on the Earth ellipsoid. So I wish to use the following constructor,

PolygonalFieldOfView(SphericalPolygonsSet zone, double margin)

and inside this method, SphericalPolygonsSet must be defined on the unit sphere centered on the spacecraft. This raises another question in my mind. How can I define a zone (on the unit sphere centered on the s/c) at a specific time which corresponds to the polygonal FoV (as a zone or footprint, however we can call it) I desire on the surface of the Earth ellipsoid? Because in the end, we are interested in with the zone on the surface of the Earth ellipsoid, not on the unit sphere centered on the s/c.

I wish you a great week, thanks!
Baris

Hello @Echulion,

If you want to find out when a specific geographic zone is in the field of view of your satellite sensor then you should probably use a FootprintOverlapDetector.

Is that what you are looking for ?
Maxime

Unfortunately no, that is not what I am looking for. Let me try to express myself in another way. In the below code snipped, I’ve created imagerFOV2 with the second constructor included in PolygonalFieldOfView, which works perfectly well. As you can see, I tried to access to the zone of imagerFOV2, just to use it in the first constructor given in PolygonalFieldOfView, which also works perfectly well.

imagerFOV2 = PolygonalFieldOfView(Vector3D.PLUS_K,
                    PolygonalFieldOfView.DefiningConeType.OUTSIDE_CONE_TOUCHING_POLYGON_AT_VERTICES,
                     Vector3D.PLUS_I,radians(3.0), 6, 0.0)

imagerFOV1 = PolygonalFieldOfView(imagerFOV2.getZone(), fov_margin)

Now, what I want to do is, using the aforementioned first constructor I would like to define the zone as geodetic points (lat/long/alt) if possible. If not, how can I define this zone? Is there any example in your possession?

Thanks!
Baris

The discussion that is held here also solved the issue mentioned in this post. Those who are having similar problem can refer to that post together with this one. :upside_down_face: