Example #1
0
  /**
   * Get the predicted quantization-event time for a state (QSS-specific).
   *
   * @param stateIdx The state index.
   * @param quantEvtTimeMax The maximum quantization event time.
   */
  protected final Time _predictQuantizationEventTimeWorker(
      final int stateIdx, final Time quantEvtTimeMax) {

    // Note the superclass takes care of updating status variables and
    // storing the returned result.

    // Initialize.
    final ModelPolynomial qStateMdl = _qStateMdls[stateIdx];
    final ModelPolynomial cStateMdl = _cStateMdls[stateIdx];
    final double dq = _dqs[stateIdx];

    // Check internal consistency.
    assert (dq > 0);
    assert (quantEvtTimeMax.getDoubleValue() > 0);
    assert (quantEvtTimeMax.compareTo(qStateMdl.tMdl) > 0);
    assert (quantEvtTimeMax.compareTo(cStateMdl.tMdl) > 0);

    // Find predicted quantization-event time, as change from {tMostRecent}.
    Time tMostRecent;
    double dt;
    if (qStateMdl.tMdl.compareTo(cStateMdl.tMdl) > 0) {
      // Here, most recent event was a quantization-event.
      tMostRecent = qStateMdl.tMdl;
      dt = _predictQuantizationEventDeltaTimeQSS2QFromC(qStateMdl, cStateMdl, dq, _exactInputs);
    } else {
      // Here, most recent event was a rate-event.
      tMostRecent = cStateMdl.tMdl;
      dt = _predictQuantizationEventDeltaTimeQSS2General(qStateMdl, cStateMdl, dq, _exactInputs);
    }

    // Require {dt} > 0.
    if (dt <= 0) {
      // In exact arithmetic, and if the integrator is being stepped properly,
      // this should never happen.  However, if the integrator stepped to a
      // time very close to the previous predicted quantization-event time,
      // or given a small numerator and large denominator in expressions
      // above, can get nonpositive {dt}.
      //   Reset to as small a value as can manage.
      //   Use the `ulp`, the "units in the last place".  From the
      // documentation at {http://docs.oracle.com/javase/7/docs/api/java/lang/Math.html}:
      // "For a given floating-point format, an ulp of a specific real
      // number value is the distance between the two floating-point
      // values bracketing that numerical value."
      // TODO: Construct integrator with "min time step" parameter,
      // and pass it in for use it here.
      dt = java.lang.Math.ulp(tMostRecent.getDoubleValue());
    }

    // Bound result to reasonable limits.
    //   At lower end, need a positive number that, when added to {tMostRecent},
    // produces a distinct time.
    //   At upper end, can't be larger than {quantEvtTimeMax}.
    Time predQuantEvtTime;
    while (true) {
      if (quantEvtTimeMax.subtractToDouble(tMostRecent) <= dt) {
        // Here, tMostRecent + dt >= quantEvtTimeMax.
        //   Note determined this case in a slightly roundabout way, since
        // simply adding {dt} to {tMostRecent} may cause problems if {quantEvtTimeMax}
        // reflects some inherent limitation of class {Time}.
        predQuantEvtTime = quantEvtTimeMax;
        break;
      }
      // Here, tMostRecent + dt < quantEvtTimeMax.
      predQuantEvtTime = tMostRecent.addUnchecked(dt);
      if (predQuantEvtTime.compareTo(tMostRecent) > 0) {
        // Here, added {dt} and got a distinct, greater, time.
        break;
      }
      // Here, {dt} so small that can't resolve difference from {tMostRecent}.
      dt *= 2;
    }

    return (predQuantEvtTime);
  }