BurstSelector.java
- /* Copyright 2002-2025 CS GROUP
- * Licensed to CS GROUP (CS) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * CS licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.orekit.time;
- import java.util.ArrayList;
- import java.util.List;
- import org.hipparchus.util.FastMath;
- /** Selector generating high rate bursts of dates separated by some rest period.
- * <p>
- * The dates can be aligned to whole steps in some time scale. So for example
- * if a rest period of 3600s is used and the alignment time scale is set to
- * {@link org.orekit.time.TimeScales#getUTC() UTC}, the earliest date of
- * each burst will occur at whole hours in UTC time.
- * </p>
- * <p>
- * BEWARE! This class stores internally the last selected dates, so it is <em>neither</em>
- * reusable across several {@link org.orekit.estimation.measurements.generation.EventBasedScheduler
- * fixed step} or {@link org.orekit.estimation.measurements.generation.ContinuousScheduler
- * continuous} schedulers, <em>nor</em> thread-safe. A separate selector should be used for each
- * scheduler and for each thread in multi-threading context.
- * </p>
- * @author Luc Maisonobe
- * @since 9.3
- */
- public class BurstSelector implements DatesSelector {
- /** Maximum number of selected dates in a burst. */
- private final int maxBurstSize;
- /** Step between two consecutive dates within a burst. */
- private final double highRateStep;
- /** Period between the start of each burst. */
- private final double burstPeriod;
- /** Alignment time scale (null is alignment is not needed). */
- private final TimeScale alignmentTimeScale;
- /** First date in last burst. */
- private AbsoluteDate first;
- /** Last selected date. */
- private AbsoluteDate last;
- /** Index of last selected date in current burst. */
- private int index;
- /** Simple constructor.
- * <p>
- * The {@code burstPeriod} ignores the duration of the burst itself. This
- * means that if burst of {@code maxBurstSize=256} dates each separated by
- * {@code highRateStep=100ms} should be selected with {@code burstPeriod=300s},
- * then the first burst would contain 256 dates from {@code t0} to {@code t0+25.5s}
- * and the second burst would start at {@code t0+300s}, <em>not</em> at
- * {@code t0+325.5s}.
- * </p>
- * <p>
- * If alignment to some time scale is needed, it applies only to the first date in
- * each burst.
- * </p>
- * @param maxBurstSize maximum number of selected dates in a burst
- * @param highRateStep step between two consecutive dates within a burst (s)
- * @param burstPeriod period between the start of each burst (s)
- * @param alignmentTimeScale alignment time scale for first date in burst
- * (null is alignment is not needed)
- */
- public BurstSelector(final int maxBurstSize, final double highRateStep,
- final double burstPeriod, final TimeScale alignmentTimeScale) {
- this.maxBurstSize = maxBurstSize;
- this.highRateStep = highRateStep;
- this.burstPeriod = burstPeriod;
- this.alignmentTimeScale = alignmentTimeScale;
- this.last = null;
- this.first = null;
- this.index = 0;
- }
- /** {@inheritDoc} */
- @Override
- public List<AbsoluteDate> selectDates(final AbsoluteDate start, final AbsoluteDate end) {
- final int increment = end.durationFrom(start) > 0 ? +1 : -1;
- final int firstIndex = increment > 0 ? 0 : maxBurstSize - 1;
- final int lastIndex = maxBurstSize - 1 - firstIndex;
- final double signedHighRateStep = FastMath.copySign(highRateStep, increment);
- final double signedBurstPeriod = FastMath.copySign(burstPeriod, increment);
- final List<AbsoluteDate> selected = new ArrayList<>();
- final boolean reset = first == null || increment * start.durationFrom(first) > burstPeriod;
- if (reset) {
- first = null;
- index = firstIndex;
- }
- for (AbsoluteDate next = reset ? start : last.shiftedBy(signedHighRateStep);
- increment * next.durationFrom(end) <= 0;
- next = last.shiftedBy(signedHighRateStep)) {
- if (index == lastIndex + increment) {
- // we have exceeded burst size, jump to next burst
- next = first.shiftedBy(signedBurstPeriod);
- first = null;
- index = firstIndex;
- if (increment * next.durationFrom(end) > 0) {
- // next burst is out of current interval
- break;
- }
- }
- if (first == null && alignmentTimeScale != null) {
- // align earliest burst date to time scale
- final double offset = firstIndex * highRateStep;
- final double t = next.getComponents(alignmentTimeScale).getTime().getSecondsInLocalDay() - offset;
- final double dt = burstPeriod * FastMath.round(t / burstPeriod) - t;
- next = next.shiftedBy(dt);
- while (index != lastIndex && increment * next.durationFrom(start) < 0) {
- next = next.shiftedBy(signedHighRateStep);
- index += increment;
- }
- if (increment * next.durationFrom(start) < 0) {
- // alignment shifted date out of interval
- next = next.shiftedBy(signedBurstPeriod - (maxBurstSize - 1) * signedHighRateStep);
- index = firstIndex;
- }
- }
- if (increment * next.durationFrom(start) >= 0) {
- if (increment * next.durationFrom(end) <= 0) {
- // the date is within range, select it
- if (first == null) {
- first = next.shiftedBy(-signedHighRateStep * index);
- }
- selected.add(next);
- } else {
- // we have exceeded date range
- break;
- }
- }
- last = next;
- index += increment;
- }
- return selected;
- }
- }