/// <summary> /// Method to compute new speed and new position for the current platoon based on /// speed limit restrictions and maintaining minimum required distance with predecessor. /// </summary> /// <param name="prev">Reference to previous platoon</param> /// <param name="newPosn">New tentative position to move to</param> /// <param name="newSpeed">New speed to move to newPosn</param> private void computeNewSpeedAndPosition(Platoon prev, out int newPosn, out int newSpeed) { int distToTravel = 0; // Distance to travel through in one time slot /** * If there's no platoon ahead of this platoon then in one time unit, a platoon * can move as much as the speedLimit. */ if(prev == null) { distToTravel = speedLimit; } else { /** * If there is a platoon ahead of this platoon, compute distToTravel * such that it maintains "interPlatoonDist" with it. */ if(this.dirn == Direction.NS || this.dirn == Direction.EW) { distToTravel = prev.rearPosition() - currPosn; } if(this.dirn == Direction.SN || this.dirn == Direction.WE) { distToTravel = currPosn - prev.rearPosition(); } distToTravel = distToTravel - interPlatoonDist; /** * However, speedLimit can't be exceeded. So if distToTravel > speedLimit, then * reduce distToTravel to speedLimit. */ if(distToTravel > speedLimit) distToTravel = speedLimit; } /** * Compute newSpeed and newPosn. */ newSpeed = distToTravel; if(this.dirn == Direction.NS || this.dirn == Direction.EW) { newPosn = currPosn + newSpeed; } else if(this.dirn == Direction.SN || this.dirn == Direction.WE) { newPosn = currPosn - newSpeed; } else { /** * Written ONLY to satisfy the compiler */ newPosn = -100000; newSpeed = -100000; } }
/// <summary> /// Algorithm used by the platoons to move /// </summary> /// <param name="prev">Previous platoon's reference</param> /// <param name="currTime">Current time</param> /// <returns></returns> public void move(Platoon prev, int currTime) { int newSpeed = -1; // New speed int newPosn = -1; // New position bool canMerge = true; // Can merge with previous platoon int nextXPosn; // Position of next intersection bool moveSucceeded; // Move to new position succeeded int nextIntxnNum = -2000; // Number of next intersection - NOT USED RIGHT NOW /** * Compute new speed and new position for the platoon */ computeNewSpeedAndPosition(prev, out newPosn, out newSpeed); /** * If newSpeed was zero, that means that the platoon cannot move due to predecessor platoon * blocking it's path in this iteration, so return without moving. */ if(newSpeed == 0) { return; } moveSucceeded = checkIfMoveAllowed(currTime, newPosn, newSpeed, out nextXPosn); if(moveSucceeded == true) { currPosn = newPosn; currSpeed = newSpeed; } else { currPosn = nextXPosn; currSpeed = 0; } }
/// <summary> /// Helper method used by createPlatoon to create platoons. /// </summary> /// <param name="currTime">Current time</param> /// <param name="laneID">Lane ID for which platoon must be created 0 - downLane, 1 - upLane</param> private void createPlatoonHelper(int currTime, int laneID) { Platoon p; // Temp object Platoon int posn; // Rear position of last platoon on that lane int numVeh; // Number of vehicles to add in platoon int startPt; // Starting position for platoon Vehicle []v; // Array of vehicles to add to platoon int platoonDirn;// Platoon's direction Queue waitQ; // Waiting queue ArrayList lane; // Lane /** * Select values corresponding to either downlane or uplane */ if(laneID == 0) { lane = downLane; waitQ = downQueue; startPt = this.startPos; // For downlane, direction is either NS or EW if(orient == RoadOrientation.NS) platoonDirn = Direction.NS; else platoonDirn = Direction.EW; } else { lane = upLane; waitQ = upQueue; startPt = this.endPos; // For upLane, direction is either SN or WE if(orient == RoadOrientation.NS) platoonDirn = Direction.SN; else platoonDirn = Direction.WE; } /** * If this is the time to create a platoon and some vehicles are waiting to join a platoon * then only create a platoon. */ if((currTime % period == 0) && (waitQ.Count > 0)) { /** * Get the position of the last platoon on that lane. */ if(lane.Count > 0) { p = (Platoon) lane[lane.Count - 1]; posn = p.rearPosition(); /** * If there isn't place to create a new platoon such that minimum inter platoon distance * is maintained with last platoon on that lane, don't attempt to create a platoon and return. */ if(laneID == 0) { if(posn < this.startPos + ip.interPlatoonDist) { /** * Increment platoon not created counter. */ roadCntr.incrementPlatoonNotCreatedCount(); return; } } else { if(this.endPos - posn < ip.interPlatoonDist) { /** * Increment platoon not created counter. */ roadCntr.incrementPlatoonNotCreatedCount(); return; } } } // Get how many vehicles to add to this platoon numVeh = Math.Min(numVehiclesInPlatoon, waitQ.Count); v = new Vehicle[numVeh]; // Remove those many vehicles from the waiting queue for(int i = 0; i < numVeh; i++) { v[i] = (Vehicle) waitQ.Dequeue(); // Set vehicles start journey time - this determines vehicle's wait time v[i].setStartJourneyTime(currTime); } p = new Platoon(v, numVehiclesInPlatoon, platoonDirn, travelSpeed, startPt, this); if(laneID == 1) { // Console.WriteLine("Platoon created at posn {0} Dirn {1} on Road {2} Orient {3}", startPt, platoonDirn, this.roadNum, this.orient); } lane.Add(p); /** * Update platoon arrival counter in road perf counter */ roadCntr.platoonCreated(); } }
/// <summary> /// This method is invoked by the platoon to merge with its predecessor platoon. The merging platoon /// first obtains the capacity of the succeeding platoon and then merges all possible vehicles to its /// predecessor. If this platoon merges all its vehicles to predecessor, then it gets itself removed from the road /// ONLY COMPLETE MERGE IS ALLOWED. /// A succeeding platoon can invoke this method when it is intra-platoon dist away from its predecessor. Distance check /// is not done in this method. /// </summary> /// <param name="pred">Instance of preceding platoon</param> /// <returns>A boolean value true if merge is possible, false otherwise</returns> public bool mergeWithPredecessor(Platoon pred) { int predCapacity; // Additional capacity of predecessor platoon /** * Query the preceding platoon for additional platoons that it can accept. * If it's not possible to merge more platoons then return false. */ predCapacity = pred.mergeCapacity(); /** * ONLY COMPLETE MERGES ARE ALLOWED. Thus, if the number of vehicles in current platoon * are greater than the capacity of preceding platoon, do not attempt to merge and return * false. */ if(vehicles.Count > predCapacity) return false; // Add the removed vehicles into the preceding platoon pred.acceptSuccessor(vehicles); /** * This loop removes all the vehicles from the vehicles array of this platoon */ vehicles.RemoveRange(0, vehicles.Count); // while(vehicles.Count > 0) // { // vehicles.RemoveAt(0); // } // Update self length platoonLen = 0; // Set currposn to some invalid value currPosn = -1000000; return true; }
/// <summary> /// Computes the statistics for all the platoons in the system /// </summary> /// <param name="currTime">Current Time</param> public void getRoadPlatoonStatistics(int currTime) { Platoon p; /** * Add the counters for all the platoons in transit. */ for(int i = 0; i < downLane.Count; i++) { p = (Platoon) downLane[i]; roadCntr.addPlatoonCounter(p.getCounters(currTime)); } for(int i = 0; i < upLane.Count; i++) { p = (Platoon) upLane[i]; roadCntr.addPlatoonCounter(p.getCounters(currTime)); } /** * Create a new platoon containing all the vehicles in the holding queue and then * add that to the roadCntr so that transit time of these vehicles get counted also. */ Vehicle []v = new Vehicle[downQueue.Count]; int cnt = downQueue.Count; for(int i = 0; i < cnt; i++) { v[i] = (Vehicle) downQueue.Dequeue(); } p = new Platoon(v, v.Length, Direction.NS, ip.speedLimit, 0, this); roadCntr.addPlatoonCounter(p.getCounters(currTime)); /** * Do the same for up queue */ v = new Vehicle[upQueue.Count]; cnt = upQueue.Count; for(int i = 0; i < cnt; i++) { v[i] = (Vehicle) upQueue.Dequeue(); } p = new Platoon(v, v.Length, Direction.SN, ip.speedLimit, 0, this); roadCntr.addPlatoonCounter(p.getCounters(currTime)); }