From 9ec48ec7cb9a340925bb036bea2032753fafeb40 Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Thu, 20 Jan 2022 13:37:55 +0100 Subject: [PATCH] Divide MovingPhases into Behavior and DrivingDynamics --- examples/MinimalWorkingExample.jl | 1 + src/{MovingPhases.jl => Behavior.jl} | 459 ++++++++++++--------------- src/DrivingDynamics.jl | 221 +++++++++++++ src/EnergySaving.jl | 40 +-- src/Preparation.jl | 62 ++-- src/TrainRun.jl | 13 +- src/TrainRunCalc.jl | 24 +- 7 files changed, 492 insertions(+), 328 deletions(-) rename src/{MovingPhases.jl => Behavior.jl} (70%) create mode 100644 src/DrivingDynamics.jl diff --git a/examples/MinimalWorkingExample.jl b/examples/MinimalWorkingExample.jl index 3854756..9f7016c 100644 --- a/examples/MinimalWorkingExample.jl +++ b/examples/MinimalWorkingExample.jl @@ -16,4 +16,5 @@ setting_directory = "data/settings.yaml" train_run = calculateDrivingDynamics(train, running_path, settings) runtime = train_run[:movingSectionMinimumRunningTime][:t] +exportToCsv(train_run) println("The V 90 with 10 ore wagons needs $runtime seconds for 10 km with no gradient.") diff --git a/src/MovingPhases.jl b/src/Behavior.jl similarity index 70% rename from src/MovingPhases.jl rename to src/Behavior.jl index bd1faa8..d4899c5 100644 --- a/src/MovingPhases.jl +++ b/src/Behavior.jl @@ -1,12 +1,12 @@ -module MovingPhases +module Behavior + +include("./DrivingDynamics.jl") +using .DrivingDynamics export addAccelerationPhase!, addAccelerationPhaseUntilBraking!, addCruisingPhase!, addCoastingPhaseUntilBraking!, addBrakingPhase!, addBrakingPhaseStepwise!, addStandstill!, calculateForces! -export createDataPoint +export createDataPoint, calcBrakingStartVelocity # addBrakingPhaseStepwise! is not used in the current version of the tool -v00=100/3.6 # velocity constant (in m/s) -g=9.81 # acceleration due to gravity (in m/s^2) # TODO: should more digits of g be used? g=9,80665 m/s^2 - approximationLevel = 6 # value for approximation to intersections TODO further explanation (e.g. approximationLevel = 3 -> with stepSize 10 m the approximation will be calculated accurate on 10 mm ; 1s -> 1 ms; 1 km/h -> 3.6 mm/s) # TODO: define it in TrainRun and give it to each function? @@ -33,11 +33,13 @@ julia> calculateTractiveEffort(30.0, [[0.0, 180000], [20.0, 100000], [40.0, 6000 """ function calculateTractiveEffort(v::AbstractFloat, tractiveEffortVelocityPairs) for row in 1:length(tractiveEffortVelocityPairs) - if tractiveEffortVelocityPairs[row][1]==v - return tractiveEffortVelocityPairs[row][2] - elseif tractiveEffortVelocityPairs[row][1]>v + nextPair = tractiveEffortVelocityPairs[row] + if nextPair[1] == v + return nextPair[2] + elseif nextPair[1] > v # interpolate for a straight line between the two surrounding points with the formula: F=(v-v_(row-1))*(F_row-F_(row-1))/(v_row-v_(row-1))+F_(row-1) - F_T_interpolation=(v-tractiveEffortVelocityPairs[row-1][1])*(tractiveEffortVelocityPairs[row][2]-tractiveEffortVelocityPairs[row-1][2])/(tractiveEffortVelocityPairs[row][1]-tractiveEffortVelocityPairs[row-1][1])+tractiveEffortVelocityPairs[row-1][2] + previousPair = tractiveEffortVelocityPairs[row-1] + F_T_interpolation = (v-previousPair[1]) * (nextPair[2]-previousPair[2]) / (nextPair[1]-previousPair[1]) + previousPair[2] return F_T_interpolation end #if end #for @@ -46,37 +48,6 @@ function calculateTractiveEffort(v::AbstractFloat, tractiveEffortVelocityPairs) return tractiveEffortVelocityPairs[end][2] end #function calculateTractiveEffort - -#TODO: choose an explanation and replace the ? ? ? -""" - calculateTractionUnitResistance(v, train) - -Calculate the traction units vehicle resistance dependend on the velocity `v`. -Calculate the vehicle resistance for the traction unit of the `train` dependend on the velocity `v`. - -... -# Arguments -- `v::AbstractFloat`: the current velocity in m/s. -- `train::Dict`: ? ? ? -... - -# Examples -```julia-repl -julia> calculateTractionUnitResistance(30.0, ? ? ?) -? ? ? -``` -""" -function calculateTractionUnitResistance(v::AbstractFloat, train::Dict) - return train[:f_Rtd0]/1000*train[:m_td]*g+train[:f_Rtc0]/1000*train[:m_tc]*g+train[:F_Rt2]*((v+train[:Δv_t])/v00)^2 # /1000 because of the unit ‰ -end #function calculateTractionUnitResistance - -""" -calculate and return the wagons vehicle resistance dependend on the velocity -""" -function calculateWagonsResistance(v::AbstractFloat, train::Dict) - return train[:m_w]*g*(train[:f_Rw0]/1000+train[:f_Rw1]/1000*v/v00+train[:f_Rw2]/1000*((v+train[:Δv_w])/v00)^2) # /1000 because of the unit ‰ -end #function calculateWagonsResistance - """ calculate and return the path resistance dependend on the trains position and mass model """ @@ -90,35 +61,33 @@ function calculatePathResistance(s::Real, massModel::String, train::Dict, CSs::V end end #while - if massModel=="mass point" - pathResistance=CSs[id][:r_path]/1000*train[:m_train]*g # /1000 because of the unit ‰ - elseif massModel=="homogeneous strip" - pathResistance=0.0 - while id>0 && s-train[:length] 0 && s-train[:length] < CSs[id][:s_exit] + pathResistance = pathResistance + (min(s, CSs[id][:s_exit]) - max(s-train[:length], CSs[id][:s_entry])) / train[:length] * calcPathResistance(CSs[id][:r_path], train[:m_train]) + id = id-1 + if id == 0 # TODO: currently for values < movingSection[:s_entry] the values of movingSection[:s_entry] will be used - return pathResistance+(CSs[1][:s_entry]-(s-train[:length]))/train[:length]*(CSs[1][:r_path]/1000*train[:m_train]*g) # /1000 because of the unit ‰ + return pathResistance + (CSs[1][:s_entry] - (s-train[:length])) / train[:length] * calcPathResistance(CSs[1][:r_path], train[:m_train]) end #if end #while - else - error("ERROR at the calculation of path resistance: settings[:massModel]!=mass point && settings[:massModel]!=homogeneous strip") end #if return pathResistance -end #function pathResistance +end #function calculatePathResistance """ calculate and return tractive and resisting forces for a data point """ function calculateForces!(dataPoint::Dict, train::Dict, massModel::String, CSs::Vector{Dict}, bsType::String) # calculate resisting forces - dataPoint[:R_traction]=calculateTractionUnitResistance(dataPoint[:v], train) - dataPoint[:R_wagons]=calculateWagonsResistance(dataPoint[:v], train) - dataPoint[:R_train]=dataPoint[:R_traction]+dataPoint[:R_wagons] - dataPoint[:R_path]=calculatePathResistance(dataPoint[:s], massModel, train, CSs) - dataPoint[:F_R]=dataPoint[:R_train]+dataPoint[:R_path] + dataPoint[:R_traction] = calcTractionUnitResistance(dataPoint[:v], train) + dataPoint[:R_wagons] = calcWagonsResistance(dataPoint[:v], train) + dataPoint[:R_train] = dataPoint[:R_traction] + dataPoint[:R_wagons] + dataPoint[:R_path] = calculatePathResistance(dataPoint[:s], massModel, train, CSs) + dataPoint[:F_R] = dataPoint[:R_train] + dataPoint[:R_path] # calculate tractive effort if bsType == "acceleration" || bsType == "diminishing" @@ -142,44 +111,42 @@ function moveAStep(previousPoint::Dict, stepVariable::String, stepSize::Real, cs #= 08/31 TODO: How to check if the train stopps during this step? I should throw an error myself that I catch in higher hierarchies. =# # creating the next data point - newPoint=createDataPoint() - newPoint[:i]=previousPoint[:i]+1 # identifier + newPoint = createDataPoint() + newPoint[:i] = previousPoint[:i]+1 # identifier # calculate s, t, v, E - if previousPoint[:a]==0.0 # TODO: or better stepVariable=="s_cruising in m" ? - newPoint[:Δs]=stepSize # step size (in m) - newPoint[:Δt]=newPoint[:Δs]/previousPoint[:v] # step size (in s) - newPoint[:Δv]=0.0 # step size (in m/s) - elseif stepVariable=="s in m" # distance step method - newPoint[:Δs]=stepSize # step size (in m) - # 11/21 |-> - if previousPoint[:a]<0.0 + if previousPoint[:a] == 0.0 # TODO: or better stepVariable=="s_cruising in m" ? + newPoint[:Δs] = stepSize # step size (in m) + newPoint[:Δt] = newPoint[:Δs]/previousPoint[:v] # step size (in s) + newPoint[:Δv] = 0.0 # step size (in m/s) + elseif stepVariable == "s in m" # distance step method + newPoint[:Δs] = stepSize # step size (in m) + if previousPoint[:a] < 0.0 if ((previousPoint[:v]/previousPoint[:a])^2+2*newPoint[:Δs]/previousPoint[:a])<0.0 || (previousPoint[:v]^2+2*newPoint[:Δs]*previousPoint[:a])<0.0 # checking if the parts of the following square roots will be <0.0 error("ERROR: The train stops during the acceleration phase in CS",csId," because the tractive effort is lower than the resistant forces.", " Before the stop the last point has the values s=",previousPoint[:s]," m, v=",previousPoint[:v]," m/s, a=",previousPoint[:a]," m/s^2,", " F_T=",previousPoint[:F_T]," N, R_traction=",previousPoint[:R_traction]," N, R_wagons=",previousPoint[:R_wagons]," N, R_path=",previousPoint[:R_path]," N.") end end - # 11/21 ->| - newPoint[:Δt]=sign(previousPoint[:a])*sqrt((previousPoint[:v]/previousPoint[:a])^2+2*newPoint[:Δs]/previousPoint[:a])-previousPoint[:v]/previousPoint[:a] # step size (in s) - newPoint[:Δv]=sqrt(previousPoint[:v]^2+2*newPoint[:Δs]*previousPoint[:a])-previousPoint[:v] # step size (in m/s) - elseif stepVariable=="t in s" # time step method - newPoint[:Δt]=stepSize # step size (in s) - newPoint[:Δs]=newPoint[:Δt]*(2*previousPoint[:v]+newPoint[:Δt]*previousPoint[:a])/2 # step size (in m) - newPoint[:Δv]=newPoint[:Δt]*previousPoint[:a] # step size (in m/s) - elseif stepVariable=="v in m/s" # velocity step method - newPoint[:Δv]=stepSize*sign(previousPoint[:a]) # step size (in m/s) - newPoint[:Δs]=((previousPoint[:v]+newPoint[:Δv])^2-previousPoint[:v]^2)/2/previousPoint[:a] # step size (in m) - newPoint[:Δt]=newPoint[:Δv]/previousPoint[:a] # step size (in s) + newPoint[:Δt] = calc_Δt_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in s) + newPoint[:Δv] = calc_Δv_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in m/s) + elseif stepVariable =="t in s" # time step method + newPoint[:Δt] =stepSize # step size (in s) + newPoint[:Δs] = calc_Δs_with_Δt(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in m) + newPoint[:Δv] = calc_Δv_with_Δt(newPoint[:Δs], previousPoint[:a]) # step size (in m/s) + elseif stepVariable =="v in m/s" # velocity step method + newPoint[:Δv] = stepSize * sign(previousPoint[:a]) # step size (in m/s) + newPoint[:Δs] = calc_Δs_with_Δv(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in m) + newPoint[:Δt] = calc_Δt_with_Δv(newPoint[:Δs], previousPoint[:a]) # step size (in s) end #if - newPoint[:s]=previousPoint[:s]+newPoint[:Δs] # position (in m) - newPoint[:t]=previousPoint[:t]+newPoint[:Δt] # point in time (in s) - newPoint[:v]=previousPoint[:v]+newPoint[:Δv] # velocity (in m/s) - newPoint[:ΔW]=previousPoint[:F_T]*newPoint[:Δs] # mechanical work in this step (in Ws) - newPoint[:W]=previousPoint[:W]+newPoint[:ΔW] # mechanical work (in Ws) - newPoint[:ΔE]=newPoint[:ΔW] # energy consumption in this step (in Ws) - newPoint[:E]=previousPoint[:E]+newPoint[:ΔE] # energy consumption (in Ws) + newPoint[:s] = previousPoint[:s] + newPoint[:Δs] # position (in m) + newPoint[:t] = previousPoint[:t] + newPoint[:Δt] # point in time (in s) + newPoint[:v] = previousPoint[:v] + newPoint[:Δv] # velocity (in m/s) + newPoint[:ΔW] = calc_ΔW(previousPoint[:F_T], newPoint[:Δs]) # mechanical work in this step (in Ws) + newPoint[:W] = previousPoint[:W] + newPoint[:ΔW] # mechanical work (in Ws) + newPoint[:ΔE] = calc_ΔE(newPoint[:ΔW]) # energy consumption in this step (in Ws) + newPoint[:E] = previousPoint[:E] + newPoint[:ΔE] # energy consumption (in Ws) return newPoint @@ -226,17 +193,17 @@ function considerFormerSpeedLimits!(CS::Dict, drivingCourse::Vector{Dict}, setti end # create a (new and longer) clearing section - s_braking=max(0.0, ceil((CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking], digits=approximationLevel)) - s_clearing=min(CS[:s_exit]-drivingCourse[end][:s]-s_braking, formerSpeedLimits[end][1]-(drivingCourse[end][:s]-train[:length])) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + s_clearing = min(CS[:s_exit]-drivingCourse[end][:s]-s_braking, formerSpeedLimits[end][1]-(drivingCourse[end][:s]-train[:length])) - if s_clearing>0.0 - (CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_clearing, settings, train, CSs, "clearing") + if s_clearing > 0.0 + (CS, drivingCourse) = addCruisingPhase!(CS, drivingCourse, s_clearing, settings, train, CSs, "clearing") else error("ERROR: clearing <=0.0 although it has to be >0.0 in CS ",CS[:id]) end # 09/22: if drivingCourse[end][:s] < CS[:s_exit] - if drivingCourse[end][:s] < CS[:s_exit]-s_braking + if drivingCourse[end][:s] < CS[:s_exit] - s_braking # reset the accelerationSection accelerationSection = createBehaviorSection("acceleration", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) else @@ -264,55 +231,27 @@ function addBreakFreePhase!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dic calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, "acceleration") # currently the tractive effort is calculated like in the acceleration phase # acceleration (in m/s^2): - drivingCourse[end][:a]=(drivingCourse[end][:F_T]-drivingCourse[end][:F_R])/train[:m_train]/train[:ξ_train] + drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train[:m_train], train[:ξ_train]) if drivingCourse[end][:a]<0.0 error("ERROR: a<0 m/s^2 in the breakFree phase !") - elseif drivingCourse[end][:a]==0.0 + elseif drivingCourse[end][:a] == 0.0 error("ERROR: a=0 m/s^2 in the breakFree phase !") end # creating the next data point push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], settings[:stepSize], CS[:id])) drivingCourse[end][:behavior] = BS[:type] - #= 07/30 TODO: the calculation is easier with these lines because the values that are 0 in the first step are not used in calculation but all in all the code gets easier without these lines: - push!(drivingCourse, createDataPoint()) - drivingCourse[end][:i]=drivingCourse[end-1][:i]+1 # incrementing the number of the data point - - # calculate s, t, v, E - if settings[:stepVariable]=="s in m" # distance step method - drivingCourse[end][:Δs]=settings[:stepSize] # step size (in m) - drivingCourse[end][:Δt]=sqrt(2*drivingCourse[end][:Δs]/drivingCourse[end-1][:a]) # step size (in s) (in this formula drivingCourse[end-1][:v] is missing because it is 0.0) - drivingCourse[end][:Δv]=sqrt(2*drivingCourse[end][:Δs]*drivingCourse[end-1][:a]) # step size (in m/s) (in this formula drivingCourse[end-1][:v] is missing because it is 0.0) - elseif settings[:stepVariable]=="t in s" # time step method - drivingCourse[end][:Δt]=settings[:stepSize] # step size (in s) - drivingCourse[end][:Δs]=drivingCourse[end][:Δt]*(drivingCourse[end][:Δt]*drivingCourse[end-1][:a])/2 # step size (in m) - drivingCourse[end][:Δv]=drivingCourse[end][:Δt]*drivingCourse[end-1][:a] # step size (in m/s) - elseif settings[:stepVariable]=="v in m/s" # velocity step method - drivingCourse[end][:Δv]=settings[:stepSize]*sign(drivingCourse[end-1][:a]) # step size (in m/s) - drivingCourse[end][:Δs]=drivingCourse[end][:Δv]^2/2/drivingCourse[end-1][:a] # step size (in m) - drivingCourse[end][:Δt]=drivingCourse[end][:Δv]/drivingCourse[end-1][:a] # step size (in s) - end #if - - #drivingCourse[end][:s]=ceil(drivingCourse[end-1][:s]+drivingCourse[end][:Δs], digits=approximationLevel) # position (in m) # rounded -> exact to 1 nm - drivingCourse[end][:s]=drivingCourse[end-1][:s]+drivingCourse[end][:Δs] # position (in m) - drivingCourse[end][:t]=drivingCourse[end-1][:t]+drivingCourse[end][:Δt] # point in time (in s) - drivingCourse[end][:v]=drivingCourse[end-1][:v]+drivingCourse[end][:Δv] # velocity (in m/s) - drivingCourse[end][:ΔW]=drivingCourse[end-1][:F_T]*drivingCourse[end][:Δs] # mechanical work in this step (in Ws) - drivingCourse[end][:W]=drivingCourse[end-1][:W]+drivingCourse[end][:ΔW] # mechanical work (in Ws) - drivingCourse[end][:ΔE]=drivingCourse[end][:ΔW] # energy consumption in this step (in Ws) - drivingCourse[end][:E]=drivingCourse[end-1][:E]+drivingCourse[end][:ΔE] # energy consumption (in Ws) - =# push!(BS[:dataPoints], drivingCourse[end][:i]) # calculate the accumulated breakFree section information - merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m) + merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m) :s_exit => drivingCourse[end][:s], # last position (in m) - :t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) - :E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws) + :t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) + :E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws) :v_exit => drivingCourse[end][:v])) # exit speed (in m/s))) - CS[:t]=CS[:t]+BS[:t] # total running time (in s) - CS[:E]=CS[:E]+BS[:E] # total energy consumption (in Ws) + CS[:t] = CS[:t] + BS[:t] # total running time (in s) + CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws) merge!(CS[:behaviorSections], Dict(:breakFree => BS)) end # else: return the characteristic section without a breakFree section @@ -324,12 +263,12 @@ end #function addBreakFreePhase! # Therefore it gets its previous driving course and the characteristic section and returns the characteristic section and driving course including the acceleration section function addAccelerationPhase!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, CSs::Vector{Dict}) if drivingCourse[end][:v]==0.0 - (CS, drivingCourse)=addBreakFreePhase!(CS, drivingCourse, settings, train, CSs) + (CS, drivingCourse) = addBreakFreePhase!(CS, drivingCourse, settings, train, CSs) end #if calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, "acceleration") if drivingCourse[end][:F_T] < drivingCourse[end][:F_R] - (CS, drivingCourse)=addDiminishingPhase!(CS, drivingCourse, settings, train, CSs) + (CS, drivingCourse) = addDiminishingPhase!(CS, drivingCourse, settings, train, CSs) calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, "acceleration") end @@ -349,12 +288,12 @@ function addAccelerationPhase!(CS::Dict, drivingCourse::Vector{Dict}, settings:: currentStepSize=settings[:stepSize] # initialize the step size that can be reduced near intersections for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation - while drivingCourse[end][:v] drivingCourse[end][:F_R] + while drivingCourse[end][:v] < CS[:v_peak] && drivingCourse[end][:s] < CS[:s_exit] && drivingCourse[end][:F_T] > drivingCourse[end][:F_R] # traction effort and resisting forces (in N) # 11/22 calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) # acceleration (in m/s^2): - drivingCourse[end][:a]=(drivingCourse[end][:F_T]-drivingCourse[end][:F_R])/train[:m_train]/train[:ξ_train] + drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train[:m_train], train[:ξ_train]) # create the next data point push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) @@ -362,7 +301,6 @@ function addAccelerationPhase!(CS::Dict, drivingCourse::Vector{Dict}, settings:: push!(BS[:dataPoints], drivingCourse[end][:i]) # calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) - if length(formerSpeedLimits) > 0 # If the tail of the train is located in a former characteristic section with lower speed limit check if is is possible to accelerate as normal (CS, drivingCourse, formerSpeedLimits, BS, endOfCsReached) = considerFormerSpeedLimits!(CS, drivingCourse, settings, train, CSs, formerSpeedLimits, BS) if endOfCsReached @@ -375,7 +313,7 @@ function addAccelerationPhase!(CS::Dict, drivingCourse::Vector{Dict}, settings:: # check which limit was reached and adjust the currentStepSize for the next cycle if cycle < approximationLevel+1 - if drivingCourse[end][:v]<=0.0 + if drivingCourse[end][:v] <= 0.0 currentStepSize = settings[:stepSize] / 10.0^cycle elseif drivingCourse[end][:s]>CS[:s_exit] @@ -385,17 +323,17 @@ function addAccelerationPhase!(CS::Dict, drivingCourse::Vector{Dict}, settings:: currentStepSize = settings[:stepSize] / 10.0^cycle end - elseif drivingCourse[end][:v]>CS[:v_peak] - if settings[:stepVariable]=="v in m/s" + elseif drivingCourse[end][:v] > CS[:v_peak] + if settings[:stepVariable] == "v in m/s" currentStepSize=CS[:v_peak]-drivingCourse[end-1][:v] else currentStepSize = settings[:stepSize] / 10.0^cycle end - elseif drivingCourse[end][:s]==CS[:s_exit] + elseif drivingCourse[end][:s] == CS[:s_exit] break - elseif drivingCourse[end][:v]==CS[:v_peak] + elseif drivingCourse[end][:v] == CS[:v_peak] break elseif drivingCourse[end][:F_T] <= drivingCourse[end][:F_R] currentStepSize = settings[:stepSize] / 10.0^cycle @@ -408,20 +346,20 @@ function addAccelerationPhase!(CS::Dict, drivingCourse::Vector{Dict}, settings:: pop!(BS[:dataPoints]) else # if the level of approximation is reached - if drivingCourse[end][:v]<=0.0 + if drivingCourse[end][:v] <= 0.0 # push!(BS[:dataPoints], drivingCourse[end][:i]) error("ERROR: The train stops during the acceleration phase in CS",CS[:id]," because the tractive effort is lower than the resistant forces.", " Before the stop the last point has the values s=",drivingCourse[end-1][:s]," m v=",drivingCourse[end-1][:v]," m/s a=",drivingCourse[end-1][:a]," m/s^2", " F_T=",drivingCourse[end-1][:F_T]," N R_traction=",drivingCourse[end-1][:R_traction]," N R_wagons=",drivingCourse[end-1][:R_wagons]," N R_path=",drivingCourse[end-1][:R_path]," N.") - elseif drivingCourse[end][:v]>CS[:v_peak] + elseif drivingCourse[end][:v] > CS[:v_peak] pop!(drivingCourse) pop!(BS[:dataPoints]) - elseif drivingCourse[end][:s]>CS[:s_exit] - drivingCourse[end][:s]=CS[:s_exit] # rounding s down to s_exit + elseif drivingCourse[end][:s] > CS[:s_exit] + drivingCourse[end][:s] = CS[:s_exit] # rounding s down to s_exit elseif drivingCourse[end][:F_T] <= drivingCourse[end][:F_R] - (CS, drivingCourse)=addDiminishingPhase!(CS, drivingCourse, settings, train, CSs) + (CS, drivingCourse) = addDiminishingPhase!(CS, drivingCourse, settings, train, CSs) calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) else @@ -430,16 +368,16 @@ function addAccelerationPhase!(CS::Dict, drivingCourse::Vector{Dict}, settings:: end end #for - if length(BS[:dataPoints]) > 1 # 11/21 new: it is possible that the acceleration starts at v_peak, accelerates a step, is to high and drops the last point. then there is only one data point which is not a section. + if length(BS[:dataPoints]) > 1 # it is possible that the acceleration starts at v_peak, accelerates a step, is to high and drops the last point. then there is only one data point which is not a section. # calculate the accumulated acceleration section information - merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m) + merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m) :s_exit => drivingCourse[end][:s], # last position (in m) - :t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) - :E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws) + :t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) + :E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws) :v_exit => drivingCourse[end][:v])) # exit speed (in m/s))) - CS[:t]=CS[:t]+BS[:t] # total running time (in s) - CS[:E]=CS[:E]+BS[:E] # total energy consumption (in Ws) + CS[:t] = CS[:t] + BS[:t] # total running time (in s) + CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws) # TODO: this warning schould not be needed. just for testing if CS[:v_peak] < drivingCourse[end][:v] @@ -457,12 +395,12 @@ end #function addAccelerationPhase! ## This function calculates the data points of the acceleration phase. function addAccelerationPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, CSs::Vector{Dict}) if drivingCourse[end][:v]==0.0 - (CS, drivingCourse)=addBreakFreePhase!(CS, drivingCourse, settings, train, CSs) + (CS, drivingCourse) = addBreakFreePhase!(CS, drivingCourse, settings, train, CSs) end #if calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, "acceleration") if drivingCourse[end][:F_T] < drivingCourse[end][:F_R] - (CS, drivingCourse)=addDiminishingPhase!(CS, drivingCourse, settings, train, CSs) + (CS, drivingCourse) = addDiminishingPhase!(CS, drivingCourse, settings, train, CSs) calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, "acceleration") end @@ -471,21 +409,21 @@ function addAccelerationPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{Dict} # 11/23 old without F_T>F_R: if drivingCourse[end][:v] < CS[:v_peak] && drivingCourse[end][:s] drivingCourse[end][:F_R] + if drivingCourse[end][:v] < CS[:v_peak] && drivingCourse[end][:s] < CS[:s_exit] && drivingCourse[end][:F_T] > drivingCourse[end][:F_R] BS = createBehaviorSection("acceleration", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) drivingCourse[end][:behavior] = BS[:type] currentStepSize=settings[:stepSize] # initialize the step size that can be reduced near intersections for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation - s_braking=max(0.0, ceil((CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking], digits=approximationLevel)) - while drivingCourse[end][:v] < CS[:v_peak] && drivingCourse[end][:s]+s_braking drivingCourse[end][:F_R] # as long as s_i + s_braking < s_CSend + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + while drivingCourse[end][:v] < CS[:v_peak] && drivingCourse[end][:s] + s_braking drivingCourse[end][:F_R] # as long as s_i + s_braking < s_CSend # 12/03 old with v>0 while drivingCourse[end][:v] < CS[:v_peak] && drivingCourse[end][:s]+s_braking0.0 && drivingCourse[end][:F_T] > drivingCourse[end][:F_R] # as long as s_i + s_braking < s_CSend #11/22 calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) # acceleration (in m/s^2): - drivingCourse[end][:a]=(drivingCourse[end][:F_T]-drivingCourse[end][:F_R])/train[:m_train]/train[:ξ_train] - # if drivingCourse[end][:a]==0.0 + drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train[:m_train], train[:ξ_train]) + # if drivingCourse[end][:a] == 0.0 # error("ERROR: a=0 m/s^2 in the acceleration phase ! with F_T=",drivingCourse[end][:F_T]," R_traction=",drivingCourse[end][:R_traction]," R_wagons=",drivingCourse[end][:R_wagons]," R_path=",drivingCourse[end][:R_path]) # end @@ -502,7 +440,7 @@ function addAccelerationPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{Dict} end end calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) - s_braking=max(0.0, ceil((CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking], digits=approximationLevel)) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) end #while # check which limit was reached and adjust the currentStepSize for the next cycle @@ -551,7 +489,7 @@ function addAccelerationPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{Dict} pop!(BS[:dataPoints]) elseif drivingCourse[end][:F_T] <= drivingCourse[end][:F_R] - (CS, drivingCourse)=addDiminishingPhase!(CS, drivingCourse, settings, train, CSs) + (CS, drivingCourse) = addDiminishingPhase!(CS, drivingCourse, settings, train, CSs) calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) else @@ -562,15 +500,15 @@ function addAccelerationPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{Dict} if length(BS[:dataPoints]) > 1 # TODO: is it still possible that it is <=1 although there is a separate diminishing phase? # calculate the accumulated acceleration section information - merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m) + merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m) :s_exit => drivingCourse[end][:s], # last position (in m) - :t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) - :E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws) + :t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) + :E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws) :v_exit => drivingCourse[end][:v])) # exit speed (in m/s))) - CS[:v_peak]=max(drivingCourse[end][:v], CS[:v_entry]) # setting v_peak to the last data points velocity which is the highest reachable value in this characteristic section or to v_entry in case it is higher when driving on a path with high resistances - CS[:t]=CS[:t]+BS[:t] # total running time (in s) - CS[:E]=CS[:E]+BS[:E] # total energy consumption (in Ws) + CS[:v_peak] = max(drivingCourse[end][:v], CS[:v_entry]) # setting v_peak to the last data points velocity which is the highest reachable value in this characteristic section or to v_entry in case it is higher when driving on a path with high resistances + CS[:t] = CS[:t] + BS[:t] # total running time (in s) + CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws) merge!(CS[:behaviorSections], Dict(:acceleration=>BS)) end @@ -597,7 +535,7 @@ function addCruisingPhase!(CS::Dict, drivingCourse::Vector{Dict}, s_cruising::Re drivingCourse[end][:behavior] = BS[:type] # TODO: necessary? - s_cruising=min(s_cruising, CS[:s_exit]-BS[:s_entry]) + s_cruising = min(s_cruising, CS[:s_exit]-BS[:s_entry]) # traction effort and resisting forces (in N) calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, "cruising") # TODO: or give BS[:type] instead of "cruising"? @@ -606,14 +544,14 @@ function addCruisingPhase!(CS::Dict, drivingCourse::Vector{Dict}, s_cruising::Re if settings[:massModel]=="homogeneous strip" && CS[:id] > 1 currentStepSize=settings[:stepSize] for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation - while drivingCourse[end][:s] < CS[:s_entry] + train[:length] && drivingCourse[end][:s]=drivingCourse[end][:F_R] #&& drivingCourse[end][:v]<=CS[:v_peak] && drivingCourse[end][:s]=drivingCourse[end][:F_R] #&& drivingCourse[end][:v]<=CS[:v_peak] && drivingCourse[end][:s]=drivingCourse[end][:F_R] #&& drivingCourse[end][:v]<=CS[:v_peak] && drivingCourse[end][:s]BS[:s_entry]+s_cruising # TODO also the following? drivingCourse[end][:s] > CSs[CS[:id]][:s_entry] + train[:length])) + if drivingCourse[end][:s] > BS[:s_entry]+s_cruising # TODO also the following? drivingCourse[end][:s] > CSs[CS[:id]][:s_entry] + train[:length])) if settings[:stepVariable] == "s in m" - currentStepSize=BS[:s_entry]+s_cruising-drivingCourse[end-1][:s] + currentStepSize=BS[:s_entry] + s_cruising-drivingCourse[end-1][:s] else currentStepSize = settings[:stepSize] / 10.0^cycle end - elseif drivingCourse[end][:s]==BS[:s_entry]+s_cruising # || drivingCourse[end][:s]==CS[:s_exit] + elseif drivingCourse[end][:s] == BS[:s_entry]+s_cruising # || drivingCourse[end][:s]==CS[:s_exit] break elseif drivingCourse[end][:F_T] < drivingCourse[end][:F_R] # if settings[:stepVariable] == "s in m" @@ -656,19 +594,16 @@ function addCruisingPhase!(CS::Dict, drivingCourse::Vector{Dict}, s_cruising::Re pop!(BS[:dataPoints]) else # if the level of approximation is reached - if drivingCourse[end][:s]>BS[:s_entry]+s_cruising + if drivingCourse[end][:s] > BS[:s_entry]+s_cruising if BS[:type] == "clearing" else pop!(drivingCourse) pop!(BS[:dataPoints]) end - # 11/21 |-> - elseif drivingCourse[end][:s]==BS[:s_entry]+s_cruising + elseif drivingCourse[end][:s] == BS[:s_entry]+s_cruising break - # 11/21 ->| elseif drivingCourse[end][:F_T] < drivingCourse[end][:F_R] - - (CS, drivingCourse)=addDiminishingPhase!(CS, drivingCourse, settings, train, CSs) + (CS, drivingCourse) = addDiminishingPhase!(CS, drivingCourse, settings, train, CSs) calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, "cruising") # s_cruising=max(0.0, s_cruising-get(CS[:behaviorSections], :diminishing, Dict(length=>0.0))[:length]) @@ -682,11 +617,11 @@ function addCruisingPhase!(CS::Dict, drivingCourse::Vector{Dict}, s_cruising::Re # TODO oder soll das lieber nach oben in den else des letzten Durchlaufs. Noch mal genauer ansehen, ob hier was doppelt gemoppelt ist # if drivingCourse[end][:s]= drivingCourse[end][:F_R] - drivingCourse[end][:a]=0.0 # acceleration (in m/s^2) + if drivingCourse[end][:s] < BS[:s_entry]+s_cruising && drivingCourse[end][:F_T] >= drivingCourse[end][:F_R] + drivingCourse[end][:a] = 0.0 # acceleration (in m/s^2) # calculate the remaining cruising way - s_cruisingRemaining=BS[:s_entry]+s_cruising-drivingCourse[end][:s] + s_cruisingRemaining=BS[:s_entry] + s_cruising-drivingCourse[end][:s] # create the next data point push!(drivingCourse, moveAStep(drivingCourse[end], "s_cruising in m", s_cruisingRemaining, CS[:id])) @@ -695,14 +630,14 @@ function addCruisingPhase!(CS::Dict, drivingCourse::Vector{Dict}, s_cruising::Re end # calculate the accumulated cruising section information - merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m) + merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m) :s_exit => drivingCourse[end][:s], # last position (in m) - :t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) - :E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws) + :t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) + :E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws) :v_exit => drivingCourse[end][:v])) # exit speed (in m/s))) - CS[:t]=CS[:t]+BS[:t] # total running time (in s) - CS[:E]=CS[:E]+BS[:E] # total energy consumption (in Ws) + CS[:t] = CS[:t] + BS[:t] # total running time (in s) + CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws) merge!(CS[:behaviorSections], Dict(Symbol(BS[:type]) => BS)) end # else: return the characteristic section without a cruising section @@ -715,43 +650,35 @@ end #function addCruisingPhase! function addDiminishingPhase!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, CSs::Vector{Dict}) calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, "diminishing") - if drivingCourse[end][:F_T] <= drivingCourse[end][:F_R] && drivingCourse[end][:v] > 0.0 && drivingCourse[end][:s] 0.0 && drivingCourse[end][:s] < CS[:s_exit] BS = createBehaviorSection("diminishing", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) drivingCourse[end][:behavior] = BS[:type] currentStepSize=settings[:stepSize] # initialize the step size that can be reduced near intersections for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation - s_braking=max(0.0, ceil((CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking], digits=approximationLevel)) - while drivingCourse[end][:F_T] <= drivingCourse[end][:F_R] && drivingCourse[end][:s]+s_braking0.0 # as long as s_i + s_braking < s_CSend - # 11/22 old without F_T<=F_R while drivingCourse[end][:s]+s_braking0.0 # as long as s_i + s_braking < s_CSend - - #11/22 calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) - + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + while drivingCourse[end][:F_T] <= drivingCourse[end][:F_R] && drivingCourse[end][:s] + s_braking < CS[:s_exit] && drivingCourse[end][:v]>0.0 # as long as s_i + s_braking < s_CSend # acceleration (in m/s^2): - drivingCourse[end][:a]=(drivingCourse[end][:F_T]-drivingCourse[end][:F_R])/train[:m_train]/train[:ξ_train] - # 11/21: old, only for cruising: - #if drivingCourse[end][:a]==0.0 - # error("ERROR: a=0 m/s^2 in the diminishing phase ! with F_T=",drivingCourse[end][:F_T]," R_traction=",drivingCourse[end][:R_traction]," R_wagons=",drivingCourse[end][:R_wagons]," R_path=",drivingCourse[end][:R_path]) - #end + drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train[:m_train], train[:ξ_train]) # create the next data point push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) drivingCourse[end][:behavior] = BS[:type] push!(BS[:dataPoints], drivingCourse[end][:i]) - s_braking=max(0.0, ceil((CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking], digits=approximationLevel)) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) end #while # check which limit was reached and adjust the currentStepSize for the next cycle if cycle < approximationLevel+1 - if drivingCourse[end][:v]<=0.0 + if drivingCourse[end][:v] <= 0.0 currentStepSize = settings[:stepSize] / 10.0^cycle elseif drivingCourse[end][:s] + s_braking > CS[:s_exit] currentStepSize = settings[:stepSize] / 10.0^cycle - elseif drivingCourse[end][:s] + s_braking==CS[:s_exit] + elseif drivingCourse[end][:s] + s_braking == CS[:s_exit] # 11/21 old without s_braking: elseif drivingCourse[end][:s]==CS[:s_exit] break @@ -766,7 +693,7 @@ function addDiminishingPhase!(CS::Dict, drivingCourse::Vector{Dict}, settings::D pop!(BS[:dataPoints]) else # if the level of approximation is reached - if drivingCourse[end][:v]<=0.0 + if drivingCourse[end][:v] <= 0.0 # push!(BS[:dataPoints], drivingCourse[end][:i]) error("ERROR: The train stops during diminishing run in CS",CS[:id]," because the maximum tractive effort is lower than the resistant forces.", " Before the stop the last point has the values s=",drivingCourse[end-1][:s]," m v=",drivingCourse[end-1][:v]," m/s a=",drivingCourse[end-1][:a]," m/s^2", @@ -785,16 +712,16 @@ function addDiminishingPhase!(CS::Dict, drivingCourse::Vector{Dict}, settings::D end end #for - if length(BS[:dataPoints]) > 1 # TODO: necessary? May it be possible that there is no diminishing because braking has to start + if length(BS[:dataPoints]) > 1 # TODO: necessary? May it be possible that there is no diminishing because braking has to start? # calculate the accumulated diminishing section information - merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m) + merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m) :s_exit => drivingCourse[end][:s], # last position (in m) - :t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) - :E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws) + :t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) + :E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws) :v_exit => drivingCourse[end][:v])) # exit speed (in m/s))) - CS[:t]=CS[:t]+BS[:t] # total running time (in s) - CS[:E]=CS[:E]+BS[:E] # total energy consumption (in Ws) + CS[:t] = CS[:t] + BS[:t] # total running time (in s) + CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws) merge!(CS[:behaviorSections], Dict(:diminishing=>BS)) end @@ -817,20 +744,20 @@ function addCoastingPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{Dict}, se currentStepSize=settings[:stepSize] # initialize the step size that can be reduced near intersections # 08/24 old for cycle in 1:3 # first cycle with normal step size, second cycle with reduced step size, third cycle with more reduced step size for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation - s_braking=ceil((CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking], digits=approximationLevel) - while drivingCourse[end][:v]>CS[:v_exit] && drivingCourse[end][:v]<=CS[:v_peak] && drivingCourse[end][:s] + s_braking < CS[:s_exit] # as long as s_i + s_braking < s_CSend + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + while drivingCourse[end][:v] > CS[:v_exit] && drivingCourse[end][:v] <= CS[:v_peak] && drivingCourse[end][:s] + s_braking < CS[:s_exit] # as long as s_i + s_braking < s_CSend # traction effort and resisting forces (in N): calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) # acceleration (in m/s^2): - drivingCourse[end][:a]=(drivingCourse[end][:F_T]-drivingCourse[end][:F_R])/train[:m_train]/train[:ξ_train] + drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train[:m_train], train[:ξ_train]) # creating the next data point push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) drivingCourse[end][:behavior] = BS[:type] push!(BS[:dataPoints], drivingCourse[end][:i]) - s_braking=ceil((CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking]) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) end # while @@ -875,19 +802,28 @@ function addCoastingPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{Dict}, se pop!(BS[:dataPoints]) elseif drivingCourse[end][:v] > CS[:v_peak] # if the train gets to fast it has to brake # TODO: if accelereation and coasting functions will be combined this case is different for coasting and also the order of if cases is different + # delete last data point because it went to far + pop!(drivingCourse) + pop!(BS[:dataPoints]) + # while coasting the train brakes to hold v_peak (only one data point in the end of coasting is calculated like cruising at v_peak) - drivingCourse[end-1][:a]=0.0 - s_braking=ceil((CS[:v_exit]^2-drivingCourse[end-1][:v]^2)/2/train[:a_braking]) + drivingCourse[end][:a] = 0.0 + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) # recalculate s, t, v, E + s_constantCoasting = min(currentStepSize, CS[:s_exit] - (drivingCourse[end-1][:s] + s_braking)) # TODO: if settings[:stepVariable]=="s in m" + push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], s_constantCoasting, CS[:id])) + drivingCourse[end][:behavior] = BS[:type] + push!(BS[:dataPoints], drivingCourse[end][:i]) + #= #drivingCourse[end][:Δs]= CS[:s_exit]-drivingCourse[end-1][:s] - s_braking # step size (in m) # TODO: the coasting section is currently realised with using distance steps. For example t_braking could also be used - drivingCourse[end][:Δs]=min(currentStepSize, CS[:s_exit]-(drivingCourse[end-1][:s]+s_braking)) # TODO: if settings[:stepVariable]=="s in m" - drivingCourse[end][:Δt]=drivingCourse[end][:Δs]/drivingCourse[end-1][:v] # step size (in s) - drivingCourse[end][:Δv]=0.0 # step size (in m/s) + drivingCourse[end][:Δs] = min(currentStepSize, CS[:s_exit] - (drivingCourse[end-1][:s] + s_braking)) # TODO: if settings[:stepVariable]=="s in m" + drivingCourse[end][:Δt] = drivingCourse[end][:Δs]/drivingCourse[end-1][:v] # step size (in s) + drivingCourse[end][:Δv] = 0.0 # step size (in m/s) - drivingCourse[end][:s]=drivingCourse[end-1][:s]+drivingCourse[end][:Δs] # position (in m) - drivingCourse[end][:t]=drivingCourse[end-1][:t]+drivingCourse[end][:Δt] # point in time (in s) - drivingCourse[end][:v]=drivingCourse[end-1][:v] # velocity (in m/s) + drivingCourse[end][:s] = drivingCourse[end-1][:s] + drivingCourse[end][:Δs] # position (in m) + drivingCourse[end][:t] = drivingCourse[end-1][:t] + drivingCourse[end][:Δt] # point in time (in s) + drivingCourse[end][:v] = drivingCourse[end-1][:v] # velocity (in m/s) drivingCourse[end][:ΔW]=drivingCourse[end-1][:F_T]*drivingCourse[end][:Δs] # mechanical work in this step (in Ws) # =0.0 @@ -897,6 +833,7 @@ function addCoastingPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{Dict}, se # =0.0 drivingCourse[end][:E]=drivingCourse[end-1][:E]+drivingCourse[end][:ΔE] # energy consumption (in Ws) # =drivingCourse[end-1][:E] + =# else end @@ -904,14 +841,14 @@ function addCoastingPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{Dict}, se end #for # calculate the accumulated coasting section information - merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m) + merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m) :s_exit => drivingCourse[end][:s], # last position (in m) - :t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) - :E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws) + :t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) + :E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws) :v_exit => drivingCourse[end][:v])) # exit speed (in m/s))) - CS[:t]=CS[:t]+BS[:t] # total running time (in s) - CS[:E]=CS[:E]+BS[:E] # total energy consumption (in Ws) + CS[:t] = CS[:t] + BS[:t] # total running time (in s) + CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws) merge!(CS[:behaviorSections], Dict(:coasting=>BS)) end ## else: just return the given data point number without changes due to the coasting phase @@ -925,7 +862,7 @@ function addBrakingPhase!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, # function addBrakingPhase!(CS::Dict, drivingCourse::Vector{Dict}, massModel::String, train::Dict, CSs::Vector{Dict}) #, s_braking::AbstractFloat) if drivingCourse[end][:v]>CS[:v_exit] && drivingCourse[end][:s]=0.0 println("") println("Warning: a_braking gets to high in CS ",CS[:id], " with a=",drivingCourse[end-1][:a] ," > ",train[:a_braking]) @@ -951,22 +888,22 @@ function addBrakingPhase!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, println(" v_exit=",CS[:v_exit]) println("") end =# - drivingCourse[end][:Δt]=drivingCourse[end][:Δv]/drivingCourse[end-1][:a] # step size (in s) - drivingCourse[end][:t]=drivingCourse[end-1][:t]+drivingCourse[end][:Δt] # point in time (in s) + drivingCourse[end][:Δt] = drivingCourse[end][:Δv] / drivingCourse[end-1][:a] # step size (in s) + drivingCourse[end][:t] = drivingCourse[end-1][:t] + drivingCourse[end][:Δt] # point in time (in s) - drivingCourse[end][:ΔW]=0.0 # mechanical work in this step (in Ws) - drivingCourse[end][:W]=drivingCourse[end-1][:W]+drivingCourse[end][:ΔW] # mechanical work (in Ws) - drivingCourse[end][:ΔE]=drivingCourse[end][:ΔW] # energy consumption in this step (in Ws) - drivingCourse[end][:E]=drivingCourse[end-1][:E]+drivingCourse[end][:ΔE] # energy consumption (in Ws) + drivingCourse[end][:ΔW] = 0.0 # mechanical work in this step (in Ws) + drivingCourse[end][:W] = drivingCourse[end-1][:W] + drivingCourse[end][:ΔW] # mechanical work (in Ws) + drivingCourse[end][:ΔE] = drivingCourse[end][:ΔW] # energy consumption in this step (in Ws) + drivingCourse[end][:E] = drivingCourse[end-1][:E] + drivingCourse[end][:ΔE] # energy consumption (in Ws) - merge!(BS, Dict(:length => drivingCourse[end][:Δs], # total length (in m) + merge!(BS, Dict(:length => drivingCourse[end][:Δs], # total length (in m) #:s_exit => drivingCourse[end][:s], # last position (in m) :t => drivingCourse[end][:Δt], # total running time (in s) :E => drivingCourse[end][:ΔE], # total energy consumption (in Ws) :v_exit => drivingCourse[end][:v])) # exit speed (in m/s))) - CS[:t]=CS[:t]+BS[:t] # total running time (in s) - CS[:E]=CS[:E]+BS[:E] # total energy consumption (in Ws) + CS[:t] = CS[:t] + BS[:t] # total running time (in s) + CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws) merge!(CS[:behaviorSections], Dict(:braking=>BS)) end # else: return the characteristic section without a braking section @@ -982,19 +919,19 @@ function addBrakingPhaseStepwise!(CS::Dict, drivingCourse::Vector{Dict}, setting drivingCourse[end][:behavior] = BS[:type] currentStepSize=settings[:stepSize] # initialize the step size that can be reduced near intersections - velocityIsPositive=true + velocityIsPositive = true while drivingCourse[end][:v] > CS[:v_exit] && drivingCourse[end][:s] < CS[:s_exit] && velocityIsPositive # traction effort and resisting forces (in N): calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) # acceleration (in m/s^2): - drivingCourse[end][:a]=train[:a_braking] + drivingCourse[end][:a] = train[:a_braking] # creating the next data point #TODO moveAStep should give back true or false for success or failure e.g. with dropping below v=0 m/s #at the moment it is only for stepVariable=="s in m" - if settings[:stepVariable]=="s in m" + if settings[:stepVariable] == "s in m" if ((drivingCourse[end][:v]/drivingCourse[end][:a])^2+2*currentStepSize/drivingCourse[end][:a])<0.0 || (drivingCourse[end][:v]^2+2*currentStepSize*drivingCourse[end][:a])<0.0 velocityIsPositive=false break @@ -1004,44 +941,43 @@ function addBrakingPhaseStepwise!(CS::Dict, drivingCourse::Vector{Dict}, setting drivingCourse[end][:behavior] = BS[:type] push!(BS[:dataPoints], drivingCourse[end][:i]) - # s_braking=ceil((CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking]) + # s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) end # while if drivingCourse[end][:v] < CS[:v_exit] || !velocityIsPositive # calculate s, t, v - drivingCourse[end][:s]=CS[:s_exit] # position (in m) - drivingCourse[end][:v]=CS[:v_exit] # velocity (in m/s) - drivingCourse[end][:Δs]=drivingCourse[end][:s]-drivingCourse[end-1][:s] # step size (in m) - drivingCourse[end][:Δv]=drivingCourse[end][:v]-drivingCourse[end-1][:v] # step size (in m/s) - - #drivingCourse[end-1][:a]=round((drivingCourse[end][:v]^2-drivingCourse[end-1][:v]^2)/2/drivingCourse[end][:Δs], digits=approximationLevel) # acceleration (in m/s^2) (rounding because it should not be less than a_braking) - drivingCourse[end-1][:a]=(drivingCourse[end][:v]^2-drivingCourse[end-1][:v]^2)/2/drivingCourse[end][:Δs] # acceleration (in m/s^2) + drivingCourse[end][:s] = CS[:s_exit] # position (in m) + drivingCourse[end][:v] = CS[:v_exit] # velocity (in m/s) + drivingCourse[end][:Δs] = drivingCourse[end][:s] - drivingCourse[end-1][:s] # step size (in m) + drivingCourse[end][:Δv] = drivingCourse[end][:v] - drivingCourse[end-1][:v] # step size (in m/s) + #drivingCourse[end-1][:a]=round(calcBrakingAcceleration(drivingCourse[end-1][:v], drivingCourse[end][:v], drivingCourse[end][:Δs]), digits=approximationLevel) # acceleration (in m/s^2) (rounding because it should not be less than a_braking) + drivingCourse[end-1][:a] = calcBrakingAcceleration(drivingCourse[end-1][:v], drivingCourse[end][:v], drivingCourse[end][:Δs]) # if drivingCourse[end-1][:a]=0.0 # println("Warning: a_braking gets to high in CS ",CS[:id], " with a=",drivingCourse[end-1][:a] ," > ",train[:a_braking]) # end - drivingCourse[end][:Δt]=drivingCourse[end][:Δv]/drivingCourse[end-1][:a] # step size (in s) - drivingCourse[end][:t]=drivingCourse[end-1][:t]+drivingCourse[end][:Δt] # point in time (in s) + drivingCourse[end][:Δt] = drivingCourse[end][:Δv] / drivingCourse[end-1][:a] # step size (in s) + drivingCourse[end][:t] = drivingCourse[end-1][:t] + drivingCourse[end][:Δt] # point in time (in s) - drivingCourse[end][:ΔW]=0.0 # mechanical work in this step (in Ws) - drivingCourse[end][:W]=drivingCourse[end-1][:W]+drivingCourse[end][:ΔW] # mechanical work (in Ws) - drivingCourse[end][:ΔE]=drivingCourse[end][:ΔW] # energy consumption in this step (in Ws) - drivingCourse[end][:E]=drivingCourse[end-1][:E]+drivingCourse[end][:ΔE] # energy consumption (in Ws) + drivingCourse[end][:ΔW] = 0.0 # mechanical work in this step (in Ws) + drivingCourse[end][:W] = drivingCourse[end-1][:W] + drivingCourse[end][:ΔW] # mechanical work (in Ws) + drivingCourse[end][:ΔE] = drivingCourse[end][:ΔW] # energy consumption in this step (in Ws) + drivingCourse[end][:E] = drivingCourse[end-1][:E] + drivingCourse[end][:ΔE] # energy consumption (in Ws) elseif drivingCourse[end][:s] > CS[:s_exit] - error("Beim Bremsen wurde das CS-Ende überschritten, aber nicht v_exit unterschritten !!") + error("At the end of braking: s>s_exit but v>v_exit") else end # calculate the accumulated coasting section information - merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m) + merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m) :s_exit => drivingCourse[end][:s], # last position (in m) - :t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) - :E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws) + :t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) + :E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws) :v_exit => drivingCourse[end][:v])) # exit speed (in m/s))) - CS[:t]=CS[:t]+BS[:t] # total running time (in s) - CS[:E]=CS[:E]+BS[:E] # total energy consumption (in Ws) + CS[:t] = CS[:t] + BS[:t] # total running time (in s) + CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws) merge!(CS[:behaviorSections], Dict(:braking=>BS)) end # else: return the characteristic section without a braking section @@ -1052,12 +988,11 @@ end #function addBrakingPhaseStepwise! ## This function calculates the data point of the standstill. # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the standstill if needed. function addStandstill!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, CSs::Vector{Dict}) - if drivingCourse[end][:v] == 0.0 BS = createBehaviorSection("standstill", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) merge!(BS, Dict(:length => 0.0, # total length (in m) - :t => 0.0, # total running time (in s) - :E => 0.0, # total energy consumption (in Ws) + :t => 0.0, # total running time (in s) + :E => 0.0, # total energy consumption (in Ws) :s_exit => drivingCourse[end][:s], # last position (in m) :v_exit => drivingCourse[end][:v])) # exit speed (in m/s))) drivingCourse[end][:behavior] = BS[:type] @@ -1111,4 +1046,4 @@ function createDataPoint() return dataPoint end #function createDataPoint -end #module MovingPhases +end #module Behavior diff --git a/src/DrivingDynamics.jl b/src/DrivingDynamics.jl new file mode 100644 index 0000000..71089c8 --- /dev/null +++ b/src/DrivingDynamics.jl @@ -0,0 +1,221 @@ +module DrivingDynamics + +# export resisting forces and acceleration +export calcTractionUnitResistance, calcWagonsResistance, calcForceFromCoefficient, calcAcceleration, + +# export step sizes in different units +calc_Δs_with_Δt, calc_Δs_with_Δv, +calc_Δt_with_Δs, calc_Δt_with_Δv, calc_Δt_with_constant_v, +calc_Δv_with_Δs, calc_Δv_with_Δt, +calc_ΔW, calc_ΔE, + +# export braking information +calcBrakingDistance, calcBrakingStartVelocity, calcBrakingAcceleration + +# literature the driving dynamics equations are based on: +# - Brünger, Olaf and Dahlhaus, Elias. 2014. Running Time Estimation. [book authors] Ingo Arne Hansen and Jörn Pachl. Railway Timetabling & Operations. Analysis Modelling Optimisation Simulation Performance Evaluation. Hamburg : Eurailpress DVV Media Group, 2014, edtition 2, chapter 4. +# - Jaekel, Birgit and Albrecht, Thomas. 2014. Comparative analysis of algorithms and models for train running simulation. Journal of Rail Transport Planning & Management. 2014. +# - Wende, Dietrich. 2003. Fahrdynamik des Schienenverkehrs. Wiesbaden : Vieweg + Teubner, 2003. edition 1. + +v00 = 100/3.6 # velocity constant (in m/s) +g = 9.81 # acceleration due to gravity (in m/s^2) # TODO: should more digits of g be used? g=9,80665 m/s^2 + +approximationLevel = 6 # value for approximation to intersections TODO further explanation (e.g. approximationLevel = 3 -> with stepSize 10 m the approximation will be calculated accurate on 10 mm ; 1s -> 1 ms; 1 km/h -> 3.6 mm/s) +# TODO: necessary here? + + +## calculate forces + +#TODO: replace the ? ? ? +""" + calcTractionUnitResistance(v, train) + +Calculate the vehicle resistance for the traction unit of the `train` dependend on the velocity `v`. + +... +# Arguments +- `v::AbstractFloat`: the current velocity in m/s. +- `train::Dict`: ? ? ? +... + +# Examples +```julia-repl +julia> calcTractionUnitResistance(30.0, ? ? ?) +? ? ? +``` +""" +function calcTractionUnitResistance(v::AbstractFloat, train::Dict) + # equation is based on Wende, page 151 + f_Rtd0 = train[:f_Rtd0] # coefficient for basic resistance due to the traction units driving axles (in ‰) + f_Rtc0 = train[:f_Rtc0] # coefficient for basic resistance due to the traction units carring axles (in ‰) + F_Rt2 = train[:F_Rt2] # coefficient for air resistance of the traction units (in N) + m_td = train[:m_td] # mass on the traction unit's driving axles (in kg) + m_tc = train[:m_tc] # mass on the traction unit's carrying axles (in kg) + Δv_t = train[:Δv_t] # coefficient for velocitiy difference between traction unit and outdoor air (in m/s) + + F_R_tractionUnit = f_Rtd0/1000 * m_td * g + f_Rtc0/1000 * m_tc * g + F_Rt2 * ((v + Δv_t) /v00)^2 # vehicle resistance of the traction unit (in N) # /1000 because of the unit ‰ + # TODO: use calcForceFromCoefficient? F_R_tractionUnit = calcForceFromCoefficient(f_Rtd0, m_td) + calcForceFromCoefficient(f_Rtc0, m_tc) + F_Rt2 * ((v + Δv_t) /v00)^2 # vehicle resistance of the traction unit (in N) + return F_R_tractionUnit + #TODO: same variable name like in the rest of the tool? return R_traction + #TODO: just one line? return train[:f_Rtd0]/1000*train[:m_td]*g+train[:f_Rtc0]/1000*train[:m_tc]*g+train[:F_Rt2]*((v+train[:Δv_t])/v00)^2 # /1000 because of the unit ‰ +end #function calcTractionUnitResistance + +""" +TODO +calculate and return the wagons vehicle resistance dependend on the velocity +""" +function calcWagonsResistance(v::AbstractFloat, train::Dict) + # equation is based on a combination of the equations of Strahl and Sauthoff (Wende, page 153) with more detailled factors (Lehmann, page 135) + f_Rw0 = train[:f_Rw0] # coefficient for basic resistance of the set of wagons (consist) (in ‰) + f_Rw1 = train[:f_Rw1] # coefficient for the consists resistance to rolling (in ‰) + f_Rw2 = train[:f_Rw2] # coefficient fo the consistsr air resistance (in ‰) + m_w = train[:m_w] # mass of the set of wagons (consist) (in kg) + Δv_w = train[:Δv_w] # coefficient for velocitiy difference between set of wagons (consist) and outdoor air (in m/s) + + F_R_wagons = m_w *g *(f_Rw0/1000 + f_Rw1/1000 *v /v00 + f_Rw2/1000 * ((v + Δv_w) /v00)^2) # vehicle resistance of the wagons (in N) # /1000 because of the unit ‰ +# TODO: use calcForceFromCoefficient? F_R_wagons = calcForceFromCoefficient(f_Rw0, m_w) + calcForceFromCoefficient(f_Rw1, m_w) *v /v00 + calcForceFromCoefficient(f_Rw2, m_w) * ((v + Δv_w) /v00)^2 # vehicle resistance of the wagons (in N) + return F_R_wagons +end #function calcWagonsResistance + +function calcForceFromCoefficient(f_R::Real, m::Real) + # equation is based on Wende, page 8 + + # f_R: specific resistance (in ‰) + # m: vehicle's mass (in kg) + + F_R = f_R /1000 *m *g # Resisting Force (in N) # /1000 because of the unit ‰ + return F_R +end #function calcForceFromCoefficient + +function calcAcceleration(F_T::Real, F_R::Real, m_train::Real, ξ_train::Real) + # equation is based on Brünger et al., page 72 with a=dv/dt + + # F_T: tractive effort (in N) + # F_R: resisting forces (in N) + # m_train: train's mass (in kg) + # ξ_train: train's rotation mass factor (without unit) + + a = (F_T - F_R) /m_train /ξ_train # acceleration (in m/s) + return a +end #function calcAcceleration + +function calc_Δs_with_Δt(Δt::Real, a_prev::Real, v_prev::Real) + # equation is based on Wende, page 37 + + # Δt: time step (in s) + # a_prev: acceleration from previous data point + # v_prev: velocitiy from previous data point + Δs = Δt * (2*v_prev + Δt*a_prev) /2 # step size (in m) + return Δs +end #function calc_Δs_with_Δt + +function calc_Δs_with_Δv(Δv::Real, a_prev::Real, v_prev::Real) + # equation is based on Wende, page 37 + + # Δv: velocity step (in m/s) + # a_prev: acceleration from previous data point + # v_prev: velocitiy from previous data point + Δs = ((v_prev + Δv)^2 - v_prev^2)/2/a_prev # step size (in m) + return Δs +end #function calc_Δs_with_Δv + +function calc_Δt_with_Δs(Δs::Real, a_prev::Real, v_prev::Real) + # equation is based on Wende, page 37 + + # Δs: distance step (in m) + # a_prev: acceleration from previous data point + # v_prev: velocitiy from previous data point + + Δt = sign(a_prev) *sqrt((v_prev /a_prev)^2 + 2 *Δs /a_prev) - v_prev /a_prev # step size (in m/s) + return Δt +end #function calc_Δt_with_Δs + +function calc_Δt_with_Δv(Δv::Real, a_prev::Real) + # equation is based on Wende, page 37 + + # Δv: velocity step (in m/s) + # a_prev: acceleration from previous data point + Δt = Δv /a_prev # step size (in s) + return Δt +end #function calc_Δt_with_Δv + +function calc_Δt_with_constant_v(Δs::Real, v::Real) + # equation is based on Wende, page 37 + + # Δs: distance step (in m) + # v: constant velocity (in m/s) + Δt = Δs /v # step size (in s) + return Δt +end #function calc_Δt_with_constant_v + +function calc_Δv_with_Δs(Δs::Real, a_prev::Real, v_prev::Real) + # equation is based on Wende, page 37 + + # Δs: distance step (in m) + # a_prev: acceleration from previous data point + # v_prev: velocitiy from previous data point + Δv = sqrt(v_prev^2 + 2*Δs*a_prev) - v_prev # step size (in m/s) + return Δv +end #function calc_Δv_with_Δs + +function calc_Δv_with_Δt(Δt::Real, a_prev::Real) + # equation is based on Wende, page 37 + + # Δt: time step (in s) + # a_prev: acceleration from previous data point + # v_prev: velocitiy from previous data point + Δv = Δt * a_prev # step size (in m/s) + return Δv +end #function calc_Δv_with_Δt + + + +function calc_ΔW(F_T_prev::Real, Δs::Real) + # equation is based on Wende, page 17 + + # F_T_prev: tractive force from previous data point + # Δs: distance step + ΔW = F_T_prev * Δs # mechanical work in this step (in Ws) + return ΔW +end #function calc_ΔW + +function calc_ΔE(ΔW::Real) + # simplified equation is based on Jaekel et al., page 6 + + # ΔW: mechanical work in this step (in Ws) + ΔE = ΔW # energy consumption in this step (in Ws) + return ΔE +end #function calc_ΔW + +function calcBrakingDistance(v_start::Real, v_end::Real, a_braking::Real) + # equation is based on Wende, page 37 + + # v_start: velocity at the start of braking (in m/s) + # v_end: target velocity at the end of braking (in m/s) + # a_braking: constant braking acceleration (in m/s^2) + s_braking = (v_end^2 - v_start^2) /2 /a_braking # braking distance (in m) + # TODO: also possible: calc_Δs_with_Δv(v_end-v_start, a_braking, v_start) + return max(0.0, ceil(s_braking, digits=approximationLevel)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors +end #function calcBrakingDistance + +function calcBrakingStartVelocity(v_end::Real, a_braking::Real, s_braking::Real) + # equation is based on Wende, page 37 + + # v_end: target velocity at the end of braking (in m/s) + # a_braking: constant braking acceleration (in m/s^2) + # s_braking: braking distance (in Ws) + v_start = sqrt(v_end^2 - 2*a_braking *s_braking) # braking start velocity (in m/s) + return floor(v_start, digits=approximationLevel) +end #function calcBrakingStartVelocity + +function calcBrakingAcceleration(v_start::Real, v_end::Real, s_braking::Real) + # equation is based on Wende, page 37 + + # v_start: braking start velocity (in m/s) + # v_end: target velocity at the end of braking (in m/s) + # s_braking: braking distance (in Ws) + a_braking = (v_end^2 - v_start^2) /2 /s_braking # constant braking acceleration (in m/s^2) + return a_braking +end #function calcBrakingAcceleration + +end #module DrivingDynamics diff --git a/src/EnergySaving.jl b/src/EnergySaving.jl index 6b34dbe..99eec70 100644 --- a/src/EnergySaving.jl +++ b/src/EnergySaving.jl @@ -1,16 +1,17 @@ # INFO: EnergySaving should not be used because it is not completed yet. It was used to show the possiility of calculating different operation modes. -# TODO: It has to be optimized so that each ernergy saving merhode is working individually for every train on every path. +# TODO: It has to be optimized so that each ernergy saving method is working individually for every train on every path. # TODO: calculation time for passenger trains on path1 is very long and should be reduced -#TODO: Test if enum trainType is working correctly in function calculateRecoveryTime or if only the else-pathis taken +# TODO from 2022/01/18: Test if enum trainType is working correctly in function calculateRecoveryTime or if only the else-pathis taken +# TODO from 2022/01/19: Are here calculations that should be transferred to DrivingDynamics.jl? module EnergySaving # include modules of TrainRunCalc -include("./MovingPhases.jl") +include("./Behavior.jl") # use modules of TrainRunCalc -using .MovingPhases +using .Behavior export addOperationModeEnergySaving! @@ -596,11 +597,11 @@ function increaseCoastingSection(csOriginal::Dict, drivingCourse::Vector{Dict}, # calculate the new and now shorter cruising section if s_cruising>0.0 - (csModified, drivingCourseModified)=addCruisingPhase!(csModified, drivingCourseModified, s_cruising, settings, train, allCSs, "cruising") + (csModified, drivingCourseModified)=addCruisingSection!(csModified, drivingCourseModified, s_cruising, settings, train, allCSs, "cruising") end # calculate the coasting phase until the point the train needs to brake - (csModified, drivingCourseModified)=addCoastingPhaseUntilBraking!(csModified, drivingCourseModified, settings, train, allCSs) + (csModified, drivingCourseModified)=addCoastingSectionUntilBraking!(csModified, drivingCourseModified, settings, train, allCSs) if drivingCourseModified[end][:v] < csModified[:v_exit] || drivingCourseModified[end][:s] > csModified[:s_exit] # the train reaches v_exit before reaching s_exit. The cruising and coasting sections have to be calculated again with a larger cruising section (so with a smaller reduction of the cruising section) @@ -612,8 +613,8 @@ function increaseCoastingSection(csOriginal::Dict, drivingCourse::Vector{Dict}, # calculate the moving phase between coasting and the end of the CS if drivingCourseModified[end][:v] > csModified[:v_exit] - #(csModified, drivingCourseModified)=addBrakingPhase!(csModified, drivingCourseModified, settings[:massModel], train, allCSs) - (csModified, drivingCourseModified)=addBrakingPhase!(csModified, drivingCourseModified, settings, train, allCSs) + #(csModified, drivingCourseModified)=addBrakingSection!(csModified, drivingCourseModified, settings[:massModel], train, allCSs) + (csModified, drivingCourseModified)=addBrakingSection!(csModified, drivingCourseModified, settings, train, allCSs) end if t_recoveryAvailable < csModified[:t]-csOriginal[:t] || drivingCourseModified[end][:v] != csModified[:v_exit] || drivingCourseModified[end][:s] != csModified[:s_exit] # time loss is to high and the CS has to be calculated again with larger cruising section (so with a smaller reduction of the cruising section) or v_exit or s_exit are not reached excatly @@ -729,11 +730,11 @@ function increaseCoastingSection(csOriginal::Dict, drivingCourse::Vector{Dict}, # calculate the new and now shorter cruising section if s_cruising>0.0 - (csModified, drivingCourseModified)=addCruisingPhase!(csModified, drivingCourseModified, s_cruising, settings, train, allCSs, "cruising") + (csModified, drivingCourseModified)=addCruisingSection!(csModified, drivingCourseModified, s_cruising, settings, train, allCSs, "cruising") end # calculate the coasting phase until the point the train needs to brake - (csModified, drivingCourseModified)=addCoastingPhaseUntilBraking!(csModified, drivingCourseModified, settings, train, allCSs) + (csModified, drivingCourseModified)=addCoastingSectionUntilBraking!(csModified, drivingCourseModified, settings, train, allCSs) if drivingCourseModified[end][:v] < csModified[:v_exit] || drivingCourseModified[end][:s] > csModified[:s_exit] # the train reaches v_exit before reaching s_exit. The cruising and coasting sections have to be calculated again with a larger cruising section (so with a smaller reduction of the cruising section) @@ -745,8 +746,8 @@ function increaseCoastingSection(csOriginal::Dict, drivingCourse::Vector{Dict}, # calculate the moving phase between coasting and the end of the CS if drivingCourseModified[end][:v] > csModified[:v_exit] - #(csModified, drivingCourseModified)=addBrakingPhase!(csModified, drivingCourseModified, settings[:massModel], train, allCSs) - (csModified, drivingCourseModified)=addBrakingPhase!(csModified, drivingCourseModified, settings, train, allCSs) + #(csModified, drivingCourseModified)=addBrakingSection!(csModified, drivingCourseModified, settings[:massModel], train, allCSs) + (csModified, drivingCourseModified)=addBrakingSection!(csModified, drivingCourseModified, settings, train, allCSs) end if t_recoveryAvailable < csModified[:t]-csOriginal[:t] || drivingCourseModified[end][:v] != csModified[:v_exit] || drivingCourseModified[end][:s] != csModified[:s_exit] # time loss is to high and the CS has to be calculated again with larger cruising section (so with a smaller reduction of the cruising section) or v_exit or s_exit are not reached excatly @@ -826,11 +827,11 @@ function increaseCoastingSection(csOriginal::Dict, drivingCourse::Vector{Dict}, drivingCourseModified = copy(drivingCourse[1:energySavingStartId]) # List of data points till the start of energy saving # calculate the coasting phase until the point the train needs to brake - (csModified, drivingCourseModified)=addCoastingPhaseUntilBraking!(csModified, drivingCourseModified, settings, train, allCSs) + (csModified, drivingCourseModified)=addCoastingSectionUntilBraking!(csModified, drivingCourseModified, settings, train, allCSs) # calculate the moving phase between coasting and the end of the CS if drivingCourseModified[end][:v] > csModified[:v_exit] - (csModified, drivingCourseModified)=addBrakingPhase!(csModified, drivingCourseModified, settings, train, allCSs) + (csModified, drivingCourseModified)=addBrakingSection!(csModified, drivingCourseModified, settings, train, allCSs) end if t_recoveryAvailable >= csModified[:t] - csOriginal[:t] @@ -928,20 +929,19 @@ function decreaseMaximumVelocity(csOriginal::Dict, drivingCourse, settings::Dict # copy the drivingCourse till the beginning of energy saving drivingCourseModified = copy(drivingCourse[1:energySavingStartId]) # List of data points till the start of energy saving - #s_braking=max(0.0, ceil((csModified[:v_exit]^2-csModified[:v_peak]^2)/2/train[:a_braking], digits=approximationLevel)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors - s_braking=max(0.0, ceil((csModified[:v_exit]^2-drivingCourseModified[end][:v]^2)/2/train[:a_braking], digits=approximationLevel)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors - s_cruising=csModified[:s_exit]-drivingCourseModified[end][:s]-s_braking + s_braking = calcBrakingDistance(drivingCourseModified[end][:v], csModified[:v_exit], train[:a_braking]) + s_cruising = csModified[:s_exit]-drivingCourseModified[end][:s]-s_braking if s_cruising > 1/10^approximationLevel # 01/09 old if s_cruising > 0.001 - (csModified, drivingCourseModified)=addCruisingPhase!(csModified, drivingCourseModified, s_cruising, settings, train, allCSs, "cruising") + (csModified, drivingCourseModified)=addCruisingSection!(csModified, drivingCourseModified, s_cruising, settings, train, allCSs, "cruising") end #if # s_brakingAfterCruising=ceil((csModified[:v_exit]^2-drivingCourseModified[end][:v]^2)/2/train[:a_braking], digits=10) # TODO: check if s_braking and s_brakingAfterCruising are really always the same if drivingCourseModified[end][:v]>csModified[:v_exit] - #(csModified, drivingCourseModified)=addBrakingPhase!(csModified, drivingCourseModified, settings[:massModel], train, allCSs) - (csModified, drivingCourseModified)=addBrakingPhase!(csModified, drivingCourseModified, settings, train, allCSs) + #(csModified, drivingCourseModified)=addBrakingSection!(csModified, drivingCourseModified, settings[:massModel], train, allCSs) + (csModified, drivingCourseModified)=addBrakingSection!(csModified, drivingCourseModified, settings, train, allCSs) elseif drivingCourseModified[end][:s]0.001 diff --git a/src/Preparation.jl b/src/Preparation.jl index 862416e..eb7f38a 100644 --- a/src/Preparation.jl +++ b/src/Preparation.jl @@ -1,7 +1,7 @@ module Preparation -include("./MovingPhases.jl") -using .MovingPhases +include("./Behavior.jl") +using .Behavior export preparateSections @@ -26,10 +26,12 @@ function createMovingSection(path::Dict, v_trainLimit::Real) s_csStart=s_entry csId=1 for row in 2:length(path[:sections]) - if min(path[:sections][row-1][:v_limit], v_trainLimit) != min(path[:sections][row][:v_limit], v_trainLimit) || path[:sections][row-1][:f_Rp] != path[:sections][row][:f_Rp] - push!(CSs, createCharacteristicSection(csId, s_csStart, path[:sections][row-1], min(path[:sections][row-1][:v_limit], v_trainLimit))) - s_csStart=path[:sections][row][:s_start] - csId=csId+1 + previousSection = path[:sections][row-1] + currentSection = path[:sections][row] + if min(previousSection[:v_limit], v_trainLimit) != min(currentSection[:v_limit], v_trainLimit) || previousSection[:f_Rp] != currentSection[:f_Rp] + push!(CSs, createCharacteristicSection(csId, s_csStart, previousSection, min(previousSection[:v_limit], v_trainLimit))) + s_csStart = currentSection[:s_start] + csId = csId+1 end #if end #for push!(CSs, createCharacteristicSection(csId, s_csStart, path[:sections][end], min(path[:sections][end][:v_limit], v_trainLimit))) @@ -70,15 +72,15 @@ function secureBrakingBehavior!(movingSection::Dict, a_braking::Real) # this function limits the entry and exit velocity of the characteristic sections to secure that the train stops at the moving sections end CSs = movingSection[:characteristicSections] - csId=length(CSs) - CSs[csId][:v_exit]=0.0 # the exit velocity of the last characteristic section is 0.0 m/s + csId = length(CSs) + CSs[csId][:v_exit] = 0.0 # the exit velocity of the last characteristic section is 0.0 m/s while csId >= 1 - v_entryMax=sqrt(CSs[csId][:v_exit]^2-2*a_braking*CSs[csId][:length]) - v_entryMax=floor(v_entryMax, digits=12) + v_entryMax = calcBrakingStartVelocity(CSs[csId][:v_exit], a_braking, CSs[csId][:length]) + #v_entryMax=floor(v_entryMax, digits=12) - CSs[csId][:v_entry]=min(CSs[csId][:v_limit], v_entryMax) - CSs[csId][:v_peak]=CSs[csId][:v_entry] - csId=csId-1 + CSs[csId][:v_entry] = min(CSs[csId][:v_limit], v_entryMax) + CSs[csId][:v_peak] = CSs[csId][:v_entry] + csId = csId - 1 if csId >= 1 CSs[csId][:v_exit]=min(CSs[csId][:v_limit], CSs[csId+1][:v_entry]) end #if @@ -91,20 +93,20 @@ function secureAccelerationBehavior!(movingSection::Dict, settings::Dict, train: # this function limits the entry and exit velocity of the characteristic sections in case that the train accelerates in every section and cruises aterwards CSs = movingSection[:characteristicSections] - CSs[1][:v_entry]=0.0 # the entry velocity of the first characteristic section is 0.0 m/s - startingPoint=createDataPoint() - startingPoint[:i]=1 + CSs[1][:v_entry] = 0.0 # the entry velocity of the first characteristic section is 0.0 m/s + startingPoint = createDataPoint() + startingPoint[:i] = 1 - previousCSv_exit=CSs[1][:v_entry] + previousCSv_exit = CSs[1][:v_entry] for csId in 1:length(CSs) - CSs[csId][:v_entry]=min(CSs[csId][:v_entry], previousCSv_exit) + CSs[csId][:v_entry] = min(CSs[csId][:v_entry], previousCSv_exit) - startingPoint[:s]=CSs[csId][:s_entry] - startingPoint[:v]=CSs[csId][:v_entry] + startingPoint[:s] = CSs[csId][:s_entry] + startingPoint[:v] = CSs[csId][:v_entry] accelerationCourse::Vector{Dict} = [startingPoint] # List of data points if CSs[csId][:v_entry] < CSs[csId][:v_peak] - (CSs[csId], accelerationCourse) = addAccelerationPhase!(CSs[csId], accelerationCourse, settings, train, CSs) # this function changes the accelerationCourse + (CSs[csId], accelerationCourse) = addAccelerationSection!(CSs[csId], accelerationCourse, settings, train, CSs) # this function changes the accelerationCourse CSs[csId][:v_peak] = max(CSs[csId][:v_entry], accelerationCourse[end][:v]) CSs[csId][:v_exit] = min(CSs[csId][:v_exit], CSs[csId][:v_peak], accelerationCourse[end][:v]) else #CSs[csId][:v_entry]==CSs[csId][:v_peak] @@ -124,22 +126,22 @@ function secureCruisingBehavior!(movingSection::Dict, settings::Dict, train::Dic # limit the exit velocity of the characteristic sections in case that the train cruises in every section at v_peak CSs = movingSection[:characteristicSections] - startingPoint=createDataPoint() - startingPoint[:i]=1 + startingPoint = createDataPoint() + startingPoint[:i] = 1 - previousCSv_exit=CSs[1][:v_entry] + previousCSv_exit = CSs[1][:v_entry] for csId in 1:length(CSs) - CSs[csId][:v_entry]=min(CSs[csId][:v_entry], previousCSv_exit) + CSs[csId][:v_entry] = min(CSs[csId][:v_entry], previousCSv_exit) - startingPoint[:s]=CSs[csId][:s_entry] - startingPoint[:v]=CSs[csId][:v_peak] + startingPoint[:s] = CSs[csId][:s_entry] + startingPoint[:v] = CSs[csId][:v_peak] cruisingCourse::Vector{Dict} = [startingPoint] # List of data points - (CSs[csId], cruisingCourse)=addCruisingPhase!(CSs[csId], cruisingCourse, CSs[csId][:length], settings, train, CSs, "cruising") # this function changes the cruisingCourse - CSs[csId][:v_exit]=min(CSs[csId][:v_exit], cruisingCourse[end][:v]) + (CSs[csId], cruisingCourse) = addCruisingSection!(CSs[csId], cruisingCourse, CSs[csId][:length], settings, train, CSs, "cruising") # this function changes the cruisingCourse + CSs[csId][:v_exit] = min(CSs[csId][:v_exit], cruisingCourse[end][:v]) - previousCSv_exit=CSs[csId][:v_exit] + previousCSv_exit = CSs[csId][:v_exit] end #for return movingSection diff --git a/src/TrainRun.jl b/src/TrainRun.jl index b95214d..b49f885 100644 --- a/src/TrainRun.jl +++ b/src/TrainRun.jl @@ -5,22 +5,22 @@ include("./TrainRunCalc.jl") # include additional modules include("./Import.jl") -include("./EnergySaving.jl") include("./Export.jl") # include additional modules that are not recommended to use in this state include("./AdditionalOutput.jl") +include("./EnergySaving.jl") # use main module TrainRunCalc using .TrainRunCalc # use additional modules using .Import -using .EnergySaving using .Export # use additional modules that are not recommended to use in this state using .AdditionalOutput +using .EnergySaving # main function export calculateDrivingDynamics, @@ -28,7 +28,7 @@ export calculateDrivingDynamics, # import functions importYamlFiles, importYamlFile, -# functions for saving energy +# functions for saving energy that are not recommended to use in this state addOperationModeEnergySaving!, # export functions @@ -38,6 +38,11 @@ exportToCsv, plotResults, plotDrivingCourse, printImportantValues, printSectionInformation # approximationLevel = 6 # value for approximation to intersections - # TODO: define it here and give it to each function? (MovingPhases, EnergySaving, ..) + # TODO: define it here and give it to each function? (Behavior, EnergySaving, ..) + +""" + TODO: Package description +""" + end # module TrainRun diff --git a/src/TrainRunCalc.jl b/src/TrainRunCalc.jl index 3d46d9b..3dc1a58 100644 --- a/src/TrainRunCalc.jl +++ b/src/TrainRunCalc.jl @@ -3,21 +3,21 @@ module TrainRunCalc # include modules of TrainRunCalc include("./Input.jl") include("./Preparation.jl") -include("./MovingPhases.jl") +include("./Behavior.jl") include("./Output.jl") # use modules of TrainRunCalc using .Input using .Preparation -using .MovingPhases +using .Behavior using .Output # export main function export calculateDrivingDynamics approximationLevel = 6 # value for approximation to intersections and precisely calculated digits - # TODO: define it here and give it to each function? (MovingPhases, ...) + # TODO: define it here and give it to each function? (Behavior, ...) # Calculate the driving dynamics of a train run on a path with special settings with information from the corresponding YAML files with the file paths `trainDirectory`, `pathDirectory`, `settingsDirectory`. @@ -90,15 +90,15 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train if s_clearing == CS[:length] - # 09/06 TODO: thought about using "cruising" because it is used in EnergySaving and not clearing (CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_clearing, settings, train, CSs, "cruising") - (CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_clearing, settings, train, CSs, "clearing") + # 09/06 TODO: thought about using "cruising" because it is used in EnergySaving and not clearing (CS, drivingCourse)=addCruisingSection!(CS, drivingCourse, s_clearing, settings, train, CSs, "cruising") + (CS, drivingCourse)=addCruisingSection!(CS, drivingCourse, s_clearing, settings, train, CSs, "clearing") elseif s_cruising == CS[:length] - (CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_cruising, settings, train, CSs, "cruising") + (CS, drivingCourse)=addCruisingSection!(CS, drivingCourse, s_cruising, settings, train, CSs, "cruising") elseif s_cruising > 0.0 || s_braking == 0.0 # 09/21 elseif s_cruising > 0.0 # 09/21 elseif s_cruising > 0.01 # if the cruising section is longer than 1 cm (because of rounding issues not >0.0) if drivingCourse[end][:v] < CS[:v_peak] - (CS, drivingCourse)=addAccelerationPhase!(CS, drivingCourse, settings, train, CSs) + (CS, drivingCourse)=addAccelerationSection!(CS, drivingCourse, settings, train, CSs) end #if if CS[:s_exit]-drivingCourse[end][:s]-max(0.0, (CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking]) < -0.001 # ceil is used to be sure that the train reaches v_exit at s_exit in spite of rounding errors @@ -111,13 +111,13 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train s_cruising=CS[:s_exit]-drivingCourse[end][:s]-s_braking if s_cruising > 0.0 - (CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_cruising, settings, train, CSs, "cruising") + (CS, drivingCourse)=addCruisingSection!(CS, drivingCourse, s_cruising, settings, train, CSs, "cruising") end else if CS[:v_entry] < CS[:v_peak] || s_acceleration > 0.0 # or instead of " || s_acceleration > 0.0" use "v_entry <= v_peak" or "v_i <= v_peak" # 09/09 old (not sufficient for steep gradients): if CS[:v_entry] < CS[:v_peak] - (CS, drivingCourse)=addAccelerationPhaseUntilBraking!(CS, drivingCourse, settings, train, CSs) + (CS, drivingCourse)=addAccelerationSectionUntilBraking!(CS, drivingCourse, settings, train, CSs) end #if end #if @@ -125,8 +125,8 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train s_braking=max(0.0, ceil((CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking], digits=approximationLevel)) # ceil is used to be sure that the train reaches v_exit at s_exit in spite of rounding errors if drivingCourse[end][:v] > CS[:v_exit] - #(CS, drivingCourse)=addBrakingPhase!(CS, drivingCourse, settings[:massModel], train, CSs) - (CS, drivingCourse)=addBrakingPhase!(CS, drivingCourse, settings, train, CSs) + #(CS, drivingCourse)=addBrakingSection!(CS, drivingCourse, settings[:massModel], train, CSs) + (CS, drivingCourse)=addBrakingSection!(CS, drivingCourse, settings, train, CSs) end #if #= 09/20 old and should never be used: @@ -134,7 +134,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train if haskey(BSs, :cruising) println("INFO: A second cruising section has been added to CS ", csId," from s=",drivingCourse[end][:s]," to s_exit=",CS[:s_exit]) end - (CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_cruising, settings, train, CSs, "cruising") + (CS, drivingCourse)=addCruisingSection!(CS, drivingCourse, s_cruising, settings, train, CSs, "cruising") end =# end #for