private float getRampLength(float totalLen, RosterSpeedProfile speedProfile) { float speed = 0.0f; float rampLength = 0.0f; int numSteps = 0; while (speed < _maxSpeed) { float dist; if (speedProfile != null) { dist = speedProfile.getSpeed((speed + _minSpeed / 2), _forward.isSelected()) * _intervalTime / 1000; } else { dist = (speed + _minSpeed / 2) * _intervalTime * _throttleFactor; } if (rampLength + dist <= totalLen / 2) { if ((speed + _minSpeed) > _maxSpeed) { dist = dist * (_maxSpeed - speed) / _minSpeed; speed = _maxSpeed; } else { speed += _minSpeed; } rampLength += dist; numSteps++; if (log.isDebugEnabled()) { log.debug( "step " + numSteps + " dist= " + dist + " speed= " + speed + " rampLength = " + rampLength); } } else { // cannot get to _maxSpeed and have enough length to decelerate _maxSpeed = speed; // modify break; } } // add the smidge of distance needed to reach _maxSpeed // rampLength += (_maxSpeed - speed)*_intervalTime*_throttleFactor; if (log.isDebugEnabled()) { log.debug( numSteps + " speed steps of delta= " + _minSpeed + " for rampLength = " + rampLength + " to reach speed " + _maxSpeed); } return rampLength; }
private String makeCommands(Warrant w) { int nextIdx = 0; // block index - increment after getting a block order List<BlockOrder> orders = getOrders(); BlockOrder bo = orders.get(nextIdx++); String blockName = bo.getBlock().getDisplayName(); w.addThrottleCommand(new ThrottleSetting(0, "F0", "true", blockName)); if (_forward.isSelected()) { w.addThrottleCommand(new ThrottleSetting(1000, "Forward", "true", blockName)); w.addThrottleCommand(new ThrottleSetting(1000, "F2", "true", blockName)); w.addThrottleCommand(new ThrottleSetting(2500, "F2", "false", blockName)); w.addThrottleCommand(new ThrottleSetting(1000, "F2", "true", blockName)); w.addThrottleCommand(new ThrottleSetting(2500, "F2", "false", blockName)); } else { w.addThrottleCommand(new ThrottleSetting(1000, "Forward", "false", blockName)); w.addThrottleCommand(new ThrottleSetting(2000, "F3", "true", blockName)); w.addThrottleCommand(new ThrottleSetting(500, "F3", "false", blockName)); w.addThrottleCommand(new ThrottleSetting(500, "F3", "true", blockName)); w.addThrottleCommand(new ThrottleSetting(500, "F1", "true", blockName)); } // estimate for blocks of zero length - an estimate of ramp length boolean isForward = _forward.isSelected(); jmri.jmrit.roster.RosterEntry ent = getTrain(); RosterSpeedProfile speedProfile = null; if (ent != null) { speedProfile = ent.getSpeedProfile(); if (speedProfile != null) { float s = speedProfile.getSpeed(_maxSpeed, isForward); if (log.isDebugEnabled()) { log.debug("SpeedProfile _maxSpeed setting= " + _maxSpeed + " speed= " + s + "mps"); } if (s <= 0.0f || s == Float.POSITIVE_INFINITY) { speedProfile = null; } } } if (log.isDebugEnabled()) { log.debug( "throttle Factor= " + _throttleFactor + " from " + (speedProfile != null ? "SpeedProfile" : "Default")); } float defaultBlockLen = 6 * _maxSpeed * _intervalTime / _throttleFactor; // just a wild guess float totalLen = getTotalLength(defaultBlockLen); float rampLength = getRampLength(totalLen, speedProfile); float blockLen = bo.getPath().getLengthMm(); // length of path in current block if (blockLen <= 0) { blockLen = defaultBlockLen; } blockLen /= 2; // start train float speedTime = 500; // ms time to complete speed step from last block float noopTime = 0; // ms time for entry into next block float curSpeed = 0; // each speed step will last for _intervalTime ms float curDistance = 0; // distance traveled in current block float remRamp = rampLength; if (log.isDebugEnabled()) { log.debug( "Start Ramp Up in block \"" + blockName + "\" in " + (int) speedTime + "ms, remRamp= " + remRamp + ", blockLen= " + blockLen); } while (remRamp > 0.0f) { // ramp up loop if (speedProfile != null) { curDistance = speedProfile.getSpeed(curSpeed, isForward) * speedTime / 1000; } else { curDistance = curSpeed * speedTime * _throttleFactor; } while (curDistance < blockLen && curSpeed < _maxSpeed) { float dist; if (speedProfile != null) { dist = speedProfile.getSpeed((curSpeed + _minSpeed / 2), isForward) * _intervalTime / 1000; } else { dist = (curSpeed + _minSpeed / 2) * _intervalTime * _throttleFactor; } float prevSpeed = curSpeed; if ((curSpeed + _minSpeed) > _maxSpeed) { dist = dist * (_maxSpeed - curSpeed) / _minSpeed; curSpeed = _maxSpeed; } else { curSpeed += _minSpeed; } if (curDistance + dist <= blockLen && remRamp > 0.0f) { curDistance += dist; remRamp -= dist; w.addThrottleCommand( new ThrottleSetting((int) speedTime, "Speed", Float.toString(curSpeed), blockName)); if (log.isDebugEnabled()) { log.debug(" dist= " + dist); } if (log.isDebugEnabled()) { log.debug( "Ramp Up in block \"" + blockName + "\" to speed " + curSpeed + " in " + (int) speedTime + "ms to reach curDistance= " + curDistance + " with remRamp= " + remRamp); } speedTime = _intervalTime; } else { curSpeed = prevSpeed; break; } } // Possible case where curDistance can exceed the length of a block that was just entered. // Move to next block and adjust the distance times into that block if (speedProfile != null) { if (curDistance >= blockLen) { noopTime = Math.round( 1000 * speedProfile.getDurationOfTravelInSeconds( isForward, curSpeed, Math.round(blockLen))); // time to next block speedTime = Math.round( 1000 * speedProfile.getDurationOfTravelInSeconds( isForward, curSpeed, Math.round(curDistance - blockLen))); } else { noopTime = Math.round( 1000 * speedProfile.getDurationOfTravelInSeconds( isForward, curSpeed, Math.round(blockLen - curDistance))); speedTime = _intervalTime - noopTime; // time to next speed change } } else { if (curDistance >= blockLen) { noopTime = (blockLen) / (curSpeed * _throttleFactor); // time to next block speedTime = (curDistance - blockLen) / (curSpeed * _throttleFactor); } else { noopTime = (blockLen - curDistance) / (curSpeed * _throttleFactor); // time to next block speedTime = _intervalTime - noopTime; // time to next speed change } } // break out here if deceleration is to be started in this block if (totalLen - blockLen <= rampLength || curSpeed >= _maxSpeed) { break; } if (remRamp > 0.0f && nextIdx < orders.size()) { totalLen -= blockLen; if (log.isDebugEnabled()) { log.debug( "Leave RampUp block \"" + blockName + "\" noopTime= " + noopTime + ", in distance=" + curSpeed * noopTime * _throttleFactor + ", blockLen= " + blockLen + ", remRamp= " + remRamp); } bo = orders.get(nextIdx++); blockName = bo.getBlock().getDisplayName(); blockLen = bo.getPath().getLengthMm(); if (blockLen <= 0) { blockLen = defaultBlockLen; } w.addThrottleCommand(new ThrottleSetting((int) noopTime, "NoOp", "Enter Block", blockName)); if (log.isDebugEnabled()) { log.debug( "Enter block \"" + blockName + "\" noopTime= " + noopTime + ", blockLen= " + blockLen); } } } if (log.isDebugEnabled()) { log.debug( "Ramp Up done at block \"" + blockName + "\" curSpeed=" + "" + curSpeed + ", blockLen= " + blockLen + " totalLen= " + totalLen + ", rampLength= " + rampLength + ", remRamp= " + remRamp); } if (totalLen - blockLen > rampLength) { totalLen -= blockLen; if (nextIdx < orders.size()) { // not the last block bo = orders.get(nextIdx++); blockName = bo.getBlock().getDisplayName(); blockLen = bo.getPath().getLengthMm(); if (blockLen <= 0) { blockLen = defaultBlockLen; } w.addThrottleCommand(new ThrottleSetting((int) noopTime, "NoOp", "Enter Block", blockName)); if (log.isDebugEnabled()) { log.debug( "Enter block \"" + blockName + "\" noopTime= " + noopTime + ", blockLen= " + blockLen); } curDistance = 0; } // run through mid route at max speed while (nextIdx < orders.size() && totalLen - blockLen > rampLength) { totalLen -= blockLen; // constant speed, get time to next block if (speedProfile != null) { noopTime = Math.round( 1000 * speedProfile.getDurationOfTravelInSeconds( isForward, curSpeed, Math.round(blockLen - curDistance))); } else { noopTime = (blockLen - curDistance) / (curSpeed * _throttleFactor); } if (log.isDebugEnabled()) { log.debug( "Leave MidRoute block \"" + blockName + "\" noopTime= " + noopTime + ", curDistance=" + curDistance + ", blockLen= " + blockLen + ", totalLen= " + totalLen); } bo = orders.get(nextIdx++); blockName = bo.getBlock().getDisplayName(); blockLen = bo.getPath().getLengthMm(); if (blockLen <= 0) { blockLen = defaultBlockLen; } if (nextIdx == orders.size()) { blockLen /= 2; } w.addThrottleCommand(new ThrottleSetting((int) noopTime, "NoOp", "Enter Block", blockName)); if (log.isDebugEnabled()) { log.debug( "Enter block \"" + blockName + "\" noopTime= " + noopTime + ", blockLen= " + blockLen); } curDistance = 0; } } // else Start ramp down in current block // Ramp down. use negative delta remRamp = rampLength; if (speedProfile != null) { speedTime = Math.round( 1000 * speedProfile.getDurationOfTravelInSeconds( isForward, curSpeed, Math.round(totalLen - rampLength))); } else { speedTime = (totalLen - rampLength) / (curSpeed * _throttleFactor); } curDistance = totalLen - rampLength; if (log.isDebugEnabled()) { log.debug( "Begin Ramp Down at block \"" + blockName + "\" curDistance= " + curDistance + " SpeedTime= " + (int) speedTime + "ms, blockLen= " + blockLen + ", totalLen= " + totalLen + ", rampLength= " + rampLength + " curSpeed= " + curSpeed); } while (curSpeed > 0) { if (nextIdx == orders.size()) { // at last block if (_stageEStop.isSelected()) { w.addThrottleCommand(new ThrottleSetting(0, "Speed", "-0.5", blockName)); _intervalTime = 0; break; } } do { float dist; float nextSpeed = Math.max(curSpeed - _minSpeed, 0); if (speedProfile != null) { dist = speedProfile.getSpeed((curSpeed + nextSpeed) / 2, isForward) * _intervalTime / 1000; } else { dist = (curSpeed + nextSpeed) / 2 * _intervalTime * _throttleFactor; } curDistance += dist; curSpeed = nextSpeed; remRamp -= dist; w.addThrottleCommand( new ThrottleSetting((int) speedTime, "Speed", Float.toString(curSpeed), blockName)); if (log.isDebugEnabled()) { log.debug( "Ramp Down in block \"" + blockName + "\" to speed " + curSpeed + " in " + (int) speedTime + "ms to reach curDistance= " + curDistance + " with remRamp= " + remRamp); } if (curDistance >= blockLen) { if (speedProfile != null) { speedTime = Math.round( 1000 * speedProfile.getDurationOfTravelInSeconds( isForward, curSpeed, Math.round(curDistance - blockLen))); } else { speedTime = (curDistance - blockLen) / (curSpeed * _throttleFactor); } } else { speedTime = _intervalTime; } noopTime = _intervalTime - speedTime; } while (curDistance < blockLen && curSpeed > 0); if (nextIdx < orders.size()) { totalLen -= blockLen; if (log.isDebugEnabled()) { log.debug( "Leave RampDown block \"" + blockName + "\" noopTime= " + noopTime + ", in distance=" + curSpeed * noopTime * _throttleFactor + ", blockLen= " + blockLen + ", totalLen= " + totalLen + ", remRamp= " + remRamp); } bo = orders.get(nextIdx++); blockName = bo.getBlock().getDisplayName(); blockLen = bo.getPath().getLengthMm(); if (blockLen <= 0) { blockLen = defaultBlockLen; } if (nextIdx == orders.size()) { blockLen /= 2; } w.addThrottleCommand(new ThrottleSetting((int) noopTime, "NoOp", "Enter Block", blockName)); if (log.isDebugEnabled()) { log.debug( "Enter block \"" + blockName + "\" noopTime= " + noopTime + ", blockLen= " + blockLen); } if (speedProfile != null) { curDistance = speedProfile.getSpeed(curSpeed, isForward) * speedTime / 1000; } else { curDistance = curSpeed * speedTime * _throttleFactor; } } else { if (blockLen == 0) { speedTime = 0; } break; } } // Ramp down finished if (curSpeed > 0) { // cleanup fractional speeds. insure speed 0 - should never happen. log.warn( "Ramp down LAST speed change in block \"" + blockName + "\" to speed 0 after " + (int) speedTime + "ms. curSpeed= " + curSpeed + ", curDistance= " + curDistance + ", remRamp= " + remRamp); w.addThrottleCommand(new ThrottleSetting((int) speedTime, "Speed", "0.0", blockName)); } w.addThrottleCommand(new ThrottleSetting(500, "F1", "false", blockName)); w.addThrottleCommand(new ThrottleSetting(1000, "F2", "true", blockName)); w.addThrottleCommand(new ThrottleSetting(3000, "F2", "false", blockName)); w.addThrottleCommand(new ThrottleSetting(1000, "F0", "false", blockName)); /* if (_addTracker.isSelected()) { WarrantTableFrame._defaultAddTracker = true; w.addThrottleCommand(new ThrottleSetting(10, "START TRACKER", "", blockName)); } else { WarrantTableFrame._defaultAddTracker = false; }*/ return null; }