BurstSelector.java

  1. /* Copyright 2002-2025 CS GROUP
  2.  * Licensed to CS GROUP (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.time;

  18. import java.util.ArrayList;
  19. import java.util.List;

  20. import org.hipparchus.util.FastMath;


  21. /** Selector generating high rate bursts of dates separated by some rest period.
  22.  * <p>
  23.  * The dates can be aligned to whole steps in some time scale. So for example
  24.  * if a rest period of 3600s is used and the alignment time scale is set to
  25.  * {@link org.orekit.time.TimeScales#getUTC() UTC}, the earliest date of
  26.  * each burst will occur at whole hours in UTC time.
  27.  * </p>
  28.  * <p>
  29.  * BEWARE! This class stores internally the last selected dates, so it is <em>neither</em>
  30.  * reusable across several {@link org.orekit.estimation.measurements.generation.EventBasedScheduler
  31.  * fixed step} or {@link org.orekit.estimation.measurements.generation.ContinuousScheduler
  32.  * continuous} schedulers, <em>nor</em> thread-safe. A separate selector should be used for each
  33.  * scheduler and for each thread in multi-threading context.
  34.  * </p>
  35.  * @author Luc Maisonobe
  36.  * @since 9.3
  37.  */
  38. public class BurstSelector implements DatesSelector {

  39.     /** Maximum number of selected dates in a burst. */
  40.     private final int maxBurstSize;

  41.     /** Step between two consecutive dates within a burst. */
  42.     private final double highRateStep;

  43.     /** Period between the start of each burst. */
  44.     private final double burstPeriod;

  45.     /** Alignment time scale (null is alignment is not needed). */
  46.     private final TimeScale alignmentTimeScale;

  47.     /** First date in last burst. */
  48.     private AbsoluteDate first;

  49.     /** Last selected date. */
  50.     private AbsoluteDate last;

  51.     /** Index of last selected date in current burst. */
  52.     private int index;

  53.     /** Simple constructor.
  54.      * <p>
  55.      * The {@code burstPeriod} ignores the duration of the burst itself. This
  56.      * means that if burst of {@code maxBurstSize=256} dates each separated by
  57.      * {@code highRateStep=100ms} should be selected with {@code burstPeriod=300s},
  58.      * then the first burst would contain 256 dates from {@code t0} to {@code t0+25.5s}
  59.      * and the second burst would start at {@code t0+300s}, <em>not</em> at
  60.      * {@code t0+325.5s}.
  61.      * </p>
  62.      * <p>
  63.      * If alignment to some time scale is needed, it applies only to the first date in
  64.      * each burst.
  65.      * </p>
  66.      * @param maxBurstSize maximum number of selected dates in a burst
  67.      * @param highRateStep step between two consecutive dates within a burst (s)
  68.      * @param burstPeriod period between the start of each burst (s)
  69.      * @param alignmentTimeScale alignment time scale for first date in burst
  70.      * (null is alignment is not needed)
  71.      */
  72.     public BurstSelector(final int maxBurstSize, final double highRateStep,
  73.                          final double burstPeriod, final TimeScale alignmentTimeScale) {
  74.         this.maxBurstSize       = maxBurstSize;
  75.         this.highRateStep       = highRateStep;
  76.         this.burstPeriod        = burstPeriod;
  77.         this.alignmentTimeScale = alignmentTimeScale;
  78.         this.last               = null;
  79.         this.first              = null;
  80.         this.index              = 0;
  81.     }

  82.     /** {@inheritDoc} */
  83.     @Override
  84.     public List<AbsoluteDate> selectDates(final AbsoluteDate start, final AbsoluteDate end) {

  85.         final int    increment          = end.durationFrom(start) > 0 ? +1 : -1;
  86.         final int    firstIndex         = increment > 0 ? 0 : maxBurstSize - 1;
  87.         final int    lastIndex          = maxBurstSize - 1 - firstIndex;
  88.         final double signedHighRateStep = FastMath.copySign(highRateStep, increment);
  89.         final double signedBurstPeriod  = FastMath.copySign(burstPeriod, increment);

  90.         final List<AbsoluteDate> selected = new ArrayList<>();

  91.         final boolean reset = first == null || increment * start.durationFrom(first) > burstPeriod;
  92.         if (reset) {
  93.             first = null;
  94.             index = firstIndex;
  95.         }

  96.         for (AbsoluteDate next = reset ? start : last.shiftedBy(signedHighRateStep);
  97.              increment * next.durationFrom(end) <= 0;
  98.              next = last.shiftedBy(signedHighRateStep)) {

  99.             if (index == lastIndex + increment) {
  100.                 // we have exceeded burst size, jump to next burst
  101.                 next  = first.shiftedBy(signedBurstPeriod);
  102.                 first = null;
  103.                 index = firstIndex;
  104.                 if (increment * next.durationFrom(end) > 0) {
  105.                     // next burst is out of current interval
  106.                     break;
  107.                 }
  108.             }

  109.             if (first == null && alignmentTimeScale != null) {
  110.                 // align earliest burst date to time scale
  111.                 final double offset = firstIndex * highRateStep;
  112.                 final double t      = next.getComponents(alignmentTimeScale).getTime().getSecondsInLocalDay() - offset;
  113.                 final double dt     = burstPeriod * FastMath.round(t / burstPeriod) - t;
  114.                 next = next.shiftedBy(dt);
  115.                 while (index != lastIndex && increment * next.durationFrom(start) < 0) {
  116.                     next = next.shiftedBy(signedHighRateStep);
  117.                     index += increment;
  118.                 }
  119.                 if (increment * next.durationFrom(start) < 0) {
  120.                     // alignment shifted date out of interval
  121.                     next  = next.shiftedBy(signedBurstPeriod - (maxBurstSize - 1) * signedHighRateStep);
  122.                     index = firstIndex;
  123.                 }
  124.             }

  125.             if (increment * next.durationFrom(start) >= 0) {
  126.                 if (increment * next.durationFrom(end) <= 0) {
  127.                     // the date is within range, select it
  128.                     if (first == null) {
  129.                         first = next.shiftedBy(-signedHighRateStep * index);
  130.                     }
  131.                     selected.add(next);
  132.                 } else {
  133.                     // we have exceeded date range
  134.                     break;
  135.                 }
  136.             }
  137.             last   = next;
  138.             index += increment;

  139.         }

  140.         return selected;

  141.     }

  142. }