/************************************************************************/ public void AddCurve(QuadraticSpeedDistanceCurve aCurve, string Name, string color) { PlottedItem p = new PlottedItem(); p.theCurve = aCurve; p.theName = Name; p.theColor = color; Items.Add(p); }
/// <summary> /// Provides the quadratic speed / distance curve for this graph /// </summary> /// <param name="expectedEnd">the last X value</param> /// <returns></returns> public QuadraticSpeedDistanceCurve QuadraticSpeedDistanceCurve(double expectedEnd) { QuadraticSpeedDistanceCurve curve = new QuadraticSpeedDistanceCurve(); foreach (Segment segment in Segments) { double start = segment.Start; double end = segment.End; if (end == double.MaxValue) { end = expectedEnd; } curve.Add( new SiDistance(segment.Start, SiDistance_SubUnits.Meter), new SiDistance(end, SiDistance_SubUnits.Meter), new SiAcceleration(segment.Expression.a, SiAcceleration_SubUnits.Meter_per_SecondSquare), new SiSpeed(segment.Expression.v0, SiSpeed_SubUnits.KiloMeter_per_Hour), new SiDistance(segment.Expression.d0, SiDistance_SubUnits.Meter)); } return(curve); }
/// <summary> /// Creates the picture associated to this graph /// </summary> /// <param name="name"></param> /// <returns>the corresponding bitmap</returns> public Bitmap Display() { Bitmap retVal = null; SpeedDistanceCurvePlotter display = new SpeedDistanceCurvePlotter(); String name = null; /// Computes the expected end to display double expectedEndX = 0; Dictionary <Function, Graph> graphs = new Dictionary <Function, Graph>(); foreach (Function function in Functions) { InterpretationContext context = new InterpretationContext(function); if (function.FormalParameters.Count == 1) { Parameter parameter = (Parameter)function.FormalParameters[0]; Graph graph = function.createGraph(context, parameter); if (graph != null) { expectedEndX = Math.Max(expectedEndX, graph.ExpectedEndX()); graphs.Add(function, graph); } } } double expectedEndY = 0; Dictionary <Function, Surface> surfaces = new Dictionary <Function, Surface>(); foreach (Function function in Functions) { InterpretationContext context = new InterpretationContext(function); if (function.FormalParameters.Count == 2) { Surface surface = function.createSurface(context); if (surface != null) { expectedEndX = Math.Max(expectedEndX, surface.ExpectedEndX()); expectedEndY = Math.Max(expectedEndY, surface.ExpectedEndY()); surfaces.Add(function, surface); } } } // Don't display surfaces that are too big if (setMaximumYValueCheckBox.Checked) { try { int maxY = Int32.Parse(maximumYValueTextBox.Text); expectedEndY = Math.Min(expectedEndY, maxY); } catch (Exception) { } } expectedEndY = Math.Min(600, expectedEndY); int i = 0; /// Creates the graphs foreach (KeyValuePair <Function, Graph> pair in graphs) { Function function = pair.Key; Graph graph = pair.Value; if (graph != null) { if (graph.IsFlat()) { FlatSpeedDistanceCurve curve = graph.FlatSpeedDistanceCurve(expectedEndX); display.AddCurve(curve, function.FullName, COLORS[i % COLORS.Length]); } else { QuadraticSpeedDistanceCurve curve = graph.QuadraticSpeedDistanceCurve(expectedEndX); display.AddCurve(curve, function.FullName, COLORS[i % COLORS.Length]); } if (name == null) { name = function.Name; } } i += 1; } /// Creates the surfaces foreach (KeyValuePair <Function, Surface> pair in surfaces) { Function function = pair.Key; Surface surface = pair.Value; if (surface != null) { AccelerationSpeedDistanceSurface curve = surface.createAccelerationSpeedDistanceSurface(expectedEndX, expectedEndY); display.AddCurve(curve, function.FullName); if (name == null) { name = function.Name; } } } if (name != null) { display.GnuPlot_Home_Path = Path.GetDirectoryName(Application.ExecutablePath) + "\\gnuplot\\bin"; string outputDir = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData) + "\\ERTMSFormalSpecs"; System.IO.Directory.CreateDirectory(outputDir); display.Output_Path = outputDir; display.Base_Name = "EFSPicture_" + name; display.ImageWidth = 1200; display.ImageHeight = 600; display.EraseTemporaryFiles = false; display.ShowColouredSegments = false; if (setMinimumValueCheckBox.Checked) { try { double val = double.Parse(minimumValueTextBox.Text); display.Min_X = new SiDistance(val, SiDistance_SubUnits.Meter); } catch (Exception) { } } if (setMaximumValueCheckBox.Checked) { try { double val = double.Parse(maximumValueTextBox.Text); display.Max_X = new SiDistance(val, SiDistance_SubUnits.Meter); } catch (Exception) { } } if (display.Plot()) { // Sometimes, a handle is still open on the corresponding file which forbids opening the stream on it // Wait a bit until the handle is no more open System.IO.FileStream stream = null; System.DateTime start = System.DateTime.Now; while (stream == null && System.DateTime.Now - start < new TimeSpan(0, 0, 5)) { try { stream = new System.IO.FileStream(display.ImageFileName, System.IO.FileMode.Open, System.IO.FileAccess.Read); } catch (Exception) { System.Threading.Thread.Sleep(100); } } if (stream != null) { try { retVal = new Bitmap(stream); } catch (Exception) { } finally { stream.Close(); // System.IO.File.Delete(display.ImageFileName); } } } } return(retVal); }
public OutputData() { A_service_break = new QuadraticSpeedDistanceCurve(); A_emergency_break = new QuadraticSpeedDistanceCurve(); }
public static QuadraticSpeedDistanceCurve Build_A_Safe_Backward(AccelerationSpeedDistanceSurface A_V_D, FlatSpeedDistanceCurve MRSP) { if (debug) { Log.InfoFormat("#######################################################"); Log.InfoFormat("## Build_A_Safe_Backward_Surface#######################"); Log.InfoFormat("#######################################################"); } int debugging_counter = 0; QuadraticSpeedDistanceCurve result = new QuadraticSpeedDistanceCurve(); /*********************************************************** The ending point is the first point in the MRSP ***********************************************************/ SiDistance end_position = MRSP[0].X.X0; /*********************************************************** Go forward in the MRSP until we find the point with minimal speed. This shall be our starting point **********************************************************/ SiDistance current_position = SiDistance.Zero; SiSpeed current_speed = SiSpeed.MaxValue; if (debug) Log.DebugFormat(" Search the position of the minimal speed in the MRSP"); for (int i = 0; i < MRSP.SegmentCount; i++) { ConstantCurveSegment<SiDistance, SiSpeed> segment = MRSP[i]; if (segment.Y < current_speed) { current_speed = segment.Y; current_position = segment.X.X1; if (debug) Log.DebugFormat(" new start position V={0,7:F2} at={1,7:F2} ", current_speed.ToUnits(), current_position.ToUnits()); } } if (debug) Log.DebugFormat(" end position is at={0,7:F2} ", end_position.ToUnits()); /*************************************************************************/ /* Starting from the right side of curves, go back to the left side. */ /* Build small curves arcs where the acceleration is constant on each one*/ /*************************************************************************/ while (current_position > end_position) { if (debug) { Log.DebugFormat("#######################################################"); Log.DebugFormat("### Loop {0} #########################################", debugging_counter); Log.DebugFormat("#######################################################"); } /************************************************************ Based on current speed and position, search on wich tile of A_V_D tile we are ***********************************************************/ SurfaceTile current_tile = A_V_D.GetTileAt(current_speed + new SiSpeed(0.01), current_position - new SiDistance(0.1)); SiAcceleration current_acceleration = current_tile.V.Y; /***************************************************************************/ /* If at previous loop wi did 'hit' the vertical part of the MRSP, we might have a speed above the current MRSP segment.*/ /***************************************************************************/ if (current_speed > MRSP.GetValueAt(current_position - new SiDistance(0.1))) { current_speed = MRSP.GetValueAt(current_position - new SiDistance(0.1)); } /******************************************************************* We build a quadratic arc with current train position, speed and acceleration. The arc domain [0..current_position] is not valid yet. We must find out the domain left limit. *****************************************************************/ QuadraticCurveSegment current_curve = new QuadraticCurveSegment(SiDistance.Zero, current_position, current_acceleration, current_speed, current_position); if (debug) { Log.DebugFormat(" current_acceleration = {0,7:F2} from a_tile {1}", current_acceleration.ToUnits(), current_tile.ToString()); Log.DebugFormat(" current_speed = {0,7:F2} ", current_speed.ToUnits()); Log.DebugFormat(" current_position = {0,7:F2} ", current_position.ToUnits()); Log.DebugFormat(" --> current_curve = {0} ", current_curve.ToString()); } /********************************************************************/ /* The current_curve may 'hit' one of these 4 items: 1) The upper border of the tile (because of a new acceleration) 2) The left border of the tile (because of a gradient?) 3) A vertical segment of the MRSP 4) An horizontal segment of the MRSP Text all of them and update the next_position accordingly. *************************************************************************/ SiDistance next_position = SiDistance.Zero; /* 1) The distance at wich our temporary arc intersects the top (V2) segment of the AVD tile */ { SiDistance d = current_curve.IntersectAt(current_tile.V.X.X1); if (debug) Log.DebugFormat(" intersection with tile (V_TOP) at {0,7:F2} ", d.ToUnits()); if (d >= next_position) { if (debug) Log.DebugFormat(" --> case_1 next_position {0,7:F2} -> {1,7:F2}", next_position.ToUnits(), d.ToUnits()); next_position = d; } } /* 2) The distance at wich our temporary arc intersects the left (D0) segment of the AVD tile */ { SiDistance d = current_tile.D.X.X0; if (debug) Log.DebugFormat(" intersection with tile (D0) at {0,7:F2} ", d.ToUnits()); if (d >= next_position) { if (debug) Log.DebugFormat(" --> case_2 next_position {0,7:F2} -> {1,7:F2}", next_position.ToUnits(), d.ToUnits()); next_position = d; } } /*Since the MRSP is continous, the following cannot fail. */ ConstantCurveSegment<SiDistance, SiSpeed> speed_limit_here = MRSP.Intersect(current_position - new SiDistance(0.1), current_curve); if (debug) Log.DebugFormat(" MRSP segment {0} ", speed_limit_here.ToString()); /* 3) Do we hit the vertical segment of the MRSP ? */ { if (speed_limit_here.X.X0 >= next_position) { if (debug) Log.DebugFormat(" --> case_3 next_position {0,7:F2} -> {1,7:F2}", next_position.ToUnits(), speed_limit_here.X.X0.ToUnits()); next_position = speed_limit_here.X.X0; } } /* 4) Do we hit the horizontal segment of the MRSP */ { if (current_speed + new SiSpeed(0.01) < speed_limit_here.Y) { SiDistance d = current_curve.IntersectAt(speed_limit_here.Y); if (d >= next_position) { if (debug) Log.DebugFormat(" --> case_4a next_d {0,7:F2} -> {1,7:F2}", next_position.ToUnits(), d.ToUnits()); next_position = d; } } else { if (debug) Log.DebugFormat(" --> case_4b next_acc_0 {0,7:F2} -> {1,7:F2}", next_position.ToUnits(), speed_limit_here.X.X0.ToUnits()); current_acceleration = SiAcceleration.Zero; next_position = speed_limit_here.X.X0; } } /* Finally we can add the segment because next_position has been computed. */ result.Add(next_position, current_position, current_acceleration, current_speed, current_position); result.Dump("result so far "); /* Next loop starts from our new position. We do not need to update current_acceleration because it is done at the beginning of the loop*/ current_position = next_position; current_speed = result.GetValueAt(current_position); /*************************************************************/ /* If this exception is thrown, you'd better call Juan */ /*************************************************************/ if (debugging_counter++ > 200) { throw new Exception("Algorithm is broken"); } } return result; }
/// <summary> /// Method used to get the full EBD and SBD curves from the MRSP /// </summary> /// <param name="A_V_D"></param> /// <param name="MRSP"></param> /// <returns></returns> public static QuadraticSpeedDistanceCurve Build_A_Safe_Backward(AccelerationSpeedDistanceSurface A_V_D, FlatSpeedDistanceCurve MRSP) { debugging_counter = 0; if (debug) { Log.InfoFormat("#######################################################"); Log.InfoFormat("## Build_A_Safe_Backward_Surface#######################"); Log.InfoFormat("#######################################################"); } QuadraticSpeedDistanceCurve result = new QuadraticSpeedDistanceCurve(); /*********************************************************** The ending point is the first point in the MRSP ***********************************************************/ SiDistance end_position = MRSP[0].X.X0; /*********************************************************** Go forward in the MRSP until we find the point with minimal speed. This shall be our starting point **********************************************************/ SiDistance current_position = SiDistance.Zero; SiSpeed current_speed = SiSpeed.MaxValue; if (debug) Log.DebugFormat(" Search the position of the minimal speed in the MRSP"); for (int i = 0; i < MRSP.SegmentCount; i++) { ConstantCurveSegment<SiDistance, SiSpeed> segment = MRSP[i]; if (segment.Y < current_speed) { current_speed = segment.Y; current_position = segment.X.X1; if (debug) Log.DebugFormat(" new start position V={0,7:F2} at={1,7:F2} ", current_speed.ToUnits(), current_position.ToUnits()); } } if (debug) Log.DebugFormat(" end position is at={0,7:F2} ", end_position.ToUnits()); SiDistance next_position = SiDistance.Zero; /*************************************************************************/ /* Starting from the right side of curves, go back to the left side. */ /* Build small curves arcs where the acceleration is constant on each one*/ /*************************************************************************/ while (current_position > end_position) { Compute_Curve(A_V_D, result, MRSP, ref current_position, ref next_position, ref current_speed, BrakingCurveDirectionEnum.Backwards); /* Next loop starts from our new position. We do not need to update current_acceleration because it is done at the beginning of the loop*/ current_position = next_position; current_speed = result.GetValueAt(current_position, BrakingCurveDirectionEnum.Backwards); /*************************************************************/ /* If this exception is thrown, you'd better call Juan */ /*************************************************************/ if (debugging_counter++ > 200) { throw new Exception("Algorithm is broken"); } } return result; }
/// <summary> /// Computes the curve from a point /// </summary> /// <param name="A_V_D"></param> /// <param name="result"></param> /// <param name="mrsp"></param> /// <param name="current_position"></param> /// <param name="next_position"></param> /// <param name="current_speed"></param> /// <param name="dir"></param> private static void Compute_Curve(AccelerationSpeedDistanceSurface A_V_D, QuadraticSpeedDistanceCurve result, FlatSpeedDistanceCurve mrsp, ref SiDistance current_position, ref SiDistance next_position, ref SiSpeed current_speed, BrakingCurveDirectionEnum dir) { int Direction = Get_Direction(dir); SiSpeed speed_step = (-1)*Direction*minimal_speed_threshold; SiDistance distance_step = Direction*minimal_distance_threshold; if (debug) { Log.DebugFormat("#######################################################"); Log.DebugFormat("### Loop {0} #########################################", debugging_counter); Log.DebugFormat("#######################################################"); } /************************************************************ Based on current speed and position, search on wich tile of A_V_D tile we are ***********************************************************/ SurfaceTile current_tile = A_V_D.GetTileAt(current_speed + speed_step, current_position + distance_step); /***************************************************************************/ /* If at previous loop wi did 'hit' the vertical part of the MRSP, we might have a speed above the current MRSP segment.*/ /***************************************************************************/ if (current_speed > mrsp.GetValueAt(current_position - minimal_distance_threshold, BrakingCurveDirectionEnum.Backwards)) { current_speed = mrsp.GetValueAt(current_position - minimal_distance_threshold, BrakingCurveDirectionEnum.Backwards); } /******************************************************************* We build a quadratic arc with current train position, speed and acceleration. The arc domain [0..current_position] is not valid yet. We must find out the domain left limit. *****************************************************************/ QuadraticCurveSegment current_curve = Build_One_Curve_Segment(current_tile, current_position, current_speed, mrsp, dir); next_position = Distance_Edge(current_curve, dir); SiAcceleration current_acceleration = current_curve.A; /* Finally we can add the segment because next_position has been computed. */ SiDistance refLocation = current_curve.X.X0; SiSpeed refSpeed = current_curve.Get(refLocation); result.Add(current_curve.X.X0, current_curve.X.X1, current_acceleration, refSpeed, refLocation); result.Dump("result so far "); }
/// <summary> /// Builds a full deceleration curve corresponding to a given target(location, speed) /// </summary> /// <param name="A_V_D"></param> /// <param name="TargetSpeed"></param> /// <param name="TargetDistance"></param> /// <returns></returns> public static QuadraticSpeedDistanceCurve Build_Deceleration_Curve(AccelerationSpeedDistanceSurface A_V_D, SiSpeed TargetSpeed, SiDistance TargetDistance) { debugging_counter = 0; QuadraticSpeedDistanceCurve result = new QuadraticSpeedDistanceCurve(); // Build a MRSP for this target FlatSpeedDistanceCurve mrsp = new FlatSpeedDistanceCurve(); mrsp.Add(SiDistance.Zero, TargetDistance, new SiSpeed(400, SiSpeed_SubUnits.KiloMeter_per_Hour)); mrsp.Add(TargetDistance, new SiDistance(20000), TargetSpeed); // Add to result by calculating backwards then forwards SiDistance current_position = TargetDistance; SiSpeed current_speed = TargetSpeed; BrakingCurveDirectionEnum dir = BrakingCurveDirectionEnum.Backwards; SiDistance next_position = SiDistance.Zero; SiDistance end_position = mrsp[0].X.X0; while (current_position > end_position) { Compute_Curve(A_V_D, result, mrsp, ref current_position, ref next_position, ref current_speed, dir); /* Next loop starts from our new position. We do not need to update current_acceleration because it is done at the beginning of the loop*/ current_position = next_position; current_speed = result.GetValueAt(current_position, BrakingCurveDirectionEnum.Backwards); } current_position = TargetDistance; current_speed = TargetSpeed; dir = BrakingCurveDirectionEnum.Forwards; while (current_speed > minimal_speed_threshold) { Compute_Curve(A_V_D, result, mrsp, ref current_position, ref next_position, ref current_speed, dir); /* Next loop starts from our new position. We do not need to update current_acceleration because it is done at the beginning of the loop*/ current_position = next_position; current_speed = result.GetValueAt(current_position, dir); } result.Add(current_position, mrsp[mrsp.SegmentCount - 1].X.X1, SiAcceleration.Zero, SiSpeed.Zero, current_position); return result; }
/// <summary> /// Provides the graph of this function if it has been statically defined /// </summary> /// <param name="context">the context used to create the graph</param> /// <returns></returns> public override Graph createGraph(Interpreter.InterpretationContext context, Parameter parameter) { Graph retVal = null; Graph MRSPGraph = null; Function speedRestriction = context.findOnStack(SpeedRestrictions).Value as Function; if (speedRestriction != null) { Parameter p = (Parameter)speedRestriction.FormalParameters[0]; int token = context.LocalScope.PushContext(); context.LocalScope.setGraphParameter(p); MRSPGraph = createGraphForValue(context, context.findOnStack(SpeedRestrictions).Value, p); context.LocalScope.PopContext(token); } if (MRSPGraph != null) { Function deceleratorFactor = context.findOnStack(DecelerationFactor).Value as Function; if (deceleratorFactor != null) { Surface DecelerationSurface = deceleratorFactor.createSurface(context); if (DecelerationSurface != null) { FlatSpeedDistanceCurve MRSPCurve = MRSPGraph.FlatSpeedDistanceCurve(MRSPGraph.ExpectedEndX()); AccelerationSpeedDistanceSurface accelerationSurface = DecelerationSurface.createAccelerationSpeedDistanceSurface(double.MaxValue, double.MaxValue); QuadraticSpeedDistanceCurve BrakingCurve = null; try { BrakingCurve = EtcsBrakingCurveBuilder.Build_A_Safe_Backward(accelerationSurface, MRSPCurve); } catch (System.Exception e) { retVal = new Graph(); retVal.addSegment(new Graph.Segment(0, double.MaxValue, new Graph.Segment.Curve(0, 0, 0))); } if (BrakingCurve != null) { retVal = new Graph(); // TODO : Remove the distinction between linear curves and quadratic curves bool isLinear = true; for (int i = 0; i < BrakingCurve.SegmentCount; i++) { QuadraticCurveSegment segment = BrakingCurve[i]; if (segment.A.ToUnits() != 0.0 || segment.V0.ToUnits() != 0.0) { isLinear = false; break; } } for (int i = 0; i < BrakingCurve.SegmentCount; i++) { QuadraticCurveSegment segment = BrakingCurve[i]; Graph.Segment newSegment; if (isLinear) { newSegment = new Graph.Segment( segment.X.X0.ToUnits(), segment.X.X1.ToUnits(), new Graph.Segment.Curve(0.0, segment.V0.ToSubUnits(SiSpeed_SubUnits.KiloMeter_per_Hour), 0.0)); } else { newSegment = new Graph.Segment( segment.X.X0.ToUnits(), segment.X.X1.ToUnits(), new Graph.Segment.Curve( segment.A.ToSubUnits(SiAcceleration_SubUnits.Meter_per_SecondSquare), segment.V0.ToSubUnits(SiSpeed_SubUnits.KiloMeter_per_Hour), segment.D0.ToSubUnits(SiDistance_SubUnits.Meter) ) ); } retVal.addSegment(newSegment); } } } else { Log.Error("Cannot create surface for " + DecelerationFactor.ToString()); } } else { Log.Error("Cannot evaluate " + DecelerationFactor.ToString() + " as a function"); } } else { Log.Error("Cannot create graph for " + SpeedRestrictions.ToString()); } return(retVal); }
/// <summary> /// Creates a graph for the function /// </summary> /// <param name="context"></param> /// <param name="parameter"></param> /// <param name="explain"></param> /// <returns></returns> public override Graph CreateGraph(InterpretationContext context, Parameter parameter, ExplanationPart explain) { Graph retVal = new Graph(); StructureValue LocationStruct = context.FindOnStack(Target).Value as StructureValue; SiDistance location; SiSpeed speed; if (LocationStruct != null) { IVariable locationField = LocationStruct.Val["Location"] as IVariable; location = new SiDistance((locationField.Value as DoubleValue).Val); IVariable speedField = LocationStruct.Val["Speed"] as IVariable; speed = new SiSpeed((speedField.Value as DoubleValue).Val, SiSpeed_SubUnits.KiloMeter_per_Hour); Function decelerationFactor = context.FindOnStack(DecelerationFactor).Value as Function; if (decelerationFactor != null) { Surface DecelerationSurface = decelerationFactor.CreateSurface(context, explain); if (DecelerationSurface != null) { AccelerationSpeedDistanceSurface accelerationSurface = DecelerationSurface.createAccelerationSpeedDistanceSurface(double.MaxValue, double.MaxValue); QuadraticSpeedDistanceCurve BrakingCurve = null; try { BrakingCurve = EtcsBrakingCurveBuilder.Build_Deceleration_Curve(accelerationSurface, speed, location); } catch (Exception e) { retVal.AddSegment(new Graph.Segment(0, double.MaxValue, new Graph.Segment.Curve(0, 0, 0))); } SiSpeed finalSpeed = new SiSpeed(GetDoubleValue(context.FindOnStack(EndSpeed).Value), SiSpeed_SubUnits.KiloMeter_per_Hour); for (int i = 0; i < BrakingCurve.SegmentCount; i++) { QuadraticCurveSegment segment = BrakingCurve[i]; SiSpeed endSpeed = Max(finalSpeed, segment.Get(segment.X.X1)); SiDistance endDistance; if (endSpeed == finalSpeed) { // Ensures that a braking curve is calculated until the finalSpeed // but not further than the end of the curve segment SiSpeed tmp = Max(segment.Get(segment.X.X1), endSpeed - new SiSpeed(0.001)); endDistance = segment.IntersectAt(tmp); } else { endDistance = segment.X.X1; } Graph.Segment newSegment = new Graph.Segment( segment.X.X0.ToUnits(), endDistance.ToUnits(), new Graph.Segment.Curve( segment.A.ToSubUnits(SiAcceleration_SubUnits.Meter_per_SecondSquare), segment.V0.ToSubUnits(SiSpeed_SubUnits.KiloMeter_per_Hour), segment.D0.ToSubUnits(SiDistance_SubUnits.Meter) ) ); retVal.AddSegment(newSegment); if (endSpeed == finalSpeed) { break; } } } } } return(retVal); }