Observations from satellite

Hi!

Few months ago I had a problem with writing a script for detecting satellites from Earth-based station with given FoV. You all guys were very helpful and it worked like a charm (thread for reference). Now I’m trying to elevate this script a bit - I want to change this old script to carry out simulations with satellite-based observer. Let’s say I have a TLE for particular satellite and there is some sort of camera on this telescope with known FoV (lets say its rectangular 5x5degrees FoV directed straight ahead). Also I have a list of TLEs for every LEO satellite. How do I define frames, measurements, and FoV for this task?

Hi @jlipinski,

Orekit does not support angular space-based measurements, it’s something we would actually like to have so contribution are welcome ! :slight_smile:
There’s an issue already opened on the forge for this.
And several threads on the forum:

I think a FieldOfViewDetector should work, with targetPVProvider the TLE propagator of your target object.

Hope this helps,
Maxime

1 Like

Thank you for the tips! I’ll let you know if I make progress.

Thanks @MaximeJ for quick response. I’ll look into it but I don’t think my skills are sufficent enough for meaningful contribution :sweat_smile:

What if I only wanted to calculate the number of other satellites in satellite-based FoV, without knowing the exact space-based angular measurements, I feel like there should be an easy workaround for this.

EDIT:
Sorry, I have some problems with expressing my problem accurately. Right now I want to check how many other satellites would be visible from satellite based detector. I assume it is possible by combining InterSatDirectViewDetector with FieldOfViewDetector. I’m using DoubleDihedraFieldOfView but how spacecraft frame of reference is defined? PLUS_I is in the direction of movement, MINUS_K is towards Earth and J is perpendicular?

And the biggest issue I have is how to set up propagator having my target spacecraft TLE propagator and secondary spacecraft TLE propagator so that later I can use EventBasedScheduler to get ITRF position of secondary spacecraft.

EDIT 2:
I think it will be much easier with some code:

I have a primary TLE (the one with sensor) PmTLE and secondary (the one I am trying to observe) sTLE

First I constructed propagators:

TLEPropagator PmPropagator = TLEPropagator.selectExtrapolator(PmTLE);
TLEPropagator sPropagator = TLEPropagator.selectExtrapolator(sTle);

Then FieldOfViewDetector (sph2car is simple method for conversion from spherical to cartesian):

double[] coords = Sph2Car(phi, theta, r);
double x = coords[0];
double y = coords[1];
double z = coords[2];

Vector3D center = new Vector3D(x, y, z);
Vector3D axis2 = Vector3D.crossProduct(Vector3D.PLUS_K, center).normalize();
Vector3D axis1 = Vector3D.crossProduct(axis2, center).normalize();

double ha1 = FastMath.toRadians(width/2.);
double ha2 = FastMath.toRadians(height/2.);

DoubleDihedraFieldOfView fov = new DoubleDihedraFieldOfView(
    center, axis1, ha1, axis2, ha2, 0.0
);

FieldOfViewDetector fovd = new FieldOfViewDetector(
    PmPropagator, fov
).withHandler(new ContinueOnEvent<>())

And then I don’t really understand how to use InterSatDirectViewDetector. Ideally I would want to combine them using BooleanDetector like this (earth is defined earlier as OneAxisEllipsoid):

InterSatDirectViewDetector isdvd = new InterSatDirectViewDetector(earth, sPropagator);
BooleanDetector detector = BooleanDetector.andCombine(fovd, isdvd);

But then I have a problem with constructing generator and scheduler:

final Generator generator = new Generator();
ObservableSatellite sat = generator.addPropagator(???Propagator);

PositionBuilder PosBuilder = new PositionBuilder(
            null, 0., 1., sat
);

EventBasedScheduler<Position> scheduler = new EventBasedScheduler<>(
             PosBuilder, new FixedStepSelector(60.0, TimeScalesFactory.getUTC()),
             ???Propagator, detector,
             SignSemantic.FEASIBLE_MEASUREMENT_WHEN_POSITIVE
);

generator.addScheduler(scheduler);

SortedSet<ObservedMeasurement<?>> data = generator.generate(t0, t1);

I don’t really undestand which propagator to use in those instances and if this approach is even correct for this problem.

