Generate CPF AZEL measurements from list of dates

Hi!
I have a list of dates for which I’m trying to generate altaz measurements based on CPF data from EDC. My first approach was something like this:

...
earth = OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, 
                         Constants.WGS84_EARTH_FLATTENING, 
                         itrf)

station = GeodeticPoint(math.radians(lat), math.radians(lon), elevation)
topo = TopocentricFrame(earth, station, "topo")
alts = [ ]
azs = [ ]
distance = [ ]
times = list_of_dates
for t in times:
    absdate = datetime_to_absolutedate(t)
    state = prop.propagate(absdate)
    pvInit = state.getPVCoordinates()
    frame = state.getFrame()

    alt = np.degrees(topo.getElevation(pvInit.getPosition(), frame, absdate))
    az = np.degrees(topo.getAzimuth(pvInit.getPosition(), frame, absdate))
    distance = topo.getRange(pvInit.getPosition(), frame, absdate)

    alts.append(alt)
    azs.append(az)
    distances.append(distance)

And I think it works ok, but I read somewhere that I should use AngularAzElBuilder for that kind of things, so I tried but I have no idea how to create scheduler that would allow me to generate measurements for given dates:

err = 1e-5
altazError = [err, err]
altazWeight = [1.0, 1.0]
covariance = MatrixUtils.createRealDiagonalMatrix([err**2, err**2, err**2, err**2, err**2, err**2])
random_vector = CorrelatedRandomVectorGenerator(covariance, 1.0e-10, GaussianRandomGenerator(MersenneTwister()))
obs_sat   = ObservableSatellite(0)
generator = Generator()
generator.addPropagator(prop)
absdates = [datetime_to_absolutedate(t) for t in times]
azelBuilder = AngularAzElBuilder(random_vector, ground_station, altazError, altazWeight, obs_sat)

generator.addScheduler(???)

meas = generator.generate(absdates[0], absdates[-1])

Is this approach valid and/or better than the first one? And if it’s better how to approach this problem?

The measurements generation feature is depicted here. There are two existing schedulers provided by Orekit: ContinuousScheduler and EventBasedScheduler. The first one generates uninterrupted lists of measurements regardless of station and satellite relative position, so you may end up with measurements below the horizon. The second one generates measurements only when some conditions triggered by event detectors allow it. This is the most often used scheduler, and it is often configured with events detectors based on satellite visibility from the measurement receiver (ground station, other satellite…).

Yes, but my problem is that I don’t have any fixed step or continuous dates. To be honest, I’m working with observations of some LEO satellites (with available CPFs) that I need to verify. Timing of these observations does not follow any specific pattern.

As I mentioned, propagating the state to a chosen absolute date seems to work fine, but I’m not sure if that’s the correct approach.

The scheduler documentation for both ContinousScheduler and EventBasedScheduler mentions a “repetitive pattern,” which I don’t have. So, is there a way to use AngularAzElBuilder to generate AzEl measurements for a discrete set of dates?

Hi,

I guess you could still use a DateDetector with a bunch of dates.

Cheers,
Romain.

Thanks for the suggestion!
I realized that I never shared how I create my propagator — maybe there’s an error there:

DS = DataSource(path_to_cpf)
parser = CPFParser()
cpf = parser.parse(DS)
sat_eph = cpf.getSatellites().get(cpf.getHeader().getIlrsSatelliteId())
prop = sat_eph.getPropagator()

I tried something like this: first, I created my own date selector class to always return a list of my dates:

@JImplements(DatesSelector)
class myDateSelector():
    def __init__(self, dates):
        self.absdates = ArrayList()
        for t in dates:
            self.absdates.add(t)
    
    @JOverride
    def init(self, start, end):
        pass

    @JOverride
    def selectDates(self, s, e):
        return self.absdates

Then, I created a DateDetector with the same dates and used it to create an EventBasedScheduler:

absdates = [datetime_to_absolutedate(t) for t in times]
detector = DateDetector(0.1, absdates[0]).withHandler(ContinueOnEvent())
for t in absdates[1:]:
    detector.addEventDate(t)
date_selector = myDateSelector(absdates)
scheduler = EventBasedScheduler(azelBuilder, date_selector, prop, detector, SignSemantic.FEASIBLE_MEASUREMENT_WHEN_POSITIVE)
generator.addScheduler(scheduler)
meas = generator.generate(absdates[0], absdates[-1])

Unfortunately, this doesn’t work. There are no exceptions or warnings, but meas is always NoneType and empty. I’m not sure if the issue is related to SignSemantic — I’ve tried both POSITIVE and NEGATIVE, but it made no difference.

What am I doing wrong?

EDIT
So I discovered that you need a subscriber now to store measurements, so I added a subscriber:

subscriber = GatheringSubscriber()
generator.addSubscriber(subscriber)
generator.generate(absdates[0], absdates[-1])
 
for i in subscirber.getGeneratedMeasurements():
    print(np.rad2deg(i.getObservedMeasurement().getObservedValue()[0]))
    print(np.rad2deg(i.getObservedMeasurement().getObservedValue()[1]))
    print(i.getObservedMeasurement().getDate())

And it somewhat works, but I get many more generated measurements than initial dates, and the number of measurements is not constant, it is different with every time I run the script.

Hello @jlipinski, I am in the process of developing something similar to this for our needs.

In your DateDetector instantiation in use with the Event based Scheduler, did you make sure that the minGap argument is smaller than the smallest time delta between adjacent obs? The documentation for DateDetector reads:

The gap between the added dates must be more than the minGap.

You can use the method withMinGap(double newMinGap) to set the minGap parameter. Half of your smallest obs delta should be ok?

In my case, I didn’t use an EventBasedScheduler because of the unclear semantic definition of the Date Detector. I used a ContinuousScheduler and I created a custom DatesSelector implementation accepting a list of observation times. ContinuousScheduler doesn’t seem to require any type of pattern but always considers feasible measurements based on what the DatesSetector implementation does (I would love to be corrected). Here is my implementation of the DatesSelector instantiated with a List<AbsoluteDate> in Java. The runs were consistent and simulated measurements were exaclty the same in number at all times.

public class IrregularDatesSelector implements DatesSelector {
  private final List<AbsoluteDate> dates;

  public IrregularDatesSelector(final List<AbsoluteDate> dates) {
    this.dates = new ArrayList<>(dates);
    Collections.sort(this.dates);
  }

  @Override
  public List<AbsoluteDate> selectDates(final AbsoluteDate start, final AbsoluteDate end) {
    final List<AbsoluteDate> selected = new ArrayList<>();
    final boolean forward = end.durationFrom(start) > 0;

    for (final AbsoluteDate date : dates) {
      if (forward) {
        if (date.isAfterOrEqualTo(start) && date.isBeforeOrEqualTo(end)) {
          selected.add(date);
        }
      } else {
        if (date.isBeforeOrEqualTo(start) && date.isAfterOrEqualTo(end)) {
          selected.add(date);
        }
      }
    }

    return selected;
  }
}

Thank you very much!

That was exactly the problem. I was fixated on using EventBasedScheduler, which caused issues with DateDetector. However, using my DatesSelector as defined in the post above, along with ContinuousScheduler, worked like a charm. I think I was too focused on the documentation’s description that ContinuousScheduler follows a repetitive pattern to even give it a try.

1 Like