Define a rectangular field of view

Hello, I have encountered an issue. I am preparing to define a sensor for an observing satellite, and its observation shape(field of view) is a rectangle, which is defined in STK by vertical half-angle and horizontal half-angle. Could you please explain which libraries in Orekit can be used to define this?

Hi @YangYang,

To define a rectangular field of view, you can use the DoubleDihedraFieldOfView class (see the documentation here).

Also, be mindful of the AttitudeProvider you will be using ! For example, NadirPointing only define the z direction of your satellite but not the rotation around this axis which will impact your results with a rectangular field of view.

Hope i was of help !

Cheers,
Vincent

Can you provide a specific code example? I tried many times, but couldn’t succeed.

Perhaps one easier mode if you need fine-tuning your attitude is to use LofOffset.
This mode starts from one of the Local Orbital Frame (see LOFType for predefined ones, but you could also add you own as LOF is an interface you can implement). Once the Local Orbital Frame is defined, the LofOffset mode performs three rotations from there, in any order you specify (it could be X then Y then Z, or Z then Y then X, or any other order). So you can have select where the field of view points at will.

Hi @YangYang,

As @luc said, one of the easiest attitude provider to implement is LofOffset which will align the satellite with one of the predefined local orbital frame defined in LOFType. I don’t know if you are working using the develop branch, if that’s not the case, you will not see the LOF interface as it will be implementend in the soon to be released 12.0 version of Orekit.

Below is a short sample code of how you should do it :

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

       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_INERTIAL);

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

Here i’m using the QSW(=RTN) LOFType, X is along the body center to satellite center direction, Z along the orbital momentum vector and Y completes the frame.

Cheers,
Vincent

Thank you for your reply. I’ll give it a try

Thank you for your reply. I’ll give it a try

Now I have imported the code you gave me, but after running it, I found that the running result was the same as before the addition of AttributeProvider. I would like to ask where the problem lies, and how to use the advisor with FOV correctly?

final File home = new File(System.getProperty(“user.home”));
final 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 %s, unzip it in %s and rename it ‘orekit-data’ for this tutorial to work%n”,
“orekit-data-master.zip”,
https://gitlab.orekit.org/orekit/orekit-data/-/archive/master/orekit-data-master.zip”,
home.getAbsolutePath());
System.exit(1);
}
final DataProvidersManager manager = DataContext.getDefault().getDataProvidersManager();
manager.addProvider(new DirectoryCrawler(orekitData));

	// 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.EQW);

	// 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));

Hi @YangYang,

Ok, thanks to your code i get the bigger picture and what goes wrong.

First of all, you are using :

Which is the only almost pseudo inertial frame among the local orbital frames :sweat_smile:. You should use the QSW or TNW one.

Then you create the field of view, but does not use it in any way. It will not be taken into account as it is.

Finally, and according to what i can see, i believe that you want to check if you can see a ground station with your field of view ? If so, then you have two choices :
1- Stick to the fov attached to your satellite and use a FieldOfViewDetector (see documentation) combined with an ElevationDetector (see documentation). The process is explained in the documentation of FieldOfViewDetector :

“in an Earth Observation context, it can be easily combined to an ElevationDetector using BooleanDetector.andCombine(java.util.Collection) to calculate station visibility opportunities within the satellite’s field of view.”

“Why combine detectors ?” you may ask, because FieldOfViewDetector does not take into accounts occulting bodies so it will see your station even when it is on the opposite side of the Earth, hence the ElevationDetector combination. This way it will only see your ground station when it can actually see it.

2 - Either take the problem the other way around and attach a field of view to your ground station through a GroundFieldOfViewDetector (see documentation) or simply use an ElevationDetector.

I believe this shall fix everything :+1:

Cheers,
Vincent

Thank you for your reply,I will try to examine and modify my code.
Best wishes!

1 Like

Hello, as the second method does not meet my usage requirements, I have attempted to use the first method you provided (Stick to the fov attached to your satellite and use a FieldOfViewDetector (see documentation) combined with an ElevationDetector (see documentation) T) Attempted to combine ElevationDetector and FieldOfViewDetector using Boolean Detector. andCombine (java. util. Collection), but I encountered some issues. I don’t know how to call the relevant methods at all. Can you provide specific code? Can you continue to modify based on my code?
Thank you, best wishes!

Hello, as the second method does not meet my usage requirements, I have attempted to use the first method you provided (Stick to the fov attached to your satellite and use a FieldOfViewDetector (see documentation) combined with an ElevationDetector (see documentation) T) Attempted to combine ElevationDetector and FieldOfViewDetector using Boolean Detector. andCombine (java. util. Collection), but I encountered some issues. I don’t know how to call the relevant methods at all. Can you provide specific code? Can you continue to modify based on my code?
Thank you, best wishes!