Merge branch 'development_max' into development

# Conflicts:
#	src/behavior.jl
#	src/characteristics.jl
#	src/constructors.jl
development
Martin Scheidt 2022-06-05 15:25:12 +02:00
commit e0790fc4f6
16 changed files with 272 additions and 366 deletions

View File

@ -1,32 +1,24 @@
#!/usr/bin/env julia #!/usr/bin/env julia
import TrainRuns using TrainRuns
using CSV
paths=[] paths=[]
push!(paths, importFromYaml(:path, "data/paths/path_1_10km_nConst_vConst.yaml")) push!(paths, Path("test/data/paths/const.yaml"))
push!(paths, importFromYaml(:path, "data/paths/path_2_10km_nVar_vConst.yaml")) push!(paths, Path("test/data/paths/slope.yaml"))
push!(paths, importFromYaml(:path, "data/paths/path_3_10km_nConst_vVar.yaml")) push!(paths, Path("test/data/paths/speed.yaml"))
push!(paths, importFromYaml(:path, "data/paths/path_4_real_Germany_EastSaxony_DG-DN.yaml")) push!(paths, Path("test/data/paths/realworld.yaml"))
settings=[]
push!(settings, importFromYaml(:settings, "data/settings/settings_distanceStep_massPoint.yaml"))
trains=[] trains=[]
push!(trains, importFromYaml(:train, "data/trains/train_freight_V90withOreConsist.yaml")) push!(trains, Train("test/data/trains/freight.yaml"))
push!(trains, importFromYaml(:train, "data/trains/train_passenger_SiemensDesiroClassic.yaml")) push!(trains, Train("test/data/trains/local.yaml"))
push!(trains, importFromYaml(:train, "data/trains/train_passenger_IC2.yaml")) push!(trains, Train("test/data/trains/longdistance.yaml"))
for path in paths settings = Settings("test/data/settings/driving_course.yaml")
# println(" - - - - - - - - -")
# println("path: ", path[:name]) for p in 1:length(paths)
for train in trains for t in 1:length(trains)
# println("train: ", train[:name]) driving_course = trainrun(trains[t], paths[p], settings)
for settings in settings CSV.write("docs/examples/drivingCourse_path"*string(p)*"_train"*string(t)*".csv", driving_course)
resultsDict = trainrun(train, path, settings)
if haskey(settings, :outputFormat) && settings[:outputFormat] == "CSV"
exportToCsv(resultsDict, settings)
sleep(2)
end
end
end end
end end

View File

@ -5,6 +5,6 @@ using TrainRuns
train = Train("test/data/trains/freight.yaml") train = Train("test/data/trains/freight.yaml")
path = Path("test/data/paths/const.yaml") path = Path("test/data/paths/const.yaml")
runtime = trainrun(train, path) runtime = trainrun(train, path)[end, :t]
println("The train needs $runtime seconds for the running path.") println("The train needs $runtime seconds for the running path.")

View File

@ -13,13 +13,13 @@ using UUIDs, Dates, Statistics
## loading external packages ## loading external packages
using YAML, JSONSchema, DataFrames using YAML, JSONSchema, DataFrames
export export
## Interface ## Interface
trainrun, Train, Path, Settings trainrun, Train, Path, Settings
## global variables ## global variables
global g = 9.80665 # acceleration due to gravity (in m/s^2) global g = 9.80665 # acceleration due to gravity (in m/s^2)
global μ = 0.2 # friction as constant, todo: implement as function global μ = 0.2 # friction as constant, TODO: implement as function
global Δv_air = 15.0/3.6 # coefficient for velocitiy difference between train and outdoor air (in m/s) global Δv_air = 15.0/3.6 # coefficient for velocitiy difference between train and outdoor air (in m/s)
## include package files ## include package files
@ -48,14 +48,14 @@ xxx.xx # in seconds
function trainrun(train::Train, path::Path, settings=Settings()::Settings) function trainrun(train::Train, path::Path, settings=Settings()::Settings)
# prepare the input data # prepare the input data
movingSection = determineCharacteristics(path, train, settings) movingSection = determineCharacteristics(path, train, settings)
settings.outputDetail == :everything && println("The moving section has been prepared.") # settings.outputDetail == :verbose && println("The moving section has been prepared.")
# calculate the train run for oparation mode "minimum running time" # calculate the train run for oparation mode "minimum running time"
(movingSection, drivingCourse) = calculateMinimumRunningTime!(movingSection, settings, train) (movingSection, drivingCourse) = calculateMinimumRunningTime!(movingSection, settings, train)
settings.outputDetail == :everything && println("The driving course for the shortest running time has been calculated.") # settings.outputDetail == :verbose && println("The driving course for the shortest running time has been calculated.")
# accumulate data and create an output dictionary # accumulate data and create an output dictionary
output = createOutput(train, settings, path, movingSection, drivingCourse) output = createOutput(settings, drivingCourse, movingSection[:pointsOfInterest])
return output return output
end # function trainrun end # function trainrun

View File