Hi @jlipinski,

You can define S/C frame using a specific AttitudeProvider in your propagator.
For example, supposing that inertialFrame is the propagation frame and prop is the propagator:

AttitudeProvider attProv = new LofOffset(inertialFrame, LOFType.TNW);
prop.setAttitudeProvider(attProv);

This will align X (or PLUS_I) with velocity, Z (or PLUS_K) with the orbital momentum and Y will be perpendicular.
Here to see more about LOFTypes.

That could work but you have to negate the FieldOfViewDetector because it’s g function is negative when target is in FOV (see more for example here about combining detectors and sign of g).

You need to add the primary propagator (the one with the camera).
You cannot use PositionBuilder it will return the position of the primary.
You have to implement your own measurements and builder.
The structure of the measurement class would be just like an InterSatelliteRange but instead of computing the range you simply return the PV of the secondary object.

Does this help ?

Thanks very much. Yes. this helps a lot but still I can’t fully grasp this problem and in testing I found few new ones.

First, I tried using InterSatelliteRange and InterSatelliteRangeBuilder as for know I’m more intrested in a number of detected satellites, (type of measurements is a problem for future me). So I have constructed propagotors and scheduler like this (detectors set up as in posts above):

TLEPropagator PmPropagator = TLEPropagator.selectExtrapolator(PmTLE);
AttitudeProvider attProv = new LofOffset(EME, LOFType.TNW);
PmPropagator.setAttitudeProvider(attProv);

TLEPropagator spropagator = TLEPropagator.selectExtrapolator(sTle);

BooleanDetector detector = BooleanDetector.andCombine(BooleanDetector.notCombine(fovd), isdvd);

final Generator generator = new Generator();
ObservableSatellite PmSat = generator.addPropagator(PmPropagator);
ObservableSatellite sSat = generator.addPropagator(sPropagator);

InterSatellitesRangeBuilder RangeBuilder = new InterSatellitesRangeBuilder(
   null, PmSat, sSat, false, 0., 1.
);

EventBasedScheduler<InterSatellitesRange> scheduler = new EventBasedScheduler<>(
    RangeBuilder, new FixedStepSelector(60.0, TimeScalesFactory.getUTC()),
    PmPropagator, detector,
    SignSemantic.FEASIBLE_MEASUREMENT_WHEN_POSITIVE
);
generator.addScheduler(scheduler);

SortedSet<ObservedMeasurement<?>> data = generator.generate(t0, t1);

Unfortunately this results in Exception in thread "main" org.orekit.errors.OrekitException: java.lang.StackOverflowError. I narrowed down the cause to FieldOfViewDetector as without it it seems to generate just fine (although it freezes for some TLEs).

Hi @jlipinski,

If you look at the method InterSatellitesRangeBuilderTest.doTest, you’ll see a comment on the IntersatFieldOfViewDetector construction:

        // beware that in order to avoid deadlocks, the secondary PV coordinates provider
        // in InterSatDirectViewDetector must be *different* from the second propagator
        // added to generator above! The reason is the event detector will be bound
        // to the first propagator, so it cannot also refer to the second one at the same time
        // this is the reason why we create a *new* KeplerianPropagator below

I think that may be the cause of your issue.
You need to use an “independent” propagator for the secondary object in your InterSatDirectViewDetector. By independent I mean not the same one that you add to the generator when doing: ObservableSatellite sSat = generator.addPropagator(sPropagator);

If it doesn’t work please send us a runnable program (preferably a Junit test) because it’s hard to debug this kind of exception without actually running the code.

Hope this helps,
Maxime

@MaximeJ
Yes, I think that was it. I made second propagtor and used it in FieldOfViewDetector and InterSatDirectViewDetector and it worked.

Also, while I was writing my own measurement class I thought why can’t I just use PositionBuilder and supply it with secondary ObservableSatellite, something like this:

# Propagators
 
TLEPropagator PmPropagator = TLEPropagator.selectExtrapolator(PmTLE);
AttitudeProvider attProv = new LofOffset(EME, LOFType.TNW);
PmPropagator.setAttitudeProvider(attProv);