@ -39,18 +39,15 @@ function addBreakFreeSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:
# remove the accelerating section from the CS # remove the accelerating section from the CS
CS[:t] = CS[:t] - get(CS[:behaviorSections], :accelerating, Dict(:t=>0.0))[:t] # total running time (in s) CS[:t] = CS[:t] - get(CS[:behaviorSections], :accelerating, Dict(:t=>0.0))[:t] # total running time (in s)
CS[:E] = CS[:E] - get(CS[:behaviorSections], :accelerating, Dict(:E=>0.0))[:E] # total energy consumption (in Ws)
delete!(CS[:behaviorSections], :accelerating) delete!(CS[:behaviorSections], :accelerating)
# calculate the accumulated breakFree section information # 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) :s_exit => drivingCourse[end][:s], # last position (in m)
:t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) :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))) :v_exit => drivingCourse[end][:v])) # exit speed (in m/s)))
CS[:t] = CS[:t] + BS[:t] # total running time (in s) 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)) merge!(CS[:behaviorSections], Dict(:breakFree => BS))
end # else: return the characteristic section without a breakFree section end # else: return the characteristic section without a breakFree section
@ -60,7 +57,7 @@ function addBreakFreeSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:
if haskey(stateFlags, :usedForDefiningCharacteristics) && stateFlags[:usedForDefiningCharacteristics] if haskey(stateFlags, :usedForDefiningCharacteristics) && stateFlags[:usedForDefiningCharacteristics]
s_braking = 0.0 s_braking = 0.0
else else
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
end end
# reset state flags # reset state flags
@ -86,7 +83,7 @@ function addClearingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
s_braking = 0.0 s_braking = 0.0
else else
ignoreBraking = false ignoreBraking = false
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
end end
s_clearing = min(CS[:s_exit]-drivingCourse[end][:s]-s_braking, currentSpeedLimit[:s_end] - drivingCourse[end][:s]) s_clearing = min(CS[:s_exit]-drivingCourse[end][:s]-s_braking, currentSpeedLimit[:s_end] - drivingCourse[end][:s])
@ -124,7 +121,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla
s_braking = 0.0 s_braking = 0.0
else else
ignoreBraking = false ignoreBraking = false
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
end end
# conditions for the accelerating section # conditions for the accelerating section
@ -151,7 +148,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla
for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation
if !ignoreBraking if !ignoreBraking
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
end end
while !targetSpeedReached && !speedLimitReached && !brakingStartReached && !pointOfInterestReached && tractionSurplus && !previousSpeedLimitReached while !targetSpeedReached && !speedLimitReached && !brakingStartReached && !pointOfInterestReached && tractionSurplus && !previousSpeedLimitReached
@ -173,7 +170,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla
# conditions for the next while cycle # conditions for the next while cycle
if !ignoreBraking if !ignoreBraking
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
end end
brakingStartReached = drivingCourse[end][:s] +s_braking >= CS[:s_exit] brakingStartReached = drivingCourse[end][:s] +s_braking >= CS[:s_exit]
speedLimitReached = drivingCourse[end][:v] > CS[:v_limit] speedLimitReached = drivingCourse[end][:v] > CS[:v_limit]
@ -322,6 +319,9 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla
if drivingCourse[end][:s] == CS[:s_exit] if drivingCourse[end][:s] == CS[:s_exit]
endOfCSReached = true endOfCSReached = true
end end
if drivingCourse[end][:s] == nextPointOfInterest[1]
drivingCourse[end][:label] = nextPointOfInterest[2]
end
end #while end #while
@ -330,12 +330,10 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla
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) :s_exit => drivingCourse[end][:s], # last position (in m)
:t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) :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))) :v_exit => drivingCourse[end][:v])) # exit speed (in m/s)))
# 03/10 old: 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 running on a path with high resistances # 03/10 old: 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 running on a path with high resistances
CS[:t] = CS[:t] + BS[:t] # total running time (in s) CS[:t] = CS[:t] + BS[:t] # total running time (in s)
CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws)
mergeBehaviorSection!(CS[:behaviorSections], BS) mergeBehaviorSection!(CS[:behaviorSections], BS)
end end
@ -372,11 +370,11 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
s_braking = 0.0 s_braking = 0.0
else else
ignoreBraking = false ignoreBraking = false
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
end end
# conditions for cruising section # conditions for cruising section
#s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) #s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached] brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached]
speedIsValid = drivingCourse[end][:v]>0.0 && drivingCourse[end][:v]<=CS[:v_peak] speedIsValid = drivingCourse[end][:v]>0.0 && drivingCourse[end][:v]<=CS[:v_peak]
tractionDeficit = drivingCourse[end][:F_T] < drivingCourse[end][:F_R] tractionDeficit = drivingCourse[end][:F_T] < drivingCourse[end][:F_R]
@ -410,7 +408,7 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
# use the conditions for the cruising section # use the conditions for the cruising section
while trainInPreviousCS && !targetPositionReached && !tractionDeficit && (trainIsClearing || (trainIsBrakingDownhill == resistingForceNegative)) # while clearing tractive or braking force can be used while trainInPreviousCS && !targetPositionReached && !tractionDeficit && (trainIsClearing || (trainIsBrakingDownhill == resistingForceNegative)) # while clearing tractive or braking force can be used
currentStepSize = settings.stepSize currentStepSize = settings.stepSize
nextPointOfInterest[1] = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])
pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1]
for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation
@ -533,6 +531,11 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
end end
end end
end #for end #for
if drivingCourse[end][:s] == nextPointOfInterest[1]
drivingCourse[end][:label] = nextPointOfInterest[2]
end
end #while end #while
end #if end #if
@ -543,7 +546,10 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
while !targetPositionReached && !tractionDeficit && (trainIsClearing || (trainIsBrakingDownhill == resistingForceNegative)) # while clearing tractive or braking force can be used while !targetPositionReached && !tractionDeficit && (trainIsClearing || (trainIsBrakingDownhill == resistingForceNegative)) # while clearing tractive or braking force can be used
# 03/09 old: while drivingCourse[end][:s] < BS[:s_entry]+s_cruising && drivingCourse[end][:F_T] >= drivingCourse[end][:F_R] # 03/09 old: while drivingCourse[end][:s] < BS[:s_entry]+s_cruising && drivingCourse[end][:F_T] >= drivingCourse[end][:F_R]
nextPointOfInterest = min(BS[:s_entry]+s_cruising, getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])[1]) nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])
if nextPointOfInterest[1] > BS[:s_entry]+s_cruising
nextPointOfInterest = [BS[:s_entry]+s_cruising, ""]
end
# tractive effort (in N): # tractive effort (in N):
#03/25 drivingCourse[end][:F_T] = min(drivingCourse[end][:F_T], max(0.0, drivingCourse[end][:F_R])) #03/25 drivingCourse[end][:F_T] = min(drivingCourse[end][:F_T], max(0.0, drivingCourse[end][:F_R]))
@ -564,6 +570,9 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
# create the next data point # create the next data point
push!(drivingCourse, moveAStep(drivingCourse[end], :distance, s_cruisingRemaining, CS[:id])) push!(drivingCourse, moveAStep(drivingCourse[end], :distance, s_cruisingRemaining, CS[:id]))
drivingCourse[end][:behavior] = BS[:type] drivingCourse[end][:behavior] = BS[:type]
if drivingCourse[end][:s] == nextPointOfInterest[1]
drivingCourse[end][:label] = nextPointOfInterest[2]
end
push!(BS[:dataPoints], drivingCourse[end][:i]) push!(BS[:dataPoints], drivingCourse[end][:i])
calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel) calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel)
@ -587,11 +596,9 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
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) :s_exit => drivingCourse[end][:s], # last position (in m)
:t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) :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))) :v_exit => drivingCourse[end][:v])) # exit speed (in m/s)))
CS[:t] = CS[:t] + BS[:t] # total running time (in s) CS[:t] = CS[:t] + BS[:t] # total running time (in s)
CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws)
mergeBehaviorSection!(CS[:behaviorSections], BS) mergeBehaviorSection!(CS[:behaviorSections], BS)
end # else: return the characteristic section without a cruising section end # else: return the characteristic section without a cruising section
@ -599,7 +606,7 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
# set state flags # set state flags
stateFlags[:endOfCSReached] = drivingCourse[end][:s] == CS[:s_exit] stateFlags[:endOfCSReached] = drivingCourse[end][:s] == CS[:s_exit]
if !ignoreBraking if !ignoreBraking
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
end end
stateFlags[:brakingStartReached] = brakingStartReached || drivingCourse[end][:s] + s_braking >= CS[:s_exit] stateFlags[:brakingStartReached] = brakingStartReached || drivingCourse[end][:s] + s_braking >= CS[:s_exit]
stateFlags[:tractionDeficit] = tractionDeficit stateFlags[:tractionDeficit] = tractionDeficit
@ -621,14 +628,14 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag
s_braking = 0.0 s_braking = 0.0
else else
ignoreBraking = false ignoreBraking = false
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
end end
# conditions for diminishing section # conditions for diminishing section
targetSpeedReached = drivingCourse[end][:v] <= 0.0 targetSpeedReached = drivingCourse[end][:v] <= 0.0
endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached] endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached]
tractionDeficit = drivingCourse[end][:F_T] < drivingCourse[end][:F_R] #|| stateFlags[:tractionDeficit] tractionDeficit = drivingCourse[end][:F_T] < drivingCourse[end][:F_R] #|| stateFlags[:tractionDeficit]
#s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) #s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached] brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached]
# use the conditions for the diminishing section # use the conditions for the diminishing section
@ -638,7 +645,7 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag
while tractionDeficit && !targetSpeedReached && !endOfCSReached && !brakingStartReached while tractionDeficit && !targetSpeedReached && !endOfCSReached && !brakingStartReached
currentStepSize=settings.stepSize # initialize the step size that can be reduced near intersections currentStepSize=settings.stepSize # initialize the step size that can be reduced near intersections
nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])[1] nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])
pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1]
for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation
@ -656,7 +663,7 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag
# conditions for the next while cycle # conditions for the next while cycle
if !ignoreBraking if !ignoreBraking
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
end end
brakingStartReached = drivingCourse[end][:s] +s_braking >= CS[:s_exit] brakingStartReached = drivingCourse[end][:s] +s_braking >= CS[:s_exit]
pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1]
@ -674,11 +681,11 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag
# check which limit was reached and adjust the currentStepSize for the next cycle # check which limit was reached and adjust the currentStepSize for the next cycle
if cycle < settings.approxLevel+1 if cycle < settings.approxLevel+1
if drivingCourse[end][:v] < 0.0 if drivingCourse[end][:v] < 0.0
if settings.stepVariable == velocity # if settings.stepVariable == :velocity
currentStepSize = drivingCourse[end-1][:v] # currentStepSize = drivingCourse[end-1][:v]
else # else
currentStepSize = settings.stepSize / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
end # end
elseif drivingCourse[end][:F_T] > drivingCourse[end][:F_R] elseif drivingCourse[end][:F_T] > drivingCourse[end][:F_R]
testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: F_T=", drivingCourse[end][:F_T]," > F_R=",drivingCourse[end][:F_R]) # for testing testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: F_T=", drivingCourse[end][:F_T]," > F_R=",drivingCourse[end][:F_R]) # for testing
currentStepSize = settings.stepSize / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
@ -769,6 +776,10 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag
# end # end
end #if end #if
end #for end #for
if drivingCourse[end][:s] == nextPointOfInterest[1]
drivingCourse[end][:label] = nextPointOfInterest[2]
end
end #while end #while
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?
@ -776,11 +787,9 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag
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) :s_exit => drivingCourse[end][:s], # last position (in m)
:t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) :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))) :v_exit => drivingCourse[end][:v])) # exit speed (in m/s)))
CS[:t] = CS[:t] + BS[:t] # total running time (in s) CS[:t] = CS[:t] + BS[:t] # total running time (in s)
CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws)
mergeBehaviorSection!(CS[:behaviorSections], BS) mergeBehaviorSection!(CS[:behaviorSections], BS)
end end
@ -808,7 +817,7 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
targetSpeedReached = drivingCourse[end][:v] <= CS[:v_exit] targetSpeedReached = drivingCourse[end][:v] <= CS[:v_exit]
endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached] endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached]
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached] brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached]
# use the conditions for the coasting section # use the conditions for the coasting section
@ -836,7 +845,7 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
push!(BS[:dataPoints], drivingCourse[end][:i]) push!(BS[:dataPoints], drivingCourse[end][:i])
# conditions for the next while cycle # conditions for the next while cycle
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit]
pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1]
targetSpeedReached = drivingCourse[end][:v] <= CS[:v_exit] || drivingCourse[end][:v] > CS[:v_peak] targetSpeedReached = drivingCourse[end][:v] <= CS[:v_exit] || drivingCourse[end][:v] > CS[:v_peak]
@ -861,14 +870,14 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
elseif drivingCourse[end][:v] < CS[:v_exit] # TODO: if accelereation and coasting functions will be combined this case is only for coasting elseif drivingCourse[end][:v] < CS[:v_exit] # TODO: if accelereation and coasting functions will be combined this case is only for coasting
testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: v=", drivingCourse[end][:v]," < v_exit=", CS[:v_exit]) # for testing testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: v=", drivingCourse[end][:v]," < v_exit=", CS[:v_exit]) # for testing
if settings.stepVariable == velocity if settings.stepVariable == :velocity
currentStepSize = drivingCourse[end-1][:v] - CS[:v_exit] currentStepSize = drivingCourse[end-1][:v] - CS[:v_exit]
else else
currentStepSize = settings.stepSize / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
end end
elseif drivingCourse[end][:v] > CS[:v_peak] elseif drivingCourse[end][:v] > CS[:v_peak]
testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: v=", drivingCourse[end][:v]," > v_peak=", CS[:v_peak]) # for testing testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: v=", drivingCourse[end][:v]," > v_peak=", CS[:v_peak]) # for testing
if settings.stepVariable == velocity if settings.stepVariable == :velocity
currentStepSize = CS[:v_peak] - drivingCourse[end-1][:v] currentStepSize = CS[:v_peak] - drivingCourse[end-1][:v]
else else
currentStepSize = settings.stepSize / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
@ -933,6 +942,11 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
end end
end end
end #for end #for
if drivingCourse[end][:s] == nextPointOfInterest[1]
drivingCourse[end][:label] = nextPointOfInterest[2]
end
end #while end #while
stateFlags[:speedLimitReached] = false stateFlags[:speedLimitReached] = false
@ -941,11 +955,9 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
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) :s_exit => drivingCourse[end][:s], # last position (in m)
:t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) :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))) :v_exit => drivingCourse[end][:v])) # exit speed (in m/s)))
CS[:t] = CS[:t] + BS[:t] # total running time (in s) 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)) merge!(CS[:behaviorSections], Dict(:coasting=>BS))
end end
@ -1090,17 +1102,20 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D
end end
end end
end #for end #for
if drivingCourse[end][:s] == nextPointOfInterest[1]
drivingCourse[end][:label] = nextPointOfInterest[2]
end
end #while end #while
# calculate the accumulated coasting section information # 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) :s_exit => drivingCourse[end][:s], # last position (in m)
:t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s) :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))) :v_exit => drivingCourse[end][:v])) # exit speed (in m/s)))
CS[:t] = CS[:t] + BS[:t] # total running time (in s) 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)) merge!(CS[:behaviorSections], Dict(:braking=>BS))
end # else: return the characteristic section without a braking section end # else: return the characteristic section without a braking section
@ -1118,14 +1133,13 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D
end #function addBrakingSection! end #function addBrakingSection!
## This function calculates the data point of the standstill. ## This function calculates the data point of the halt.
# Therefore it gets its first data point and the characteristic section and returns the characteristic section including the standstill if needed. # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the halt if needed.
function addStandstill!(CS::Dict, drivingCourse::Vector{Dict}, settings::Settings, train::Train, CSs::Vector{Dict}) function addHalt!(CS::Dict, drivingCourse::Vector{Dict}, settings::Settings, train::Train, CSs::Vector{Dict})
if drivingCourse[end][:v] == 0.0 if drivingCourse[end][:v] == 0.0
BS = BehaviorSection("standstill", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) BS = BehaviorSection("standstill", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i])
merge!(BS, Dict(:length => 0.0, # total length (in m) merge!(BS, Dict(:length => 0.0, # total length (in m)
:t => 0.0, # total running time (in s) :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) :s_exit => drivingCourse[end][:s], # last position (in m)
:v_exit => drivingCourse[end][:v])) # exit speed (in m/s))) :v_exit => drivingCourse[end][:v])) # exit speed (in m/s)))
drivingCourse[end][:behavior] = BS[:type] drivingCourse[end][:behavior] = BS[:type]
@ -1133,10 +1147,10 @@ function addStandstill!(CS::Dict, drivingCourse::Vector{Dict}, settings::Setting
# traction effort and resisting forces (in N) # traction effort and resisting forces (in N)
calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings.massModel) calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings.massModel)
merge!(CS[:behaviorSections], Dict(:standstill => BS)) merge!(CS[:behaviorSections], Dict(:halt => BS))
end # else: return the characteristic section without a standstillSection section end # else: return the characteristic section without a halt section section
return (CS, drivingCourse) return (CS, drivingCourse)
end #function addStandstill! end #function addHalt!
function mergeBehaviorSection!(BSs::Dict, BS::Dict) function mergeBehaviorSection!(BSs::Dict, BS::Dict)
if !haskey(BSs, Symbol(BS[:type])) if !haskey(BSs, Symbol(BS[:type]))
@ -1169,15 +1183,10 @@ function recalculateLastBrakingPoint!(drivingCourse, s_target, v_target)
# end # end
currentPoint[:Δt] = calc_Δt_with_Δv(currentPoint[:Δv], previousPoint[:a]) # step size (in s) currentPoint[:Δt] = calc_Δt_with_Δv(currentPoint[:Δv], previousPoint[:a]) # step size (in s)
currentPoint[:t] = previousPoint[:t] + currentPoint[:Δt] # point in time (in s) currentPoint[:t] = previousPoint[:t] + currentPoint[:Δt] # point in time (in s)
currentPoint[:ΔW] = 0.0 # mechanical work in this step (in Ws)
currentPoint[:W] = previousPoint[:W] + currentPoint[:ΔW] # mechanical work (in Ws)
currentPoint[:ΔE] = currentPoint[:ΔW] # energy consumption in this step (in Ws)
currentPoint[:E] = previousPoint[:E] + currentPoint[:ΔE] # energy consumption (in Ws)
end #function recalculateLastBrakingPoint end #function recalculateLastBrakingPoint
## define the intersection velocities between the characterisitc sections to secure braking behavior ## define the intersection velocities between the characterisitc sections to secure braking behavior
function secureBrakingBehavior!(movingSection::Dict, a_braking::Real) function secureBrakingBehavior!(movingSection::Dict, a_braking::Real, approxLevel::Integer)
# this function limits the entry and exit velocity of the characteristic sections to secure that the train stops at the moving sections end # 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] CSs = movingSection[:characteristicSections]
@ -1188,7 +1197,7 @@ function secureBrakingBehavior!(movingSection::Dict, a_braking::Real)
CS[:v_exit] = min(CS[:v_limit], followingCSv_entry) CS[:v_exit] = min(CS[:v_limit], followingCSv_entry)
v_entryMax = calcBrakingStartVelocity(CS[:v_exit], a_braking, CS[:length]) v_entryMax = calcBrakingStartVelocity(CS[:v_exit], a_braking, CS[:length], approxLevel)
CS[:v_entry] = min(CS[:v_limit], v_entryMax) CS[:v_entry] = min(CS[:v_limit], v_entryMax)
CS[:v_peak] = CS[:v_entry] CS[:v_peak] = CS[:v_entry]
@ -1196,7 +1205,6 @@ function secureBrakingBehavior!(movingSection::Dict, a_braking::Real)
# reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit # reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit
CS[:behaviorSections] = Dict() CS[:behaviorSections] = Dict()
CS[:E] = 0.0
CS[:t] = 0.0 CS[:t] = 0.0
followingCSv_entry = CS[:v_entry] followingCSv_entry = CS[:v_entry]
@ -1252,7 +1260,7 @@ function secureAcceleratingBehavior!(movingSection::Dict, settings::Settings, tr
v_peak = max(v_peak, acceleratingCourse[end][:v]) v_peak = max(v_peak, acceleratingCourse[end][:v])
end end
# CS[:v_peak] = max(CS[:v_entry], acceleratingCourse[end][:v]) # CS[:v_peak] = max(CS[:v_entry], acceleratingCourse[end][:v])
CS[:v_peak] = v_peak CS[:v_peak] = v_peak
CS[:v_exit] = min(CS[:v_exit], CS[:v_peak], acceleratingCourse[end][:v]) CS[:v_exit] = min(CS[:v_exit], CS[:v_peak], acceleratingCourse[end][:v])
else #CS[:v_entry] == CS[:v_peak] else #CS[:v_entry] == CS[:v_peak]
@ -1263,69 +1271,8 @@ function secureAcceleratingBehavior!(movingSection::Dict, settings::Settings, tr
# reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit # reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit
CS[:behaviorSections] = Dict() CS[:behaviorSections] = Dict()
CS[:E] = 0.0
CS[:t] = 0.0 CS[:t] = 0.0
end #for end #for
return movingSection return movingSection
end #function secureAcceleratingBehavior! end #function secureAcceleratingBehavior!
#=
## define the intersection velocities between the characterisitc sections to secure cruising behavior
function secureCruisingBehavior!(movingSection::Dict, settings::Settings, train::Train)
# limit the exit velocity of the characteristic sections in case that the train cruises in every section at v_peak
CSs = movingSection[:characteristicSections]
startingPoint = DataPoint()
startingPoint[:i] = 1
previousCSv_exit = CSs[1][:v_entry]
for CS in CSs
# conditions for entering the cruising phase
stateFlags = Dict(:endOfCSReached => false,
:brakingStartReached => false,
:tractionDeficit => false,
:resistingForceNegative => false,
:previousSpeedLimitReached => false,
:speedLimitReached => false,
:error => false,
:usedForDefiningCharacteristics => true)
CS[:v_entry] = min(CS[:v_entry], previousCSv_exit)
startingPoint[:s] = CS[:s_entry]
startingPoint[:v] = CS[:v_peak]
cruisingCourse::Vector{Dict} = [startingPoint] # List of data points
while !stateFlags[:endOfCSReached] #&& s_cruising > 0.0
if !stateFlags[:tractionDeficit]
s_cruising = CS[:s_exit] - cruisingCourse[end][:s]
if !stateFlags[:resistingForceNegative]# cruisingCourse[end][:F_R] >= 0
(CS, cruisingCourse, stateFlags) = addCruisingSection!(CS, cruisingCourse, stateFlags, s_cruising, settings, train, CSs, "cruising") # this function changes the cruisingCourse
else
(CS, cruisingCourse, stateFlags) = addCruisingSection!(CS, cruisingCourse, stateFlags, s_cruising, settings, train, CSs, "downhillBraking")
end
else
if settings.massModel == :mass_point || cruisingCourse[end][:s] > CS[:s_entry] + train.length
break
else
(CS, cruisingCourse, stateFlags) = addDiminishingSection!(CS, cruisingCourse, stateFlags, settings, train, CSs) # this function is needed in case the resisitng forces are higher than the maximum possible tractive effort
end
end
end
CS[:v_exit] = min(CS[:v_exit], cruisingCourse[end][:v])
previousCSv_exit = CS[:v_exit]
# reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit
CS[:behaviorSections] = Dict()
CS[:E] = 0.0
CS[:t] = 0.0
end #for
return movingSection
end #function secureCruisingBehavior!
=#

View File

@ -12,7 +12,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t
CSs::Vector{Dict} = movingSection[:characteristicSections] CSs::Vector{Dict} = movingSection[:characteristicSections]
if settings.massModel == :homogeneous_strip && settings.stepVariable == speed if settings.massModel == :homogeneous_strip && settings.stepVariable == speed
println("WARNING: ! ! ! TrainRun.jl doesn't work reliably for the mass model homogeneous strip with step size v in m/s. The calculation time can be extremely high when calcutlating paths with steep gradients ! ! !") println("WARNING: ! ! ! TrainRuns.jl doesn't work reliably for the mass model homogeneous strip with step size v in m/s. The calculation time can be extremely high when calcutlating paths with steep gradients ! ! !")
end end
startingPoint=DataPoint() startingPoint=DataPoint()
@ -32,7 +32,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t
end end
# determine the different flags for switching between the states for creatinge moving phases # determine the different flags for switching between the states for creatinge moving phases
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel) # tractive effort and resisting forces (in N) calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel) # tractive effort and resisting forces (in N)
previousSpeedLimitReached = false previousSpeedLimitReached = false
@ -44,7 +44,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t
:speedLimitReached => drivingCourse[end][:v] > CS[:v_limit], :speedLimitReached => drivingCourse[end][:v] > CS[:v_limit],
:error => false) :error => false)
# determine the behavior sections for this characteristic section. It has to be at least one of those BS: "breakFree", "clearing", "accelerating", "cruising", "diminishing", "coasting", "braking" or "standstill") # determine the behavior sections for this characteristic section. It has to be at least one of those BS: "breakFree", "clearing", "accelerating", "cruising", "diminishing", "coasting", "braking" or "halt")
while !stateFlags[:endOfCSReached] # s < s_exit while !stateFlags[:endOfCSReached] # s < s_exit
if !stateFlags[:brakingStartReached] # s+s_braking < s_exit if !stateFlags[:brakingStartReached] # s+s_braking < s_exit
if !stateFlags[:tractionDeficit] if !stateFlags[:tractionDeficit]
@ -69,7 +69,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t
(CS, drivingCourse, stateFlags) = addCruisingSection!(CS, drivingCourse, stateFlags, s_cruising, settings, train, CSs, "cruising") (CS, drivingCourse, stateFlags) = addCruisingSection!(CS, drivingCourse, stateFlags, s_cruising, settings, train, CSs, "cruising")
elseif drivingCourse[end][:F_R] < 0 && stateFlags[:speedLimitReached] elseif drivingCourse[end][:F_R] < 0 && stateFlags[:speedLimitReached]
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking
if s_cruising > 0.0 if s_cruising > 0.0
@ -79,7 +79,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t
end end
elseif drivingCourse[end][:F_T] == drivingCourse[end][:F_R] || stateFlags[:speedLimitReached] elseif drivingCourse[end][:F_T] == drivingCourse[end][:F_R] || stateFlags[:speedLimitReached]
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking
if s_cruising > 0.0 # TODO: define a minimum cruising length? if s_cruising > 0.0 # TODO: define a minimum cruising length?
@ -103,7 +103,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t
end end
end end
#if s == s_exit #if s == s_exit
# standstill # halt
#end #end
@ -116,14 +116,14 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t
end end
end #for end #for
(CSs[end], drivingCourse) = addStandstill!(CSs[end], drivingCourse, settings, train, CSs) (CSs[end], drivingCourse) = addHalt!(CSs[end], drivingCourse, settings, train, CSs)
movingSection[:t] = drivingCourse[end][:t] # total running time (in s) movingSection[:t] = drivingCourse[end][:t] # total running time (in s)
movingSection[:E] = drivingCourse[end][:E] # total energy consumption (in Ws)
return (movingSection, drivingCourse) return (movingSection, drivingCourse)
end #function calculateMinimumRunningTime end #function calculateMinimumRunningTime
""" """
calculateTractiveEffort(v, tractiveEffortVelocityPairs) calculateTractiveEffort(v, tractiveEffortVelocityPairs)
@ -145,6 +145,11 @@ julia> calculateTractiveEffort(30.0, [(0.0, 180000), (20.0, 100000), (40.0, 6000
``` ```
""" """
function calculateTractiveEffort(v::AbstractFloat, tractiveEffortVelocityPairs::Array{}) function calculateTractiveEffort(v::AbstractFloat, tractiveEffortVelocityPairs::Array{})
if v < 0.0
#println("v=",v)
return 0.0
end
for row in 1:length(tractiveEffortVelocityPairs) for row in 1:length(tractiveEffortVelocityPairs)
nextPair = tractiveEffortVelocityPairs[row] nextPair = tractiveEffortVelocityPairs[row]
if nextPair[1] == v if nextPair[1] == v
@ -161,6 +166,7 @@ function calculateTractiveEffort(v::AbstractFloat, tractiveEffortVelocityPairs::
return tractiveEffortVelocityPairs[end][2] return tractiveEffortVelocityPairs[end][2]
end #function calculateTractiveEffort end #function calculateTractiveEffort
""" """
calculate and return the path resistance dependend on the trains position and mass model calculate and return the path resistance dependend on the trains position and mass model
""" """
@ -184,19 +190,24 @@ function calculatePathResistance(CSs::Vector{Dict}, csId::Integer, s::Real, mass
return pathResistance return pathResistance
end #function calculatePathResistance end #function calculatePathResistance
""" """
calculate and return tractive and resisting forces for a data point calculate and return tractive and resisting forces for a data point
""" """
function calculateForces!(dataPoint::Dict, CSs::Vector{Dict}, csId::Integer, bsType::String, train::Train, massModel) function calculateForces!(dataPoint::Dict, CSs::Vector{Dict}, csId::Integer, bsType::String, train::Train, massModel)
# calculate resisting forces # calculate resisting forces
dataPoint[:R_traction] = calcTractionUnitResistance(dataPoint[:v], train) dataPoint[:R_traction] = calcTractionUnitResistance(dataPoint[:v], train)
dataPoint[:R_wagons] = calcWagonsResistance(dataPoint[:v], train) if train.transportType == :freight
dataPoint[:R_wagons] = calcFreightWagonsResistance(dataPoint[:v], train)
elseif train.transportType == :passenger
dataPoint[:R_wagons] = calcPassengerWagonsResistance(dataPoint[:v], train)
end
dataPoint[:R_train] = dataPoint[:R_traction] + dataPoint[:R_wagons] dataPoint[:R_train] = dataPoint[:R_traction] + dataPoint[:R_wagons]
dataPoint[:R_path] = calculatePathResistance(CSs, csId, dataPoint[:s], massModel, train) dataPoint[:R_path] = calculatePathResistance(CSs, csId, dataPoint[:s], massModel, train)
dataPoint[:F_R] = dataPoint[:R_train] + dataPoint[:R_path] dataPoint[:F_R] = dataPoint[:R_train] + dataPoint[:R_path]
# calculate tractive effort # calculate tractive effort
if bsType == "braking" || bsType == "coasting" if bsType == "braking" || bsType == "coasting" || bsType == "halt"
dataPoint[:F_T] = 0.0 dataPoint[:F_T] = 0.0
elseif bsType == "cruising" elseif bsType == "cruising"
dataPoint[:F_T] = min(max(0.0, dataPoint[:F_R]), calculateTractiveEffort(dataPoint[:v], train.tractiveEffort)) dataPoint[:F_T] = min(max(0.0, dataPoint[:F_R]), calculateTractiveEffort(dataPoint[:v], train.tractiveEffort))
@ -265,15 +276,11 @@ function moveAStep(previousPoint::Dict, stepVariable::Symbol, stepSize::Real, cs
newPoint[:s] = previousPoint[:s] + newPoint[:Δs] # position (in m) newPoint[:s] = previousPoint[:s] + newPoint[:Δs] # position (in m)
newPoint[:t] = previousPoint[:t] + newPoint[:Δt] # point in time (in s) newPoint[:t] = previousPoint[:t] + newPoint[:Δt] # point in time (in s)
newPoint[:v] = previousPoint[:v] + newPoint[:Δv] # velocity (in m/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 return newPoint
end #function moveAStep end #function moveAStep
""" """
# if the rear of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept # if the rear of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept
""" """
@ -294,13 +301,14 @@ function getCurrentSpeedLimit(CSs::Vector{Dict}, csWithTrainHeadId::Integer, s::
return currentSpeedLimit return currentSpeedLimit
end #function getCurrentSpeedLimit end #function getCurrentSpeedLimit
""" """
? TODO
""" """
function getNextPointOfInterest(pointsOfInterest::Vector{Tuple}, s::Real) function getNextPointOfInterest(pointsOfInterest::Vector{Tuple}, s::Real)
for s_POI in pointsOfInterest for POI in pointsOfInterest
if s_POI[1] > s if POI[1] > s
return s_POI return POI
end end
end end
error("ERROR in getNextPointOfInterest: There is no POI higher than s=",s," m.") error("ERROR in getNextPointOfInterest: There is no POI higher than s=",s," m.")
@ -310,7 +318,7 @@ end #function getNextPointOfInterest
## create a moving section and its containing characteristic sections with secured braking, accelerating and cruising behavior ## create a moving section and its containing characteristic sections with secured braking, accelerating and cruising behavior
function determineCharacteristics(path::Path, train::Train, settings::Settings) function determineCharacteristics(path::Path, train::Train, settings::Settings)
movingSection = MovingSection(path, train.v_limit, train.length) movingSection = MovingSection(path, train.v_limit, train.length)
movingSection = secureBrakingBehavior!(movingSection, train.a_braking) movingSection = secureBrakingBehavior!(movingSection, train.a_braking, settings.approxLevel)
movingSection = secureAcceleratingBehavior!(movingSection, settings, train) movingSection = secureAcceleratingBehavior!(movingSection, settings, train)
#movingSection = secureCruisingBehavior!(movingSection, settings, train) #movingSection = secureCruisingBehavior!(movingSection, settings, train)

View File

@ -52,18 +52,18 @@ function Settings(file="DEFAULT")
"outputDetail": { "outputDetail": {
"description": "Selecting the detail of the result", "description": "Selecting the detail of the result",
"type": "string", "type": "string",
"enum": [ "running_time", "points_of_interest", "driving_course", "everything" ] "enum": [ "running_time", "points_of_interest", "driving_course" ]
}, },
"outputFormat": { "outputFormat": {
"description": "Output format", "description": "Output format",
"type": "string", "type": "string",
"enum": [ "dataframe", "dict" ] "enum": [ "dataframe", "vector" ]
} }
} }
}""") }""")
settings = YAML.load(open(file))["settings"] settings = YAML.load(open(file))["settings"]
## validate the loaded file ## validate the loaded file
try try
validate(schema, settings) validate(schema, settings)
@ -116,12 +116,12 @@ function Path(file, type = :YAML)
data = YAML.load(open(file)) data = YAML.load(open(file))
if data["schema"] != "https://railtoolkit.org/schema/running-path.json" if data["schema"] != "https://railtoolkit.org/schema/running-path.json"
error("Could not load path file '$file'.\n error("Could not load path file '$file'.\n
YAML format is not recognized. YAML format is not recognized.
Currently supported: railtoolkit/schema/running-path (2022.05)") Currently supported: railtoolkit/schema/running-path (2022.05)")
end end
if data["schema_version"] != "2022.05" if data["schema_version"] != "2022.05"
error("Could not load path file '$file'.\n error("Could not load path file '$file'.\n
YAML format is not recognized. YAML format is not recognized.
Currently supported: railtoolkit/schema/running-path (2022.05)") Currently supported: railtoolkit/schema/running-path (2022.05)")
end end
@ -212,7 +212,7 @@ function Path(file, type = :YAML)
validate(railtoolkit_schema, paths) validate(railtoolkit_schema, paths)
catch err catch err
error("Could not load path file '$file'.\n error("Could not load path file '$file'.\n
YAML format is not recognized. YAML format is not recognized.
Currently supported: railtoolkit/schema/running-path (2022.05)") Currently supported: railtoolkit/schema/running-path (2022.05)")
end end
if length(paths) > 1 if length(paths) > 1
@ -256,9 +256,9 @@ function Path(file, type = :YAML)
sort!(tmp_points, by = x -> x[1]) sort!(tmp_points, by = x -> x[1])
for elem in tmp_points for elem in tmp_points
station = elem[1] # first point of the section (in m) station = elem[1] # first point of the section (in m)
label = elem[2] # paths speed limt (in m/s) label = elem[2] # paths speed limt (in m/s)
measure = elem[3] # specific path resistance of the section (in ‰) measure = elem[3] # specific path resistance of the section (in ‰)
point = Dict(:station => station, point = Dict(:station => station,
:label => label, :label => label,
:measure => measure) :measure => measure)
@ -302,27 +302,27 @@ function Train(file, type = :YAML)
ξ_cars = 1.06 # rotation mass factor ξ_cars = 1.06 # rotation mass factor
transportType = :freight # "freight" or "passenger" for resistance calculation transportType = :freight # "freight" or "passenger" for resistance calculation
v_limit = 140 # in m/s (default 504 km/h) v_limit = 140 # in m/s (default 504 km/h)
a_braking = 0 # in m/s^2, todo: implement as function a_braking = 0 # in m/s^2, TODO: implement as function
f_Rtd0 = 0 # coefficient for basic resistance due to the traction units driving axles (in ‰) f_Rtd0 = 0 # coefficient for basic resistance due to the traction unit's driving axles (in ‰)
f_Rtc0 = 0 # coefficient for basic resistance due to the traction units carring axles (in ‰) f_Rtc0 = 0 # coefficient for basic resistance due to the traction unit's carring axles (in ‰)
F_Rt2 = 3000 # coefficient for air resistance of the traction units (in N) f_Rt2 = 0 # coefficient for air resistance of the traction unit (in ‰)
f_Rw0 = 0 # coefficient for the consists basic resistance (in ‰) f_Rw0 = 0 # coefficient for the consist's basic resistance (in ‰)
f_Rw1 = 0 # coefficient for the consists resistance to rolling (in ‰) f_Rw1 = 0 # coefficient for the consist's resistance to rolling (in ‰)
f_Rw2 = 0 # coefficient fo the consistsr air resistance (in ‰) f_Rw2 = 0 # coefficient for the consist's air resistance (in ‰)
F_v_pairs = [] # [v in m/s, F_T in N] F_v_pairs = [] # [v in m/s, F_T in N]
## load from file ## load from file
if type == :YAML if type == :YAML
data = YAML.load(open(file)) data = YAML.load(open(file))
if data["schema"] != "https://railtoolkit.org/schema/rolling-stock.json" if data["schema"] != "https://railtoolkit.org/schema/rolling-stock.json"
error("Could not load path file '$file'.\n error("Could not load path file '$file'.\n
YAML format is not recognized. YAML format is not recognized.
Currently supported: railtoolkit/schema/rolling-stock (2022.05)") Currently supported: railtoolkit/schema/rolling-stock (2022.05)")
end end
if data["schema_version"] != "2022.05" if data["schema_version"] != "2022.05"
error("Could not load path file '$file'.\n error("Could not load path file '$file'.\n
YAML format is not recognized. YAML format is not recognized.
Currently supported: railtoolkit/schema/rolling-stock (2022.05)") Currently supported: railtoolkit/schema/rolling-stock (2022.05)")
end end
@ -472,14 +472,14 @@ function Train(file, type = :YAML)
} }
} }
} }
} }
}""") }""")
try try
validate(railtoolkit_schema, data) validate(railtoolkit_schema, data)
catch err catch err
error("Could not load path file '$file'.\n error("Could not load path file '$file'.\n
YAML format is not recognized. YAML format is not recognized.
Currently supported: railtoolkit/schema/rolling-stock (2022.05)") Currently supported: railtoolkit/schema/rolling-stock (2022.05)")
end end
@ -514,12 +514,13 @@ function Train(file, type = :YAML)
push!(vehicles, (data=vehicle, n=n, propulsion=propulsion) ) push!(vehicles, (data=vehicle, n=n, propulsion=propulsion) )
end end
end end
## set the variables in "train" ## set the variables in "train"
name = train["name"] name = train["name"]
id = train["id"] id = train["id"]
haskey(train, "UUID") ? uuid = parse(UUID, train["UUID"] ) : nothing haskey(train, "UUID") ? uuid = parse(UUID, train["UUID"] ) : nothing
transportType == :freight ? a_braking = -0.225 : a_braking = -0.375 # set a default a_braking value depending on the train type transportType == :freight ? a_braking = -0.225 : a_braking = -0.375 # set a default a_braking value depending on the train type
#TODO: add source: Brünger, Dahlhaus, 2014 p. 74 (see formulary.jl)
## set the variables for all vehicles ## set the variables for all vehicles
for vehicle in vehicles for vehicle in vehicles
@ -529,8 +530,8 @@ function Train(file, type = :YAML)
haskey(vehicle.data, "load_limit") ? haskey(vehicle.data, "load_limit") ?
m_train_full += vehicle.data["load_limit"] * vehicle.n * 1000 : # in kg m_train_full += vehicle.data["load_limit"] * vehicle.n * 1000 : # in kg
nothing nothing
haskey(vehicle.data, "speed_limit") ? haskey(vehicle.data, "speed_limit") ?
v_limit > vehicle.data["speed_limit"]/3.6 ? v_limit = vehicle.data["speed_limit"]/3.6 : nothing : v_limit > vehicle.data["speed_limit"]/3.6 ? v_limit = vehicle.data["speed_limit"]/3.6 : nothing :
nothing nothing
end end
@ -553,7 +554,7 @@ function Train(file, type = :YAML)
haskey(loco, "a_braking") ? a_braking = loco["a_braking"] : nothing haskey(loco, "a_braking") ? a_braking = loco["a_braking"] : nothing
haskey(loco, "base_resistance") ? f_Rtd0 = loco["base_resistance"] : nothing haskey(loco, "base_resistance") ? f_Rtd0 = loco["base_resistance"] : nothing
haskey(loco, "rolling_resistance") ? f_Rtc0 = loco["rolling_resistance"] : nothing haskey(loco, "rolling_resistance") ? f_Rtc0 = loco["rolling_resistance"] : nothing
haskey(loco, "air_resistance") ? F_Rt2 = loco["air_resistance"] * g * m_loco : nothing haskey(loco, "air_resistance") ? f_Rt2 = loco["air_resistance"] : nothing
haskey(loco, "mass_traction") ? m_td = loco["mass_traction"] * 1000 : m_td = m_t haskey(loco, "mass_traction") ? m_td = loco["mass_traction"] * 1000 : m_td = m_t
haskey(loco, "rotation_mass") ? ξ_loco = loco["rotation_mass"] : nothing haskey(loco, "rotation_mass") ? ξ_loco = loco["rotation_mass"] : nothing
m_tc = m_loco- m_td m_tc = m_loco- m_td
@ -569,17 +570,17 @@ function Train(file, type = :YAML)
resis_air = [] resis_air = []
rotMassFac = [] rotMassFac = []
for car in cars for car in cars
haskey(car.data, "base_resistance") ? haskey(car.data, "base_resistance") ?
append!(resis_base,repeat([car.data["base_resistance"]],car.n)) : append!(resis_base,repeat([car.data["base_resistance"]],car.n)) :
append!(resis_base,repeat([f_Rw0],car.n)) append!(resis_base,repeat([f_Rw0],car.n))
haskey(car.data, "rolling_resistance") ? haskey(car.data, "rolling_resistance") ?
append!(resis_roll,repeat([car.data["rolling_resistance"]],car.n)) : append!(resis_roll,repeat([car.data["rolling_resistance"]],car.n)) :
append!(resis_roll,repeat([f_Rw1],car.n)) append!(resis_roll,repeat([f_Rw1],car.n))
haskey(car.data, "air_resistance") ? haskey(car.data, "air_resistance") ?
append!(resis_air,repeat([car.data["air_resistance"]],car.n)) : append!(resis_air,repeat([car.data["air_resistance"]],car.n)) :
append!(resis_air, repeat([f_Rw2],car.n)) append!(resis_air, repeat([f_Rw2],car.n))
haskey(car.data, "rotation_mass") ? haskey(car.data, "rotation_mass") ?
append!(rotMassFac,repeat([(car.data["rotation_mass"],car.data["mass"])],car.n)) : append!(rotMassFac,repeat([(car.data["rotation_mass"],car.data["mass"])],car.n)) :
append!(rotMassFac,repeat([(ξ_cars ,car.data["mass"])],car.n)) append!(rotMassFac,repeat([(ξ_cars ,car.data["mass"])],car.n))
m_car_empty += car.data["mass"] * car.n * 1000 # in kg m_car_empty += car.data["mass"] * car.n * 1000 # in kg
m_car_full += car.data["mass"] * car.n * 1000 # in kg m_car_full += car.data["mass"] * car.n * 1000 # in kg
@ -607,7 +608,7 @@ function Train(file, type = :YAML)
ξ_train, ξ_loco, ξ_cars, ξ_train, ξ_loco, ξ_cars,
transportType, v_limit, transportType, v_limit,
a_braking, a_braking,
f_Rtd0, f_Rtc0, F_Rt2, f_Rw0, f_Rw1, f_Rw2, f_Rtd0, f_Rtc0, f_Rt2, f_Rw0, f_Rw1, f_Rw2,
F_v_pairs F_v_pairs
) )
@ -621,6 +622,19 @@ function MovingSection(path::Path, v_trainLimit::Real, s_trainLength::Real)
s_exit = path.sections[end][:s_end] # last position (in m) s_exit = path.sections[end][:s_end] # last position (in m)
pathLength = s_exit - s_entry # total length (in m) pathLength = s_exit - s_entry # total length (in m)
##TODO: use a tuple with naming
pointsOfInterest = Tuple[]
if !isempty(path.poi)
for POI in path.poi
s_poi = POI[:station]
if POI[:measure] == "rear"
s_poi += s_trainLength
end
push!(pointsOfInterest, (s_poi, POI[:label]) )
end
sort!(pointsOfInterest, by = x -> x[1])
end
CSs=Vector{Dict}() CSs=Vector{Dict}()
s_csStart=s_entry s_csStart=s_entry
csId=1 csId=1
@ -630,27 +644,26 @@ function MovingSection(path::Path, v_trainLimit::Real, s_trainLength::Real)
speedLimitIsDifferent = min(previousSection[:v_limit], v_trainLimit) != min(currentSection[:v_limit], v_trainLimit) speedLimitIsDifferent = min(previousSection[:v_limit], v_trainLimit) != min(currentSection[:v_limit], v_trainLimit)
pathResistanceIsDifferent = previousSection[:f_Rp] != currentSection[:f_Rp] pathResistanceIsDifferent = previousSection[:f_Rp] != currentSection[:f_Rp]
if speedLimitIsDifferent || pathResistanceIsDifferent if speedLimitIsDifferent || pathResistanceIsDifferent
# 03/09 old: if min(previousSection[:v_limit], v_trainLimit) != min(currentSection[:v_limit], v_trainLimit) || previousSection[:f_Rp] != currentSection[:f_Rp] push!(CSs, CharacteristicSection(csId, s_csStart, previousSection, min(previousSection[:v_limit], v_trainLimit), s_trainLength, pointsOfInterest))
push!(CSs, CharacteristicSection(csId, s_csStart, previousSection, min(previousSection[:v_limit], v_trainLimit), s_trainLength, path))
s_csStart = currentSection[:s_start] s_csStart = currentSection[:s_start]
csId = csId+1 csId = csId+1
end #if end #if
end #for end #for
push!(CSs, CharacteristicSection(csId, s_csStart, path.sections[end], min(path.sections[end][:v_limit], v_trainLimit), s_trainLength, path)) push!(CSs, CharacteristicSection(csId, s_csStart, path.sections[end], min(path.sections[end][:v_limit], v_trainLimit), s_trainLength, pointsOfInterest))
movingSection= Dict(:id => 1, # identifier # if there is more than one moving section in a later version of this tool the id should not be constant anymore movingSection= Dict(:id => 1, # identifier # if there is more than one moving section in a later version of this tool the id should not be constant anymore
:length => pathLength, # total length (in m) :length => pathLength, # total length (in m)
:s_entry => s_entry, # first position (in m) :s_entry => s_entry, # first position (in m)
:s_exit => s_exit, # last position (in m) :s_exit => s_exit, # last position (in m)
:t => 0.0, # total running time (in s) :t => 0.0, # total running time (in s)
:E => 0.0, # total energy consumption (in Ws) :characteristicSections => CSs, # list of containing characteristic sections
:characteristicSections => CSs) # list of containing characteristic sections :pointsOfInterest => pointsOfInterest) # list of containing points of interest
return movingSection return movingSection
end #function MovingSection end #function MovingSection
## create a characteristic section for a path section. A characteristic section is a part of the moving section. It contains behavior sections. ## create a characteristic section for a path section. A characteristic section is a part of the moving section. It contains behavior sections.
function CharacteristicSection(id::Integer, s_entry::Real, section::Dict, v_limit::Real, s_trainLength::Real, path::Path) function CharacteristicSection(id::Integer, s_entry::Real, section::Dict, v_limit::Real, s_trainLength::Real, MS_poi::Vector{Tuple})
# Create and return a characteristic section dependent on the paths attributes # Create and return a characteristic section dependent on the paths attributes
characteristicSection= Dict(:id => id, # identifier characteristicSection= Dict(:id => id, # identifier
:s_entry => s_entry, # first position (in m) :s_entry => s_entry, # first position (in m)
@ -659,7 +672,6 @@ function CharacteristicSection(id::Integer, s_entry::Real, section::Dict, v_limi
:r_path => section[:f_Rp], # path resistance (in ‰) :r_path => section[:f_Rp], # path resistance (in ‰)
:behaviorSections => Dict(), # list of containing behavior sections :behaviorSections => Dict(), # list of containing behavior sections
:t => 0.0, # total running time (in s) :t => 0.0, # total running time (in s)
:E => 0.0, # total energy consumption (in Ws)
:v_limit => v_limit, # speed limit (in m/s) :v_limit => v_limit, # speed limit (in m/s)
# initializing :v_entry, :v_peak and :v_exit with :v_limit # initializing :v_entry, :v_peak and :v_exit with :v_limit
:v_peak => v_limit, # maximum reachable speed (in m/s) :v_peak => v_limit, # maximum reachable speed (in m/s)
@ -671,22 +683,17 @@ function CharacteristicSection(id::Integer, s_entry::Real, section::Dict, v_limi
##TODO: use a tuple with naming ##TODO: use a tuple with naming
pointsOfInterest = Tuple[] pointsOfInterest = Tuple[]
# pointsOfInterest = Real[] if !isempty(MS_poi)
if !isempty(path.poi) for POI in MS_poi
for POI in path.poi s_poi = POI[1]
s_poi = POI[:station] if s_entry < s_poi && s_poi <= s_exit
if POI[:measure] == "rear" push!(pointsOfInterest, (POI))
s_poi -= s_trainLength
end
if s_entry < s_poi && s_poi < s_exit
push!(pointsOfInterest, (s_poi, POI[:label]) )
# push!(pointsOfInterest, s_poi )
end end
end end
end end
push!(pointsOfInterest, (s_exit,"")) # s_exit has to be the last POI so that there will always be a POI to campare the current position with if isempty(pointsOfInterest) || pointsOfInterest[end][1] < s_exit
# push!(pointsOfInterest, s_exit) # s_exit has to be the last POI so that there will always be a POI to campare the current position with push!(pointsOfInterest, (s_exit,"")) # s_exit has to be the last POI so that there will always be a POI to campare the current position with
end
merge!(characteristicSection, Dict(:pointsOfInterest => pointsOfInterest)) merge!(characteristicSection, Dict(:pointsOfInterest => pointsOfInterest))
return characteristicSection return characteristicSection
@ -735,7 +742,7 @@ function DataPoint()
:R_train => 0.0, # train resistance (in N) :R_train => 0.0, # train resistance (in N)
:R_traction => 0.0, # traction unit resistance (in N) :R_traction => 0.0, # traction unit resistance (in N)
:R_wagons => 0.0, # set of wagons resistance (in N) :R_wagons => 0.0, # set of wagons resistance (in N)
:label => "" # a label for importend points :label => "" # a label for important points
) )
return dataPoint return dataPoint
end #function DataPoint end #function DataPoint

View File

@ -28,7 +28,7 @@
## } ## }
######################### #########################
approxLevel = 6 #approxLevel = 6
v00 = 100/3.6 # velocity factor (in m/s) v00 = 100/3.6 # velocity factor (in m/s)
## calculate forces ## calculate forces
@ -55,30 +55,47 @@ function calcTractionUnitResistance(v::AbstractFloat, train::Train)
# equation is based on [Wende:2003, page 151] # equation is based on [Wende:2003, page 151]
f_Rtd0 = train.f_Rtd0 # coefficient for basic resistance due to the traction units driving axles (in ‰) 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_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) f_Rt2 = train.f_Rt2 # coefficient for air resistance of the traction unit (in ‰)
m_td = train.m_td # mass on the traction unit's driving axles (in kg) 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) m_tc = train.m_tc # mass on the traction unit's carrying axles (in kg)
F_R_tractionUnit = f_Rtd0/1000 * m_td * g + f_Rtc0/1000 * m_tc * g + F_Rt2 * ((v + Δv_air) /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_air) /v00)^2 # vehicle resistance of the traction unit (in N) F_R_tractionUnit = f_Rtd0/1000 * m_td * g + f_Rtc0/1000 * m_tc * g + f_Rt2/1000 * (m_td+m_tc) * g * ((v + Δv_air) /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) + calcForceFromCoefficient(f_Rt2, m_td+m_tc) * ((v + Δv_air) /v00)^2 # vehicle resistance of the traction unit (in N)
return F_R_tractionUnit return F_R_tractionUnit
#TODO: same variable name like in the rest of the tool? return R_traction #TODO: same variable name like in the rest of TrainRuns? 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_air)/v00)^2 # /1000 because of the unit ‰
end #function calcTractionUnitResistance end #function calcTractionUnitResistance
""" """
TODO TODO
calculate and return the wagons vehicle resistance dependend on the velocity calculate and return the freight wagons' vehicle resistance dependend on the velocity
""" """
function calcWagonsResistance(v::AbstractFloat, train::Train) function calcFreightWagonsResistance(v::AbstractFloat, train::Train)
# equation is based on a combination of the equations of Strahl and Sauthoff [Wende:2003, page 153] with more detailled factors (Lehmann, page 135) # equation is based on a combination of the equations of Strahl and Sauthoff [Wende:2003, page 153]
f_Rw0 = train.f_Rw0 # coefficient for basic resistance of the set of wagons (consist) (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)
F_R_wagons = m_w *g *(f_Rw0/1000 + f_Rw2/1000 * (v /v00)^2) # vehicle resistance of freight wagons (in N) with Strahl # /1000 because of the unit ‰
# TODO: use calcForceFromCoefficient? F_R_wagons = calcForceFromCoefficient(f_Rw0, m_w) + ...
return F_R_wagons
end #function calcWagonsResistance
"""
TODO
calculate and return the passenger wagons' vehicle resistance dependend on the velocity
"""
function calcPassengerWagonsResistance(v::AbstractFloat, train::Train)
# equation is based on the equations of Sauthoff [Wende:2003, page 153]
f_Rw0 = train.f_Rw0 # coefficient for basic resistance of the set of wagons (consist) (in ‰) 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_Rw1 = train.f_Rw1 # coefficient for the consists resistance to rolling (in ‰)
f_Rw2 = train.f_Rw2 # coefficient fo the consistsr air resistance (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) m_w = train.m_w # mass of the set of wagons (consist) (in kg)
F_R_wagons = m_w *g *(f_Rw0/1000 + f_Rw1/1000 *v /v00 + f_Rw2/1000 * ((v + Δv_air) /v00)^2) # vehicle resistance of the wagons (in N) # /1000 because of the unit ‰ F_R_wagons = m_w *g *(f_Rw0/1000 + f_Rw1/1000 *v /v00 + f_Rw2/1000 * ((v + Δv_air) /v00)^2) # vehicle resistance of passenger wagons (in N) with Sauthoff # /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_air) /v00)^2 # vehicle resistance of the wagons (in N)
# TODO: use calcForceFromCoefficient? F_R_wagons = calcForceFromCoefficient(f_Rw0, m_w) + ...
return F_R_wagons return F_R_wagons
end #function calcWagonsResistance end #function calcWagonsResistance
@ -172,24 +189,7 @@ function calc_Δv_with_Δt(Δt::Real, a_prev::Real)
return Δv return Δv
end #function calc_Δv_with_Δt end #function calc_Δv_with_Δt
function calc_ΔW(F_T_prev::Real, Δs::Real) function calcBrakingDistance(v_start::Real, v_end::Real, a_braking::Real, approxLevel::Integer)
# equation is based on [Wende:2003, 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
# TODO!
# Δ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:2003, page 37] # equation is based on [Wende:2003, page 37]
# v_start: velocity at the start of braking (in m/s) # v_start: velocity at the start of braking (in m/s)
@ -198,18 +198,18 @@ function calcBrakingDistance(v_start::Real, v_end::Real, a_braking::Real)
s_braking = (v_end^2 - v_start^2) /2 /a_braking # braking distance (in m) 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) # TODO: also possible: calc_Δs_with_Δv(v_end-v_start, a_braking, v_start)
# return max(0.0, ceil(s_braking, digits=approxLevel)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors # return max(0.0, ceil(s_braking, digits=approxLevel)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors
return max(0.0, ceil(s_braking, digits=approxLevel +1)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors return max(0.0, ceil(s_braking, digits= approxLevel +1)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors
end #function calcBrakingDistance end #function calcBrakingDistance
function calcBrakingStartVelocity(v_end::Real, a_braking::Real, s_braking::Real) function calcBrakingStartVelocity(v_end::Real, a_braking::Real, s_braking::Real, approxLevel::Integer)
# equation is based on [Wende:2003, page 37] # equation is based on [Wende:2003, page 37]
# v_end: target velocity at the end 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) # a_braking: constant braking acceleration (in m/s^2)
# s_braking: braking distance (in Ws) # s_braking: braking distance (in Ws)
v_start = sqrt(v_end^2 - 2*a_braking *s_braking) # braking start velocity (in m/s) v_start = sqrt(v_end^2 - 2*a_braking *s_braking) # braking start velocity (in m/s)
# return floor(v_start, digits=approxLevel) # return floor(v_start, digits= approxLevel)
return floor(v_start, digits=approxLevel +1) return floor(v_start, digits= approxLevel +1)
end #function calcBrakingStartVelocity end #function calcBrakingStartVelocity
function calcBrakingAcceleration(v_start::Real, v_end::Real, s_braking::Real) function calcBrakingAcceleration(v_start::Real, v_end::Real, s_braking::Real)

View File

@ -5,106 +5,63 @@
# __copyright__ = "2020-2022" # __copyright__ = "2020-2022"
# __license__ = "ISC" # __license__ = "ISC"
function createOutput(train::Train, settings::Settings, path::Path, movingSection::Dict, drivingCourse::Vector{Dict}) function createOutput(settings::Settings, drivingCourse::Vector{Dict}, pointsOfInterest::Vector{Tuple})
if settings.outputDetail == :running_time if settings.outputDetail == :running_time
output = movingSection[:t] # TODO: or use drivingCourse[end][:t] output::Vector{Dict} = [Dict(:t => drivingCourse[end][:t])]
elseif settings.outputDetail == :points_of_interest elseif settings.outputDetail == :points_of_interest && !isempty(pointsOfInterest)
# add points of interest # get only the driving course's data points with POI labels
if !isempty(path.poi) output = Dict[]
dataPoint = 1
# for elem in 1:length(driving_course) for POI in 1:length(pointsOfInterest)
# end while dataPoint <= length(drivingCourse)
if pointsOfInterest[POI][1] == drivingCourse[dataPoint][:s]
output = Dict[] push!(output, drivingCourse[dataPoint])
POI = 1 break
i = 1
while POI <= length(path.poi) && i <= drivingCourse[end][:i]
if path.poi[POI][:station] == drivingCourse[i][:s]
push!(output, drivingCourse[i])
POI = POI+1
end end
i = i+1 dataPoint += 1
end end
end end
elseif settings.outputDetail == :driving_course else #if settings.outputDetail == :driving_course || (settings.outputDetail == :points_of_interest && !isempty(path.poi))
output = drivingCourse output = drivingCourse
end
elseif settings.outputDetail == :everything
output = Dict{Symbol,Any}() if settings.outputFormat == :dataframe
merge!(output, Dict(:train => train, :path => path, :settings => settings)) return createDataFrame(output, settings.outputDetail)
elseif settings.outputFormat == :vector
return output
# add moving section and driving courses
if settings[:operationModeMinimumRunningTime] == true
merge!(output, Dict(:movingSectionMinimumRunningTime => movingSection,
:drivingCourseMinimumRunningTime => drivingCourse))
elseif settings[:operationModeMinimumEnergyConsumption] == true
merge!(output, Dict(:movingSectionMinimumEnergyConsumption => movingSection,
:drivingCourseMinimumEnergyConsumption => drivingCourse))
end
# add points of interest
if !isempty(path.poi)
pointsOfInterest = Vector{Dict}()
POI = 1
i = 1
while POI <= length(path.poi) && i <= drivingCourse[end][:i]
if path.poi[POI] == drivingCourse[i][:s]
push!(pointsOfInterest, drivingCourse[i])
POI = POI+1
end
i = i+1
end
if settings[:operationModeMinimumRunningTime] == true
merge!(output, Dict(:pointsOfInterestMinimumRunningTime => pointsOfInterest))
elseif settings[:operationModeMinimumEnergyConsumption] == true
merge!(output, Dict(:pointsOfInterestMinimumEnergyConsumption => pointsOfInterest))
end
end
else
output = nothing
end end
return output
end end
#=
function createOutputDict(train::Train, settings::Settings, path::Path, movingSection::Dict, drivingCourse::Vector{Dict})
outputDict = Dict{Symbol,Any}()
merge!(outputDict, Dict(:train => train, :path => path, :settings => settings))
function createDataFrame(output_vector::Vector{Dict}, outputDetail)
if outputDetail == :running_time
# create a DataFrame with running time information
dataFrame = DataFrame(t=[output_vector[end][:t]])
else # :points_of_interest or :driving_course
columnSymbols = [:label, :behavior, :s, :v, :t, :a, :F_T, :F_R, :R_path, :R_traction, :R_wagons]
# add moving section and driving courses allColumns = []
if settings[:operationModeMinimumRunningTime] == true for column in 1:length(columnSymbols)
merge!(outputDict, Dict(:movingSectionMinimumRunningTime => movingSection, if typeof(output_vector[1][columnSymbols[column]]) == String
:drivingCourseMinimumRunningTime => drivingCourse)) currentStringColumn::Vector{String} = []
elseif settings[:operationModeMinimumEnergyConsumption] == true for point in output_vector
merge!(outputDict, Dict(:movingSectionMinimumEnergyConsumption => movingSection, push!(currentStringColumn, point[columnSymbols[column]])
:drivingCourseMinimumEnergyConsumption => drivingCourse)) end
end push!(allColumns, currentStringColumn)
elseif typeof(output_vector[1][columnSymbols[column]]) <: Real
# add points of interest currentRealColumn::Vector{Real} = []
if !isempty(path.poi) for point in output_vector
pointsOfInterest = Vector{Dict}() push!(currentRealColumn, point[columnSymbols[column]])
POI = 1 end
i = 1 push!(allColumns, currentRealColumn)
while POI <= length(path.poi) && i <= drivingCourse[end][:i]
if path.poi[POI] == drivingCourse[i][:s]
push!(pointsOfInterest, drivingCourse[i])
POI = POI+1
end end
i = i+1 end # for
end
if settings[:operationModeMinimumRunningTime] == true # combine the columns in a data frame
merge!(outputDict, Dict(:pointsOfInterestMinimumRunningTime => pointsOfInterest)) dataFrame = DataFrame(label=allColumns[1], driving_mode=allColumns[2], s=allColumns[3], v=allColumns[4], t=allColumns[5], a=allColumns[6], F_T=allColumns[7], F_R=allColumns[8], R_path=allColumns[9], R_traction=allColumns[10], R_wagons=allColumns[11])
elseif settings[:operationModeMinimumEnergyConsumption] == true
merge!(outputDict, Dict(:pointsOfInterestMinimumEnergyConsumption => pointsOfInterest))
end
end end
return outputDict return dataFrame
end # function createOutputDict end #createDataFrameForDrivingCourse
=#

View File

@ -10,10 +10,10 @@ struct Settings
massModel::Symbol # model type of train mass ":mass_point" or ":homogeneous_strip". massModel::Symbol # model type of train mass ":mass_point" or ":homogeneous_strip".
stepVariable::Symbol # variable of the linear multistep method: ":distance", ":time" or ":velocity". stepVariable::Symbol # variable of the linear multistep method: ":distance", ":time" or ":velocity".
stepSize::Real # step size, unit depends on stepVariable - :distance in meter, time in seconds and velocity in meter/second. stepSize::Real # step size, unit depends on stepVariable - :distance in meter, time in seconds and velocity in meter/second.
approxLevel::Int # value for approximation; used when rounding or interating. approxLevel::Int # value for approximation; used when rounding or iterating.
outputDetail::Symbol # single Float() ":running_time", Array() of ":points_of_interest", outputDetail::Symbol # single Float() ":running_time", Vector() of ":points_of_interest",
# complete Array() ":driving_course", or Dict() ":everything". # or complete Vector() ":driving_course"
outputFormat::Symbol # output as ":dataframe" or as ":dict". outputFormat::Symbol # output as ":dataframe" or as ":vector".
end #struct Settings end #struct Settings
@ -45,10 +45,10 @@ struct Train
a_braking::Real # in m/s^2 a_braking::Real # in m/s^2
# coefficients for the vehicle resistance # coefficients for the vehicle resistance
# for the traction unit (F_Rt=f_Rtd0*m_td*g+f_Rtc0*m_tc*g+F_Rt2*((v+Δv_air)/v00)^2) # for the traction unit (F_Rt=f_Rtd0*m_td*g+f_Rtc0*m_tc*g+f_Rt2*m_loco*g*((v+Δv_air)/v00)^2)
f_Rtd0::Real # coefficient for basic resistance due to the traction units driving axles (in ‰) f_Rtd0::Real # coefficient for basic resistance due to the traction units driving axles (in ‰)
f_Rtc0::Real # coefficient for basic resistance due to the traction units carring axles (in ‰) f_Rtc0::Real # coefficient for basic resistance due to the traction units carring axles (in ‰)
F_Rt2::Real # coefficient for air resistance of the traction units (in N) f_Rt2::Real # coefficient for air resistance of the traction units (in ‰)
# for the consist (set of wagons) (F_Rw=m_w*g*(f_Rw0+f_Rw1*v/v00+f_Rw2*((v+Δv_air)/v00)^2)) # for the consist (set of wagons) (F_Rw=m_w*g*(f_Rw0+f_Rw1*v/v00+f_Rw2*((v+Δv_air)/v00)^2))
f_Rw0::Real # coefficient for the consists basic resistance (in ‰) f_Rw0::Real # coefficient for the consists basic resistance (in ‰)

View File

@ -1,4 +1,4 @@
%YAML 1.2 %YAML 1.2
--- ---
settings: settings:
outputDetail: "driving_course" # single value "running_time", array of "points_of_interest",complete array "driving_course", or dict() "everything" outputDetail: "driving_course" # single value "running_time", list of "points_of_interest", complete "driving_course"

View File

@ -1,4 +0,0 @@
%YAML 1.2
---
settings:
outputDetail: "everything" # single value "running_time", array of "points_of_interest",complete array "driving_course", or dict() "everything"

View File

@ -1,4 +1,4 @@
%YAML 1.2 %YAML 1.2
--- ---
settings: settings:
outputDetail: "points_of_interest" # single value "running_time", array of "points_of_interest",complete array "driving_course", or dict() "everything" outputDetail: "points_of_interest" # single value "running_time", list of "points_of_interest", complete "driving_course"

View File

@ -37,7 +37,7 @@ vehicles:
rotation_mass: 1.09 # source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit rotation_mass: 1.09 # source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit
base_resistance: 2.2 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsige Diesellokomot." -> 2.2 ‰ to 3.5 ‰ base_resistance: 2.2 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsige Diesellokomot." -> 2.2 ‰ to 3.5 ‰
air_resistance: 0.01 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "MittelfUhrerstand" -> 5000 N to 10000 N; modified for the used formula air_resistance: 10 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "MittelfUhrerstand" -> 5000 N to 10000 N; modified for the used formula
tractive_effort: tractive_effort:
- [0.0, 186940] - [0.0, 186940]

View File

@ -9,12 +9,12 @@ trains:
vehicles: vehicles:
- name: Siemens Desiro Classic # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic - name: Siemens Desiro Classic # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic
id: DB_BR_642 id: DB_BR_642
UUID: c915c80d-c63d-490b-879f-c481e4b62b55 UUID: c915c80d-c63d-490b-879f-c481e4b62b55
picture: https://commons.wikimedia.org/wiki/File:Liesel_28-11-10_642_055-8_im_Bahnhof_Scharfenstein.JPG picture: https://commons.wikimedia.org/wiki/File:Liesel_28-11-10_642_055-8_im_Bahnhof_Scharfenstein.JPG
power_type: diesel # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic power_type: diesel # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic
vehicle_type: multiple unit # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic vehicle_type: multiple unit # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic
length: 41.7 # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic length: 41.7 # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic
mass: 68.0 # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic mass: 68.0 # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic
load_limit: 20.0 # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic load_limit: 20.0 # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic
@ -26,7 +26,7 @@ vehicles:
rotation_mass: 1.08 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 13 for "Zug, überschlägliche Berechnung" rotation_mass: 1.08 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 13 for "Zug, überschlägliche Berechnung"
base_resistance: 3.0 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "f_WL0" -> 2.5 ‰ to 3.5 ‰ base_resistance: 3.0 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "f_WL0" -> 2.5 ‰ to 3.5 ‰
rolling_resistance: 1.4 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "f_WW0" -> 1.2 ‰ to 1.6 ‰ rolling_resistance: 1.4 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "f_WW0" -> 1.2 ‰ to 1.6 ‰
air_resistance: 0.0039 # source: the closest parameters are used: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "Fzg. vierachsig, abgerundeter Kopf" plus "Sektion bei Mehrteiligkeit" -> 2200 N + 400 N air_resistance: 3.9 # source: the closest parameters are used: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "Fzg. vierachsig, abgerundeter Kopf" plus "Sektion bei Mehrteiligkeit" -> 2200 N + 400 N
# tractive effort as pairs of speed and tractive effort # tractive effort as pairs of speed and tractive effort
tractive_effort: tractive_effort:

View File

@ -54,7 +54,7 @@ vehicles:
rotation_mass: 1.09 # source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit rotation_mass: 1.09 # source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit
base_resistance: 2.5 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsige Diesellokomot." -> 2.2 ‰ to 3.5 ‰ base_resistance: 2.5 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsige Diesellokomot." -> 2.2 ‰ to 3.5 ‰
air_resistance: 0.006 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsig, eckige Kopfform" with "Stromabnehmer" -> 5000 N to 6000 N; modified for the used formula air_resistance: 6.0 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsig, eckige Kopfform" with "Stromabnehmer" -> 5000 N to 6000 N; modified for the used formula
tractive_effort: tractive_effort:
- [0.0, 300000] - [0.0, 300000]

View File

@ -28,7 +28,6 @@ settings = Dict()
push!(settings, "default" => @time Settings()) push!(settings, "default" => @time Settings())
push!(settings, "poi" => @time Settings("data/settings/points_of_interest.yaml")) push!(settings, "poi" => @time Settings("data/settings/points_of_interest.yaml"))
push!(settings, "drivingcourse" => @time Settings("data/settings/driving_course.yaml")) push!(settings, "drivingcourse" => @time Settings("data/settings/driving_course.yaml"))
push!(settings, "everything" => @time Settings("data/settings/everything.yaml"))
push!(settings, "strip" => @time Settings("data/settings/strip.yaml")) push!(settings, "strip" => @time Settings("data/settings/strip.yaml"))
push!(settings, "time" => @time Settings("data/settings/time.yaml")) push!(settings, "time" => @time Settings("data/settings/time.yaml"))
push!(settings, "timestrip" => @time Settings("data/settings/time_strip.yaml")) push!(settings, "timestrip" => @time Settings("data/settings/time_strip.yaml"))
@ -53,18 +52,18 @@ tests = Base.Iterators.product(trains,paths)
anticipated = Dict( anticipated = Dict(
:default => Dict( :default => Dict(
:longdistance_speed => 499.96109564970516, :freight_const => 746.6594691660882,
:freight_slope => 831.4768274141168, :freight_slope => 842.3797947097586,
:local_slope => 396.99313307033276, :freight_speed => 751.9727357301351,
:longdistance_const => 328.83479381353095, :freight_realworld => 8789.299477891092,
:freight_realworld => 8971.50124080998, :local_const => 392.6801497584646,
:longdistance_slope => 329.22915822053164, :local_slope => 396.59291844946534,
:freight_const => 727.7969403041934, :local_speed => 524.3734475900396,
:longdistance_realworld => 2900.1198723158523, :local_realworld => 3438.3543735577446,
:local_speed => 524.3948201513945, :longdistance_const => 330.8511578156266,
:local_realworld => 3443.917823618831, :longdistance_slope => 331.7163794230447,
:freight_speed => 733.2610572579886, :longdistance_speed => 501.13448446081713,
:local_const => 392.7234008268302 :longdistance_realworld => 2913.3759609192407
) )
) )
@ -75,7 +74,7 @@ anticipated = Dict(
for test in tests for test in tests
test_name = String(test[1][1]) * "_" * String(test[2][1]) test_name = String(test[1][1]) * "_" * String(test[2][1])
println("testing $test_name") println("testing $test_name")
@time result = trainrun(test[1][2],test[2][2]) @time result = trainrun(test[1][2], test[2][2])[end, :t]
expected = anticipated[:default][Symbol(test_name)] expected = anticipated[:default][Symbol(test_name)]
# compare result to test data set # compare result to test data set
@test isapprox(result, expected, rtol=0.01) @test isapprox(result, expected, rtol=0.01)