TLEPropagator sPropagator = TLEPropagator.selectExtrapolator(sTle);
TLEPropagator sPropagator2 = TLEPropagator.selectExtrapolator(sTle);

# Detectors
Vector3D center = Vector3D.PLUS_I;
Vector3D axis2 = Vector3D.PLUS_K;
Vector3D axis1 = Vector3D.PLUS_J;

double ha1 = FastMath.toRadians(width/2.);
double ha2 = FastMath.toRadians(height/2.);

DoubleDihedraFieldOfView fov = new DoubleDihedraFieldOfView(
   center, axis1, ha1, axis2, ha2, 0.0
);

FieldOfViewDetector fovd = new FieldOfViewDetector(
   sPropagator2, fov
).withHandler(new ContinueOnEvent<>()).withMaxCheck(15.0);

InterSatDirectViewDetector isdvd = new InterSatDirectViewDetector(
   earth, sPropagator2
);
   
BooleanDetector detetector = BooleanDetector.andCombine(
   isdvd, BooleanDetector.notCombine(fovd)
);

# Generator, measurements builder and scheduler
final Generator generator = new Generator();
ObservableSatellite PmSat = generator.addPropagator(PmPropagator);
ObservableSatellite sSat = generator.addPropagator(sPropagator);

PositionBuilder PosBuilder = new PositionBuilder(null, 0., 1., sSat);

EventBasedScheduler<Position> scheduler = new EventBasedScheduler<>(
   PosBuilder, new FixedStepSelector(60.0, TimeScalesFactory.getUTC()),
   PmPropagator, detector,
   SignSemantic.FEASIBLE_MEASUREMENT_WHEN_POSITIVE
);

generator.addScheduler(scheduler);

SortedSet<ObservedMeasurement<?>> data = generator.generate(t0, t1);

I don’t get any unusual exceptions with this code and positions are looking fine at first glance.

@jlipinski you are right I didn’t think of it but that should actually work ! Nice catch

Hey,
after hiatus I came back to work on this problem. I manage to put together a working (I think) modified Eclipse Detector so that it requires a PVCoordinatesProvider during initialization and check if this provider is in shadow. Now I have yet another problem. During observations I want to avoid having Sun in my field of view. Moreover, it is not enough to check if a spacecraft is not in Earth’s shadow, I need to check if it is not illuminated from behind. I found the easiest solution is to just calculate Sun position in spacecraft frame and check its X coordinate, if it’s negative that means Sun is behind my spacecraft. Unfortunately I’m not really sure how to do that. I tried to follow this tutorial to no avail. I tried writing it like this:

Vector3D sunPosition = sun.getPVCoordinates(date, PmPropagator.getFrame()).getPosition();

or like this:

LocalOrbitalFrame localSCFrame = new LocalOrbitalFrame(EME, LOFType.TNW, PmPropagator, "SCFrame");
Vector3D sunPosition = sun.getPVCoordinates(date, localSCFrame).getPosition();

both methods don’t work (the latter freezes completely). I’m sure I just don’t understand something about transforming position to different frames.

Ok, I just assumed that when you set AttitudeProvider to propagator then it changes the Frame of the propagator. Finally I used the code from Frames tutorial to calculate Sun position in spacecraft frame and used it to create a detector that checks if Sun is behind spacecraft. For anyone interested this is the code for g function of this detector:

public double g(SpacecraftState s) {
        AbsoluteDate date = s.getDate();
        PVCoordinates sCoords = s.getPVCoordinates();
        Transform transform = LOFType.TNW.transformFromInertial(date, sCoords);
        Vector3D sunInert = sun.getPVCoordinates(date, EME).getPosition();
        Vector3D sunPos = transform.transformPosition(sunInert);
        if (sunPos.getX() > 0) {
            return -1;
        }
        else {
            return 1;
        }
    }
1 Like

Hi @jlipinski and thank you for showing us your code !

I’m dropping by to suggest to slightly modify the function to make it continuous. You could simply return the x component of the sunPos vector (or the opposite value of it depending on desired behaviour) instead of using an if-else condition.

I’m recommending this because Orekit will try to bracket the exact moment in time where g = 0.

Cheers,
Vincent