Refactor modules for diminishing run and tractive effort velocity pairs

pull/1/head v0.5
Max Kannenberg 2021-12-08 22:44:35 +01:00
parent fb942260d2
commit 7eed749d49
9 changed files with 646 additions and 366 deletions

View File

@ -1,7 +1,7 @@
name = "TrainRun" name = "TrainRun"
uuid = "e4541106-d44c-4e00-b50b-ecdf479fcf92" uuid = "e4541106-d44c-4e00-b50b-ecdf479fcf92"
authors = ["Max Kannenberg"] authors = ["Max Kannenberg"]
version = "0.2.0" version = "0.5.0"
[deps] [deps]
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"

View File

@ -23,18 +23,28 @@ See folder examples.
# History # History
## Version 0.5
Refactor modules for diminishing run and tractive effort velocity pairs
- Add the seperate moving phase "diminishing run" for steep ascents where a train runs with maximum tractive effort while the driving resistances are even higher
- Refactor tractiveEffortArray to tractiveEffortVelocityPairs
- Rename file path and folder path to directory
## Version 0.4.1 ## Version 0.4.1
Rename waypoints Rename waypoints
- rename "waypoints" to "dataPoints" and "Waypoint" to "DataPoint" - rename "waypoints" to "dataPoints" and "Waypoint" to "DataPoint"
## Version 0.4 ## Version 0.4
Refactor and fix modules EnergySaving, OperationModes and MovingPhases Refactor and fix modules EnergySaving, OperationModes and MovingPhases
- add the general used level of accuracy from v0.3 to EnergySaving and OperationModes. - add the general used level of accuracy from v0.3 to EnergySaving and OperationModes
- fix OperationModes and MovingPhases for steep ascents where a train runs with maximum tractive effort while the driving resistances are even higher. - fix OperationModes and MovingPhases for steep ascents where a train runs with maximum tractive effort while the driving resistances are even higher
## Version 0.3 ## Version 0.3
@ -42,7 +52,7 @@ Refactor and fix modules EnergySaving, OperationModes and MovingPhases
Refactor module MovingPhases Refactor module MovingPhases
- extract repeatedly occuring code lines and create smaller functions (e.g. the function moveAStep) - extract repeatedly occuring code lines and create smaller functions (e.g. the function moveAStep)
- integrate a new approach for calculating the waypoints near intersections (e.g. including an editable level of accuracy). - integrate a new approach for calculating the waypoints near intersections (e.g. including an editable level of accuracy)
## Version 0.2 ## Version 0.2

View File

@ -90,6 +90,214 @@ function calculateRecoveryTime(s_MS::AbstractFloat, t_MS::AbstractFloat, train::
end #function calculateRecoveryTime end #function calculateRecoveryTime
function increaseCoastingSection(csOriginal::CharacteristicSection, drivingCourse::Vector{DataPoint}, settings::Settings, train::Train, allCSs::Vector{CharacteristicSection}, t_recoveryAvailable::AbstractFloat) function increaseCoastingSection(csOriginal::CharacteristicSection, drivingCourse::Vector{DataPoint}, settings::Settings, train::Train, allCSs::Vector{CharacteristicSection}, t_recoveryAvailable::AbstractFloat)
if (haskey(csOriginal.behaviorSections, "cruising") || haskey(csOriginal.behaviorSections, "diminishing")) && haskey(csOriginal.behaviorSections, "braking")
# check if cruising or diminishing should be reduced for coasting
if haskey(csOriginal.behaviorSections, "cruising") && haskey(csOriginal.behaviorSections, "diminishing")
if get(csOriginal.behaviorSections, "cruising", BehaviorSection()).dataPoints[1] > get(csOriginal.behaviorSections, "diminishing", BehaviorSection()).dataPoints[1]
reduceCruising=true
reduceDiminishing=false
else
reduceDiminishing=true
reduceCruising=false
end
elseif haskey(csOriginal.behaviorSections, "cruising")
reduceCruising=true
reduceDiminishing=false
elseif haskey(csOriginal.behaviorSections, "diminishing")
reduceDiminishing=true
reduceCruising=false
end
if reduceCruising
cruisingReduction=settings.stepSize
while cruisingReduction>=settings.stepSize/10^approximationLevel
#while cruisingReduction>=settings.stepSize/100
while cruisingReduction>=settings.stepSize/10^approximationLevel # will be done once and then depending on approximationLevel repeated with smaller cruisingReduction unless !(drivingCourseModified[end].v<=csModified.v_exit && drivingCourseModified[end].s<csModified.s_end) -> see below at the end of the while loop
# create a copy for the characteristic sections drivingCourse
energySavingStartId=get(csOriginal.behaviorSections, "cruising", BehaviorSection()).dataPoints[1]
if energySavingStartId==0
error("ERROR at creating a new driving course for energy saving with coasting !")
end
# copy the driving course till the beginning of energy saving
drivingCourseModified=Vector{DataPoint}()
for i in 1:energySavingStartId
push!(drivingCourseModified, DataPoint(drivingCourse[i])) # List of data points till the start of energy saving
# TODO: tried to insert copy on 15.07.2021 push!(drivingCourseModified, copy(drivingCourse[i])) # List of data points till the start of energy saving
end
# calculating the new length of the cruising section
if settings.stepVariable=="s in m" # distance step method
s_cruising=get(csOriginal.behaviorSections, "cruising", BehaviorSection()).s_total-cruisingReduction
elseif settings.stepVariable=="t in s" # time step method
# 09/20 old: doesn't work for non constant cruising
# t_cruising=get(csOriginal.behaviorSections, "cruising", BehaviorSection()).t_total-cruisingReduction
# s_cruising=t_cruising*drivingCourseModified[end].v
wayReduction=drivingCourse(get(csOriginal.behaviorSections, "cruising", BehaviorSection()).dataPoints[end]).v*cruisingReduction
s_cruising=get(csOriginal.behaviorSections, "cruising", BehaviorSection()).s_total-wayReduction
elseif settings.stepVariable=="v in m/s" # velocity step method
s_cruising=get(csOriginal.behaviorSections, "cruising", BehaviorSection()).s_total-cruisingReduction*10 # TODO: or better: *100 ?
end #if
s_cruising=max(0.0, s_cruising)
# copy csOriginal to csModified
csModified=CharacteristicSection(csOriginal.id, csOriginal.s_total, csOriginal.s_start, csOriginal.s_end, 0.0, 0.0, csOriginal.v_limit, csOriginal.v_reach, csOriginal.v_entry, csOriginal.v_exit, csOriginal.f_Rp, Dict{String, BehaviorSection}())
if haskey(csOriginal.behaviorSections, "starting")
startingSection=BehaviorSection(get(csOriginal.behaviorSections, "starting", BehaviorSection()))
merge!(csModified.behaviorSections, Dict("starting"=>startingSection))
csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "starting", BehaviorSection()).E_total
csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "starting", BehaviorSection()).t_total
end
if haskey(csOriginal.behaviorSections, "cruisingBeforeAcceleration") # this section is needed before acceleration if the mass strip model is used and if the train wants to accelerate to a velocity higher than the limit in the other CS where parts of the union are still located
cruisingBeforeAccelerationSection=BehaviorSection(get(csOriginal.behaviorSections, "cruisingBeforeAcceleration", BehaviorSection()))
merge!(csModified.behaviorSections, Dict("cruisingBeforeAcceleration"=>cruisingBeforeAccelerationSection))
csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "cruisingBeforeAcceleration", BehaviorSection()).E_total
csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "cruisingBeforeAcceleration", BehaviorSection()).t_total
end
if haskey(csOriginal.behaviorSections, "acceleration")
accelerationSection=BehaviorSection(get(csOriginal.behaviorSections, "acceleration", BehaviorSection()))
merge!(csModified.behaviorSections, Dict("acceleration"=>accelerationSection))
csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "acceleration", BehaviorSection()).E_total
csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "acceleration", BehaviorSection()).t_total
end
if haskey(csOriginal.behaviorSections, "diminishing")
diminishingSection=BehaviorSection(get(csOriginal.behaviorSections, "diminishing", BehaviorSection()))
merge!(csModified.behaviorSections, Dict("diminishing"=>diminishingSection))
csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "diminishing", BehaviorSection()).E_total
csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "diminishing", BehaviorSection()).t_total
end
# calculate the new and now shorter cruising section
if s_cruising>0.0
(csModified, drivingCourseModified)=addCruisingPhase!(csModified, drivingCourseModified, s_cruising, settings, train, allCSs, "cruising")
end
# calculate the coasting phase until the point the train needs to brake
(csModified, drivingCourseModified)=addCoastingPhaseUntilBraking!(csModified, drivingCourseModified, settings, train, allCSs)
if drivingCourseModified[end].v < csModified.v_exit || drivingCourseModified[end].s > csModified.s_end
# the train reaches v_exit before reaching s_end. The cruising and coasting sections have to be calculated again with a larger cruising section (so with a smaller reduction of the cruising section)
cruisingReduction=cruisingReduction/10
else
break
end
end # while cruisingReduction
# calculate the moving phase between coasting and the end of the CS
if drivingCourseModified[end].v > csModified.v_exit
#(csModified, drivingCourseModified)=addBrakingPhase!(csModified, drivingCourseModified, settings.massModel, train, allCSs)
(csModified, drivingCourseModified)=addBrakingPhase!(csModified, drivingCourseModified, settings, train, allCSs)
elseif drivingCourseModified[end].v == csModified.v_exit && drivingCourseModified[end].s < csModified.s_end
# v_exit is already reached. Now cruise till the end of the CS
s_cruisingAfterCoasting=csModified.s_end-drivingCourseModified[end].s
(csModified, drivingCourseModified)=addCruisingPhase!(csModified, drivingCourseModified, s_cruisingAfterCoasting, settings, train, allCSs, "cruisingAfterCoasting")
end
if t_recoveryAvailable < csModified.t_total-csOriginal.t_total || drivingCourseModified[end].v != csModified.v_exit || drivingCourseModified[end].s != csModified.s_end # time loss is to high and the CS has to be calculated again with larger cruising section (so with a smaller reduction of the cruising section) or v_exit or s_end are not reached excatly
cruisingReduction=cruisingReduction/10
else
return (csModified, drivingCourseModified, true)
end
end #while
elseif reduceDiminishing
# TODO: At the moment diminishing is reduced like the acceleration in decreaseMaximumVelocity. To reduce code, the methods for reducing cruising phase an reducing the diminishing pahse can be combined in some parts.
# copy csOriginal to csModified
csModified=CharacteristicSection(csOriginal.id, csOriginal.s_total, csOriginal.s_start, csOriginal.s_end, 0.0, 0.0, csOriginal.v_limit, csOriginal.v_reach, csOriginal.v_entry, csOriginal.v_exit, csOriginal.f_Rp, Dict{String, BehaviorSection}())
if haskey(csOriginal.behaviorSections, "starting")
startingSection=BehaviorSection(get(csOriginal.behaviorSections, "starting", BehaviorSection()))
merge!(csModified.behaviorSections, Dict("starting"=>startingSection))
csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "starting", BehaviorSection()).E_total
csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "starting", BehaviorSection()).t_total
end
if haskey(csOriginal.behaviorSections, "cruisingBeforeAcceleration") # this section is needed before acceleration if the mass strip model is used and if the train wants to accelerate to a velocity higher than the limit in the other CS where parts of the union are still located
cruisingBeforeAccelerationSection=BehaviorSection(get(csOriginal.behaviorSections, "cruisingBeforeAcceleration", BehaviorSection()))
merge!(csModified.behaviorSections, Dict("cruisingBeforeAcceleration"=>cruisingBeforeAccelerationSection))
csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "cruisingBeforeAcceleration", BehaviorSection()).E_total
csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "cruisingBeforeAcceleration", BehaviorSection()).t_total
end
if haskey(csOriginal.behaviorSections, "acceleration")
accelerationSection=BehaviorSection(get(csOriginal.behaviorSections, "acceleration", BehaviorSection()))
merge!(csModified.behaviorSections, Dict("acceleration"=>accelerationSection))
csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "acceleration", BehaviorSection()).E_total
csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "acceleration", BehaviorSection()).t_total
end
if haskey(csOriginal.behaviorSections, "cruising")
cruisingSection=BehaviorSection(get(csOriginal.behaviorSections, "cruising", BehaviorSection()))
merge!(csModified.behaviorSections, Dict("cruising"=>cruisingSection))
csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "cruising", BehaviorSection()).E_total
csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "cruising", BehaviorSection()).t_total
end
diminishingSection=BehaviorSection(get(csOriginal.behaviorSections, "diminishing", BehaviorSection()))
if length(diminishingSection.dataPoints) > 2
# remove the last diminishing waypoint
pop!(diminishingSection.dataPoints)
diminishingSection.v_exit=drivingCourse[diminishingSection.dataPoints[end]].v # exit speed (in m/s)
diminishingSection.s_end=drivingCourse[diminishingSection.dataPoints[end]].s # last position (in m)
diminishingSection.s_total=diminishingSection.s_end-diminishingSection.s_start # total length (in m)
diminishingSection.t_total=drivingCourse[diminishingSection.dataPoints[end]].t-drivingCourse[diminishingSection.dataPoints[1]].t # total running time (in s)
diminishingSection.E_total=drivingCourse[diminishingSection.dataPoints[end]].E-drivingCourse[diminishingSection.dataPoints[1]].E # total energy consumption (in Ws)
merge!(csModified.behaviorSections, Dict("diminishing"=>diminishingSection))
csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "diminishing", BehaviorSection()).E_total
csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "diminishing", BehaviorSection()).t_total
energySavingStartId=diminishingSection.dataPoints[end]
else
# The diminishing section is only one step. This step is removed and if there is a cruisingBeforeAcceleration section it will be combined with the new cruising section.
energySavingStartId=get(csOriginal.behaviorSections, "cruisingBeforeAcceleration", get(csOriginal.behaviorSections, "diminishing", BehaviorSection())).dataPoints[1]
end
# copy the driving course till the beginning of energy saving
drivingCourseModified=Vector{DataPoint}()
for i in 1:energySavingStartId
push!(drivingCourseModified, DataPoint(drivingCourse[i])) # List of data points till the start of energy saving
end
# calculate the coasting phase until the point the train needs to brake
(csModified, drivingCourseModified)=addCoastingPhaseUntilBraking!(csModified, drivingCourseModified, settings, train, allCSs)
# calculate the moving phase between coasting and the end of the CS
if drivingCourseModified[end].v > csModified.v_exit
(csModified, drivingCourseModified)=addBrakingPhase!(csModified, drivingCourseModified, settings, train, allCSs)
elseif drivingCourseModified[end].v == csModified.v_exit && drivingCourseModified[end].s < csModified.s_end
# v_exit is already reached. Now cruise till the end of the CS
s_cruisingAfterCoasting=csModified.s_end-drivingCourseModified[end].s
(csModified, drivingCourseModified)=addCruisingPhase!(csModified, drivingCourseModified, s_cruisingAfterCoasting, settings, train, allCSs, "cruisingAfterCoasting")
end
if t_recoveryAvailable>=(csModified.t_total-csOriginal.t_total)
return (csModified, drivingCourseModified, true)
else # time loss is to high. so there is no energy saving modification for this CS with the available recovery time
# TODO: just return false or take smaller steps?
return (CharacteristicSection(), [], false)
end
end
# there is no energy saving modification for this CS with the available recovery time
return (CharacteristicSection(), [], false)
else
# there is no energy saving modification for this CS because a cruising section AND a braking section are needed to be transformed into a coasting section
return (CharacteristicSection(), [], false)
end
end # function increaseCoastingSection
#= 12/03 old without diminishing: function increaseCoastingSection(csOriginal::CharacteristicSection, drivingCourse::Vector{DataPoint}, settings::Settings, train::Train, allCSs::Vector{CharacteristicSection}, t_recoveryAvailable::AbstractFloat)
if haskey(csOriginal.behaviorSections, "cruising") && haskey(csOriginal.behaviorSections, "braking") if haskey(csOriginal.behaviorSections, "cruising") && haskey(csOriginal.behaviorSections, "braking")
cruisingReduction=settings.stepSize cruisingReduction=settings.stepSize
while cruisingReduction>=settings.stepSize/10^approximationLevel while cruisingReduction>=settings.stepSize/10^approximationLevel
@ -101,11 +309,13 @@ function increaseCoastingSection(csOriginal::CharacteristicSection, drivingCours
if energySavingStartId==0 if energySavingStartId==0
error("ERROR at creating a new driving course for energy saving with coasting !") error("ERROR at creating a new driving course for energy saving with coasting !")
end end
# TODO: tried to insert copy on 15.07.2021 drivingCourseModified=[copy(drivingCourse[1])]
drivingCourseModified=[DataPoint(drivingCourse[1])] drivingCourseModified=[DataPoint(drivingCourse[1])]
# TODO: tried to insert copy on 15.07.2021 drivingCourseModified=[copy(drivingCourse[1])]
for i in 2:energySavingStartId for i in 2:energySavingStartId
# TODO: tried to insert copy on 15.07.2021 push!(drivingCourseModified, copy(drivingCourse[i])) # List of data points till the start of energy saving
push!(drivingCourseModified, DataPoint(drivingCourse[i])) # List of data points till the start of energy saving push!(drivingCourseModified, DataPoint(drivingCourse[i])) # List of data points till the start of energy saving
# TODO: tried to insert copy on 15.07.2021 push!(drivingCourseModified, copy(drivingCourse[i])) # List of data points till the start of energy saving
end end
# calculating the new length of the cruising section # calculating the new length of the cruising section
@ -182,6 +392,7 @@ function increaseCoastingSection(csOriginal::CharacteristicSection, drivingCours
end end
end # function increaseCoastingSection end # function increaseCoastingSection
=#
# method 2 with shortening the acceleration by stepsize # method 2 with shortening the acceleration by stepsize
function decreaseMaximumVelocity(csOriginal::CharacteristicSection, drivingCourse, settings::Settings, train::Train, allCSs::Vector{CharacteristicSection}, t_recoveryAvailable::AbstractFloat) function decreaseMaximumVelocity(csOriginal::CharacteristicSection, drivingCourse, settings::Settings, train::Train, allCSs::Vector{CharacteristicSection}, t_recoveryAvailable::AbstractFloat)
@ -228,7 +439,7 @@ function decreaseMaximumVelocity(csOriginal::CharacteristicSection, drivingCours
energySavingStartId=accelerationSection.dataPoints[end] energySavingStartId=accelerationSection.dataPoints[end]
else else
# The acceleration section is only one step. This step is removed and if ther ist a cruisingBeforeAcceleration section it will be combined with the new cruising section. # The acceleration section is only one step. This step is removed and if there is a cruisingBeforeAcceleration section it will be combined with the new cruising section.
energySavingStartId=get(csOriginal.behaviorSections, "cruisingBeforeAcceleration", get(csOriginal.behaviorSections, "acceleration", BehaviorSection())).dataPoints[1] energySavingStartId=get(csOriginal.behaviorSections, "cruisingBeforeAcceleration", get(csOriginal.behaviorSections, "acceleration", BehaviorSection())).dataPoints[1]
end end

View File

@ -8,10 +8,10 @@ export readInput
""" """
Read the input information from YAML files for train, path and settings, save it in different objects and return them. Read the input information from YAML files for train, path and settings, save it in different objects and return them.
""" """
function readInput(trainFilePath::String, pathFilePath::String, settingsFilePath::String) function readInput(trainDirectory::String, pathDirectory::String, settingsDirectory::String)
train=inputTrain(trainFilePath) train=inputTrain(trainDirectory)
path=inputPath(pathFilePath) path=inputPath(pathDirectory)
settings=inputSettings(settingsFilePath) settings=inputSettings(settingsDirectory)
return (train, path, settings) return (train, path, settings)
end #function readInput end #function readInput
@ -19,8 +19,8 @@ function readInput(trainFilePath::String, pathFilePath::String, settingsFilePath
""" """
Read the train information from a YAML file, save it in a Train object and return it. Read the train information from a YAML file, save it in a Train object and return it.
""" """
function inputTrain(trainFilePath::String) function inputTrain(trainDirectory::String)
data = YAML.load(open(trainFilePath)) data = YAML.load(open(trainDirectory))
collect(keys(data)) collect(keys(data))
collect(values(data)) collect(values(data))
@ -56,8 +56,6 @@ function inputTrain(trainFilePath::String)
end end
# speed limit: # trains speed limit (in m/s) # speed limit: # trains speed limit (in m/s)
v_limit_temp=0.0 v_limit_temp=0.0
v_limit_kmh_temp=0.0 v_limit_kmh_temp=0.0
@ -189,11 +187,13 @@ function inputTrain(trainFilePath::String)
delete!(data["train"], "rotationMassFactor_w") delete!(data["train"], "rotationMassFactor_w")
# input for function tractiveEffort(v) # pairs of velocity and tractive effort
# TODO: Should the arrays check and the arrays copy be in the same "for" loop?
if haskey(data["train"],"F_T_pairs") && data["train"]["F_T_pairs"]!=nothing if haskey(data["train"],"F_T_pairs") && data["train"]["F_T_pairs"]!=nothing
F_T_pairs=data["train"]["F_T_pairs"] F_T_pairs=data["train"]["F_T_pairs"]
train.tractiveEffortVelocityPairs=checkAndDefineTractiveEffortInput(F_T_pairs, 1.0)
#= old 2021-11-04: now it is pairs and no scope
# check if the elements of the array have the correct type # check if the elements of the array have the correct type
errorDetected=false errorDetected=false
for row in 1:length(F_T_pairs) for row in 1:length(F_T_pairs)
@ -207,17 +207,33 @@ function inputTrain(trainFilePath::String)
errorDetected=true errorDetected=true
println("ERROR at reading the train yaml file: The tractive effort value of F_T_pairs in row ", row ," is no real floating point number >=0.0.") println("ERROR at reading the train yaml file: The tractive effort value of F_T_pairs in row ", row ," is no real floating point number >=0.0.")
end end
if row>=2 && F_T_pairs[row][1] <= F_T_pairs[row-1][1]
errorDetected=true
println("ERROR at reading the train yaml file: The speed value of F_T_pairs in row ", row ," (v=",F_T_pairs[row][1]," m/s) is not higher than the speed value in the previous row (v=",F_T_pairs[row-1][1]," m/s).")
end
end # for end # for
if errorDetected if errorDetected
error("ERROR at reading the train yaml file: Only real floating point number >=0.0 are allowed for speed and tractive effort.") error("ERROR at reading the train yaml file: Only real floating point number >=0.0 are allowed for speed and tractive effort. The speed values have to be listed from low to high.")
end end
# create tractiveEffortVelocityPairs
if F_T_pairs[1][1]>0.0 # if there is no F_T for v=0.0, the first known value is used
push!(train.tractiveEffortVelocityPairs, [0.0, F_T_pairs[1][2]])
println("WARNING at reading the train yaml file: The tractive effort for v=0 m/s is missing. Therefore the first given value F_T(v=",F_T_pairs[1][1]," m/s)=",F_T_pairs[1][2]," N will be used." )
end
for row in 1:length(F_T_pairs)
push!(train.tractiveEffortVelocityPairs, [F_T_pairs[row][1]], F_T_pairs[row][2]])
end # for
# create tractiveEffortArray # create tractiveEffortArray
train.tractiveEffortArray=[] train.tractiveEffortArray=[]
if F_T_pairs[1][1]==0.0 if F_T_pairs[1][1]==0.0
push!(train.tractiveEffortArray, [F_T_pairs[1][1], F_T_pairs[1][1], F_T_pairs[1][2]]) push!(train.tractiveEffortArray, [F_T_pairs[1][1], F_T_pairs[1][1], F_T_pairs[1][2]])
elseif F_T_pairs[1][1]>0.0 # if there is no F_T for v=0.0, the first value is used elseif F_T_pairs[1][1]>0.0 # if there is no F_T for v=0.0, the first value is used
push!(train.tractiveEffortArray, [0.0, F_T_pairs[1][1]/3.6, F_T_pairs[1][2]]) push!(train.tractiveEffortArray, [0.0, F_T_pairs[1][1], F_T_pairs[1][2]])
println("WARNING at reading the train yaml file: The tractive effort for v=0 m/s is missing. Therefore the first given value F_T(v=",F_T_pairs[1][1]," m/s)=",F_T_pairs[1][2]," N will be used." ) println("WARNING at reading the train yaml file: The tractive effort for v=0 m/s is missing. Therefore the first given value F_T(v=",F_T_pairs[1][1]," m/s)=",F_T_pairs[1][2]," N will be used." )
else else
error("ERROR at reading the train yaml file: There is a negative speed value in the list. Only positive values for speed and tractive effort are allowed in F_T_pairs.") error("ERROR at reading the train yaml file: There is a negative speed value in the list. Only positive values for speed and tractive effort are allowed in F_T_pairs.")
@ -234,9 +250,11 @@ function inputTrain(trainFilePath::String)
error("ERROR at reading the train yaml file: The F_T_pairs are not in the correct order. They have to be arranged by speed values from low to high.") error("ERROR at reading the train yaml file: The F_T_pairs are not in the correct order. They have to be arranged by speed values from low to high.")
end end
end # for end # for
if length(F_T_pairs[1])>2 if length(F_T_pairs[1])>2
println("INFO according the train yaml file: Only the first two columns of F_T_pairs are used in this tool.") println("INFO according the train yaml file: Only the first two columns of F_T_pairs are used in this tool.")
end end
=#
if haskey(data["train"],"F_T_pairs_kmh") && data["train"]["F_T_pairs_kmh"]!=nothing if haskey(data["train"],"F_T_pairs_kmh") && data["train"]["F_T_pairs_kmh"]!=nothing
println("WARNING at reading the train yaml file: There are values for F_T_pairs and F_T_pairs_kmh. The values for F_T_pairs are used." ) println("WARNING at reading the train yaml file: There are values for F_T_pairs and F_T_pairs_kmh. The values for F_T_pairs are used." )
@ -245,6 +263,9 @@ function inputTrain(trainFilePath::String)
elseif haskey(data["train"],"F_T_pairs_kmh") && data["train"]["F_T_pairs_kmh"]!=nothing elseif haskey(data["train"],"F_T_pairs_kmh") && data["train"]["F_T_pairs_kmh"]!=nothing
F_T_pairs_kmh=data["train"]["F_T_pairs_kmh"] F_T_pairs_kmh=data["train"]["F_T_pairs_kmh"]
train.tractiveEffortVelocityPairs=checkAndDefineTractiveEffortInput(F_T_pairs_kmh, 1000/3600)
#= old 2021-11-04: now it is pairs and no scope
# check if the elements of the array have the correct type # check if the elements of the array have the correct type
errorDetected=false errorDetected=false
for row in 1:length(F_T_pairs_kmh) for row in 1:length(F_T_pairs_kmh)
@ -285,6 +306,7 @@ function inputTrain(trainFilePath::String)
if length(F_T_pairs_kmh[1])>2 if length(F_T_pairs_kmh[1])>2
println("INFO at reading the train yaml file: Only the first two columns of F_T_pairs_kmh are used in this tool.") println("INFO at reading the train yaml file: Only the first two columns of F_T_pairs_kmh are used in this tool.")
end end
=#
else else
error("ERROR at reading the train yaml file: There has to be one of the keywords F_T_pairs or F_T_pairs_kmh filled with a list of pairs of velocity and tractive effort.") error("ERROR at reading the train yaml file: There has to be one of the keywords F_T_pairs or F_T_pairs_kmh filled with a list of pairs of velocity and tractive effort.")
end # if end # if
@ -398,10 +420,53 @@ function inputTrain(trainFilePath::String)
return train return train
end #function inputTrain end #function inputTrain
function checkAndDefineTractiveEffortInput(F_T_pairs, velocityMultiplier::AbstractFloat)
# TODO: check if its numbers are real ? function checkAndDefineTractiveEffortInput(F_T_pairs::Array{Array{Real,1},1}, velocityMultiplier::AbstractFloat)
# check if the elements of the array have the correct type
errorDetected=false
for row in 1:length(F_T_pairs)
if typeof(F_T_pairs[row][1]) <: Real && F_T_pairs[row][1]>=0.0
else
errorDetected=true
println("ERROR at reading the train yaml file: The speed value of F_T_pairs in row ", row ," is no real floating point number >=0.0.")
end
if typeof(F_T_pairs[row][2]) <: Real && F_T_pairs[row][2]>=0.0
else
errorDetected=true
println("ERROR at reading the train yaml file: The tractive effort value of F_T_pairs in row ", row ," is no real floating point number >=0.0.")
end
function inputPath(pathFilePath::String) if row>=2 && F_T_pairs[row][1] <= F_T_pairs[row-1][1]
errorDetected=true
println("ERROR at reading the train yaml file: The speed value of F_T_pairs in row ", row ," (v=",F_T_pairs[row][1]," m/s) is not higher than the speed value in the previous row (v=",F_T_pairs[row-1][1]," m/s).")
end
end # for
if errorDetected
error("ERROR at reading the train yaml file: Only real floating point number >=0.0 are allowed for speed and tractive effort. The speed values have to be listed from low to high.")
end
# create tractiveEffortVelocityPairs
tractiveEffortVelocityPairs=[]
if F_T_pairs[1][1]>0.0 # if there is no F_T for v=0.0, the first known value is used
push!(tractiveEffortVelocityPairs, [0.0, F_T_pairs[1][2]])
println("WARNING at reading the train yaml file: The tractive effort for v=0 m/s is missing. Therefore the first given value F_T(v=",F_T_pairs[1][1]," m/s)=",F_T_pairs[1][2]," N will be used." )
end
for row in 1:length(F_T_pairs)
push!(tractiveEffortVelocityPairs, [F_T_pairs[row][1]*velocityMultiplier, F_T_pairs[row][2]])
end # for
if length(F_T_pairs[1])>2
println("INFO according the train yaml file: Only the first two columns of F_T_pairs are used in this tool.")
end
return tractiveEffortVelocityPairs
end #function checkAndDefineTractiveEffortInput
function inputPath(pathDirectory::String)
# this function reads path information from a YAML file, saves it in a Path object and returns it # this function reads path information from a YAML file, saves it in a Path object and returns it
data = YAML.load(open(pathFilePath)) data = YAML.load(open(pathDirectory))
collect(keys(data)) collect(keys(data))
collect(values(data)) collect(values(data))
@ -504,9 +569,9 @@ end # function inputPath
function inputSettings(settingsFilePath::String) function inputSettings(settingsDirectory::String)
# this function reads setting information from a YAML file, saves it in a Setting object and returns it # this function reads setting information from a YAML file, saves it in a Setting object and returns it
data = YAML.load(open(settingsFilePath)) data = YAML.load(open(settingsDirectory))
collect(keys(data)) collect(keys(data))
collect(values(data)) collect(values(data))
@ -594,16 +659,16 @@ function inputSettings(settingsFilePath::String)
# TODO: it could be checked if the path is existing on the pc # TODO: it could be checked if the path is existing on the pc
if settings.typeOfOutput=="CSV" if settings.typeOfOutput=="CSV"
if haskey(data["settings"],"csvFolderPath") if haskey(data["settings"],"csvDirectory")
if typeof(data["settings"]["csvFolderPath"])==String if typeof(data["settings"]["csvDirectory"])==String
settings.csvFolderPath=data["settings"]["csvFolderPath"] settings.csvDirectory=data["settings"]["csvDirectory"]
else else
error("ERROR at reading the settings yaml file: The value of csvFolderPath is wrong. It has to be of type String.") error("ERROR at reading the settings yaml file: The value of csvDirectory is wrong. It has to be of type String.")
end end
else else
error("ERROR at reading the settings yaml file: The keyword csvFolderPath is missing. It has to be added.") error("ERROR at reading the settings yaml file: The keyword csvDirectory is missing. It has to be added.")
end end
delete!(data["settings"], "csvFolderPath") delete!(data["settings"], "csvDirectory")
end # if end # if

View File

@ -11,16 +11,15 @@ approximationLevel = 6 # value for approximation to intersections TODO further
# TODO: define it in TrainRun and give it to each function? # TODO: define it in TrainRun and give it to each function?
## functions for calculating tractive effort and resisting forces ## functions for calculating tractive effort and resisting forces
#TODO: change tractiveEffortArray to tractiveEffortVelocityPairs ?? Currently the example doesn't fit to the function
""" """
calculateTractiveEffort(v, tractiveEffortArray) calculateTractiveEffort(v, tractiveEffortVelocityPairs)
Calculate the trains tractive effort from the `tractiveEffortArray` dependend on the velocity `v`. Calculate the trains tractive effort with the `tractiveEffortVelocityPairs` dependend on the velocity `v`.
... ...
# Arguments # Arguments
- `v::AbstractFloat`: the current velocity in m/s. - `v::AbstractFloat`: the current velocity in m/s.
- `tractiveEffortArray::Array{Array{AbstractFloat,1},1}`: the trains pairs for velocity in m/s and tractive effort in N as one array containing an array for each pair. - `tractiveEffortVelocityPairs::Array{Array{AbstractFloat,1},1}`: the trains pairs for velocity in m/s and tractive effort in N as one array containing an array for each pair.
... ...
# Examples # Examples
@ -32,25 +31,42 @@ julia> calculateTractiveEffort(30.0, [[0.0, 180000], [20.0, 100000], [40.0, 6000
80000 80000
``` ```
""" """
function calculateTractiveEffort(v::AbstractFloat, tractiveEffortArray) function calculateTractiveEffort(v::AbstractFloat, tractiveEffortVelocityPairs)
for row in 1:length(tractiveEffortArray) for row in 1:length(tractiveEffortVelocityPairs)
if tractiveEffortArray[row][1]<=v && v<=tractiveEffortArray[row][2] if tractiveEffortVelocityPairs[row][1]==v
return tractiveEffortArray[row][3] return tractiveEffortVelocityPairs[row][2]
elseif tractiveEffortArray[row][1]>v elseif tractiveEffortVelocityPairs[row][1]>v
if row>1 # interpolate for a straight line between the two surrounding points with the formula: F=(v-v_(row-1))*(F_row-F_(row-1))/(v_row-v_(row-1))+F_(row-1)
# interpolate for a straight line between the two surrounding points with the formula: F=(v-v_(row-1))*(F_row-_(row-1))/(v_row-v_(row-1))+F_(row-1) F_T_interpolation=(v-tractiveEffortVelocityPairs[row-1][1])*(tractiveEffortVelocityPairs[row][2]-tractiveEffortVelocityPairs[row-1][2])/(tractiveEffortVelocityPairs[row][1]-tractiveEffortVelocityPairs[row-1][1])+tractiveEffortVelocityPairs[row-1][2]
F_T_interpolation=(v-tractiveEffortArray[row-1][2])*(tractiveEffortArray[row][3]-tractiveEffortArray[row-1][3])/(tractiveEffortArray[row][1]-tractiveEffortArray[row-1][2])+tractiveEffortArray[row-1][3] return F_T_interpolation
return F_T_interpolation
else
return tractiveEffortArray[1][3]
end #if
end #if end #if
end #for end #for
# if v gets higher than the velocities in tractiveEffortArray the last tractive effort will be used # if v gets higher than the velocities in tractiveEffortVelocityPairs the last tractive effort will be used
# TODO: also an extrapolation could be used # TODO: also an extrapolation could be used
return tractiveEffortArray[end][3] return tractiveEffortVelocityPairs[end][2]
end #function calculateTractiveEffort end #function calculateTractiveEffort
#= old 2021-11-04: now with easier tractiveEffortVelocityPairs than previous tractiveEffortArray
function calculateTractiveEffort(v::AbstractFloat, tractiveEffortArray)
for row in 1:length(tractiveEffortArray)
if tractiveEffortArray[row][1]<=v && v<=tractiveEffortArray[row][2]
return tractiveEffortArray[row][3]
elseif tractiveEffortArray[row][1]>v
if row>1
# interpolate for a straight line between the two surrounding points with the formula: F=(v-v_(row-1))*(F_row-_(row-1))/(v_row-v_(row-1))+F_(row-1)
F_T_interpolation=(v-tractiveEffortArray[row-1][2])*(tractiveEffortArray[row][3]-tractiveEffortArray[row-1][3])/(tractiveEffortArray[row][1]-tractiveEffortArray[row-1][2])+tractiveEffortArray[row-1][3]
return F_T_interpolation
else
return tractiveEffortArray[1][3]
end #if
end #if
end #for
# if v gets higher than the velocities in tractiveEffortArray the last tractive effort will be used
# TODO: also an extrapolation could be used
return tractiveEffortArray[end][3]
end #function calculateTractiveEffort
=#
#TODO: choose an explanation and replace the ? ? ? #TODO: choose an explanation and replace the ? ? ?
""" """
@ -125,12 +141,14 @@ function calculateForces!(dataPoint::DataPoint, train::Train, massModel::String,
dataPoint.F_Rp=calculatePathResistance(dataPoint.s, massModel, train, allCs) dataPoint.F_Rp=calculatePathResistance(dataPoint.s, massModel, train, allCs)
dataPoint.F_R=dataPoint.F_Runion+dataPoint.F_Rp dataPoint.F_R=dataPoint.F_Runion+dataPoint.F_Rp
#calculate tractive effort # calculate tractive effort
if bsType == "acceleration" if bsType == "acceleration" || bsType == "diminishing"
dataPoint.F_T = calculateTractiveEffort(dataPoint.v, train.tractiveEffortArray) # 12/03 test: if bsType == "acceleration" || bsType == "diminishing" || bsType == "maximumTraction"
# 11/21 old without diminishing: if bsType == "acceleration"
dataPoint.F_T = calculateTractiveEffort(dataPoint.v, train.tractiveEffortVelocityPairs)
# println(" F_T:",dataPoint.F_T )
elseif bsType == "cruising" elseif bsType == "cruising"
# 09/22 println("s=",dataPoint.s, " v=",dataPoint.v, " F_R=",dataPoint.F_R, " F_T=",calculateTractiveEffort(dataPoint.v, train.tractiveEffortArray)) dataPoint.F_T = min(max(0.0, dataPoint.F_R), calculateTractiveEffort(dataPoint.v, train.tractiveEffortVelocityPairs))
dataPoint.F_T = min(max(0.0, dataPoint.F_R), calculateTractiveEffort(dataPoint.v, train.tractiveEffortArray))
else else
dataPoint.F_T = 0.0 dataPoint.F_T = 0.0
end end
@ -144,6 +162,7 @@ TODO
function moveAStep(previousPoint::DataPoint, stepVariable::String, stepSize::AbstractFloat, csId::Integer) function moveAStep(previousPoint::DataPoint, stepVariable::String, stepSize::AbstractFloat, csId::Integer)
# stepSize is the currentStepSize depending on the accessing function # stepSize is the currentStepSize depending on the accessing function
# TODO: csId is only for error messages. Should it be removed? # TODO: csId is only for error messages. Should it be removed?
#= 08/31 TODO: How to check if the train stopps during this step? I should throw an error myself that I catch in higher hierarchies. =#
# creating the next data point # creating the next data point
newPoint=DataPoint() newPoint=DataPoint()
@ -156,14 +175,15 @@ function moveAStep(previousPoint::DataPoint, stepVariable::String, stepSize::Abs
newPoint.Δv=0.0 # step size (in m/s) newPoint.Δv=0.0 # step size (in m/s)
elseif stepVariable=="s in m" # distance step method elseif stepVariable=="s in m" # distance step method
newPoint.Δs=stepSize # step size (in m) newPoint.Δs=stepSize # step size (in m)
# TODO: is this if correct and necessary? # 11/21 |->
#if ((previousPoint.v/previousPoint.a)^2+2*newPoint.Δs/previousPoint.a)<0.0 || (previousPoint.v^2+2*newPoint.Δs*previousPoint.a)<0.0 # checking if the parts of the following square roots will be <0.0 if previousPoint.a<0.0
# error("ERROR: The train stops during the acceleration phase in CS",csId," because the tractive effort is lower than the resistant forces.", if ((previousPoint.v/previousPoint.a)^2+2*newPoint.Δs/previousPoint.a)<0.0 || (previousPoint.v^2+2*newPoint.Δs*previousPoint.a)<0.0 # checking if the parts of the following square roots will be <0.0
# " Before the stop the last point has the values s=",previousPoint.s," m, v=",previousPoint.v," m/s, a=",previousPoint.a," m/s^2,", error("ERROR: The train stops during the acceleration phase in CS",csId," because the tractive effort is lower than the resistant forces.",
# " F_T=",previousPoint.F_T," N, F_Rt=",previousPoint.F_Rt," N, F_Rw=",previousPoint.F_Rw," N, F_Rp=",previousPoint.F_Rp," N.") " Before the stop the last point has the values s=",previousPoint.s," m, v=",previousPoint.v," m/s, a=",previousPoint.a," m/s^2,",
#end " F_T=",previousPoint.F_T," N, F_Rt=",previousPoint.F_Rt," N, F_Rw=",previousPoint.F_Rw," N, F_Rp=",previousPoint.F_Rp," N.")
#= 08/31 TODO: How to check if the train stopps during this step? I should throw an error myself that I catch in higher hierarchies. end
=# end
# 11/21 ->|
newPoint.Δt=sign(previousPoint.a)*sqrt((previousPoint.v/previousPoint.a)^2+2*newPoint.Δs/previousPoint.a)-previousPoint.v/previousPoint.a # step size (in s) newPoint.Δt=sign(previousPoint.a)*sqrt((previousPoint.v/previousPoint.a)^2+2*newPoint.Δs/previousPoint.a)-previousPoint.v/previousPoint.a # step size (in s)
newPoint.Δv=sqrt(previousPoint.v^2+2*newPoint.Δs*previousPoint.a)-previousPoint.v # step size (in m/s) newPoint.Δv=sqrt(previousPoint.v^2+2*newPoint.Δs*previousPoint.a)-previousPoint.v # step size (in m/s)
elseif stepVariable=="t in s" # time step method elseif stepVariable=="t in s" # time step method
@ -179,17 +199,12 @@ function moveAStep(previousPoint::DataPoint, stepVariable::String, stepSize::Abs
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)
# 08/23 the following will be checked later
#if newPoint.v<=0.0
# error("ERROR: The train stops during the acceleration phase in CS",csId," m because the tractive effort is lower than the resistant forces.",
# " Before the stop the last point has the values s=",previousPoint.s," v=",previousPoint.v," m/s a=",previousPoint.a," m/s^2",
# " F_T=",previousPoint.F_T," N F_Rt=",previousPoint.F_Rt," N F_Rw=",previousPoint.F_Rw," N F_Rp=",previousPoint.F_Rp," N.")
#end
newPoint.ΔW_T=previousPoint.F_T*newPoint.Δs # mechanical work in this step (in Ws) newPoint.ΔW_T=previousPoint.F_T*newPoint.Δs # mechanical work in this step (in Ws)
newPoint.W_T=previousPoint.W_T+newPoint.ΔW_T # mechanical work (in Ws) newPoint.W_T=previousPoint.W_T+newPoint.ΔW_T # mechanical work (in Ws)
newPoint.ΔE=newPoint.ΔW_T # energy consumption in this step (in Ws) newPoint.ΔE=newPoint.ΔW_T # energy consumption in this step (in Ws)
newPoint.E=previousPoint.E+newPoint.ΔE # energy consumption (in Ws) newPoint.E=previousPoint.E+newPoint.ΔE # energy consumption (in Ws)
return newPoint return newPoint
end #function moveAStep end #function moveAStep
@ -343,11 +358,23 @@ function addAccelerationPhase!(characteristicSection::CharacteristicSection, dri
(characteristicSection, drivingCourse)=addStartingPhase!(characteristicSection, drivingCourse, settings, train, allCs) (characteristicSection, drivingCourse)=addStartingPhase!(characteristicSection, drivingCourse, settings, train, allCs)
end #if end #if
calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "acceleration")
if drivingCourse[end].F_T < drivingCourse[end].F_R
(characteristicSection, drivingCourse)=addDiminishingPhase!(characteristicSection, drivingCourse, settings, train, allCs)
drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "acceleration"))
end
# if the tail 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 tail of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept
formerSpeedLimits = detectFormerSpeedLimits(allCs, characteristicSection.id, drivingCourse[end], train.l_union) formerSpeedLimits = detectFormerSpeedLimits(allCs, characteristicSection.id, drivingCourse[end], train.l_union)
if drivingCourse[end].v < characteristicSection.v_reach && drivingCourse[end].s <characteristicSection.s_end # conditions for acceleration phase
# 09/09 new (for steep gradients "<=" is necessary but only in accelertion until breaking due to Operation modes) TODO targetSpeedReached = drivingCourse[end].v >= characteristicSection.v_reach
trainAtEnd = drivingCourse[end].s >= characteristicSection.s_end
tractionSurplus = drivingCourse[end].F_T > drivingCourse[end].F_R
# use the conditions for the acceleration phase
if !targetSpeedReached && !trainAtEnd && tractionSurplus
#11/23 old without F_T > F_R: if drivingCourse[end].v < characteristicSection.v_reach && drivingCourse[end].s <characteristicSection.s_end && drivingCourse[end].F_T > drivingCourse[end].F_R
accelerationSection=BehaviorSection() accelerationSection=BehaviorSection()
accelerationSection.type="acceleration" # type of behavior section accelerationSection.type="acceleration" # type of behavior section
accelerationSection.s_start=drivingCourse[end].s # first position (in m) accelerationSection.s_start=drivingCourse[end].s # first position (in m)
@ -355,28 +382,20 @@ function addAccelerationPhase!(characteristicSection::CharacteristicSection, dri
push!(accelerationSection.dataPoints, drivingCourse[end].i) push!(accelerationSection.dataPoints, drivingCourse[end].i)
currentStepSize=settings.stepSize # initializing the step size that can be reduced near intersections currentStepSize=settings.stepSize # initializing the step size that can be reduced near intersections
#= 08/23 old version for intersection approximation
for cycle in 1:5 # first cycle with normal step size, second cycle with reduced step size, third cycle with more reduced step size and fourth cycle with the last step size calculated till the intersection
# in the fifth cycle the interpolated values are corrected in case v_reach is still to high although s==s_end
=#
for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation
# while characteristicSection.v_reach - drivingCourse[end].v > 0.000001 && drivingCourse[end].s<characteristicSection.s_end && drivingCourse[end].v>0.0 while drivingCourse[end].v<characteristicSection.v_reach && drivingCourse[end].s<characteristicSection.s_end && drivingCourse[end].F_T > drivingCourse[end].F_R
# 12/03 old with v>0.0: while drivingCourse[end].v<characteristicSection.v_reach && drivingCourse[end].s<characteristicSection.s_end && drivingCourse[end].v>0.0 && drivingCourse[end].F_T > drivingCourse[end].F_R
while drivingCourse[end].v<characteristicSection.v_reach && drivingCourse[end].s<characteristicSection.s_end && drivingCourse[end].v>0.0
# 09/09 new (for steep gradients "<=" is necessary but only in accelertion until braking due to Operation modes) TODO
# traction effort and resisting forces (in N) # traction effort and resisting forces (in N)
drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type)) # 11/22 drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type))
# acceleration (in m/s^2): # acceleration (in m/s^2):
drivingCourse[end].a=(drivingCourse[end].F_T-drivingCourse[end].F_R)/train.m_union/train.ξ_union drivingCourse[end].a=(drivingCourse[end].F_T-drivingCourse[end].F_R)/train.m_union/train.ξ_union
# if drivingCourse[end].a==0.0
# error("ERROR: a=0 m/s^2 in the acceleration phase ! with F_T=",drivingCourse[end].F_T," F_Rt=",drivingCourse[end].F_Rt," F_Rw=",drivingCourse[end].F_Rw," F_Rp=",drivingCourse[end].F_Rp)
# end
# create the next data point # create the next data point
push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, characteristicSection.id)) push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, characteristicSection.id))
push!(accelerationSection.dataPoints, drivingCourse[end].i) push!(accelerationSection.dataPoints, drivingCourse[end].i)
# drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type))
if length(formerSpeedLimits) > 0 # If the tail of the train is located in a former characteristic section with lower speed limit check if is is possible to accelerate as normal if length(formerSpeedLimits) > 0 # If the tail of the train is located in a former characteristic section with lower speed limit check if is is possible to accelerate as normal
(characteristicSection, drivingCourse, formerSpeedLimits, accelerationSection, endOfCsReached) = considerFormerSpeedLimits!(characteristicSection, drivingCourse, settings, train, allCs, formerSpeedLimits, accelerationSection) (characteristicSection, drivingCourse, formerSpeedLimits, accelerationSection, endOfCsReached) = considerFormerSpeedLimits!(characteristicSection, drivingCourse, settings, train, allCs, formerSpeedLimits, accelerationSection)
@ -385,6 +404,7 @@ function addAccelerationPhase!(characteristicSection::CharacteristicSection, dri
end #if end #if
currentStepSize=settings.stepSize # initializing the step size that can be reduced near intersections currentStepSize=settings.stepSize # initializing the step size that can be reduced near intersections
end #if end #if
drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type))
end #while end #while
# 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
@ -411,6 +431,8 @@ function addAccelerationPhase!(characteristicSection::CharacteristicSection, dri
elseif drivingCourse[end].v==characteristicSection.v_reach elseif drivingCourse[end].v==characteristicSection.v_reach
break break
elseif drivingCourse[end].F_T <= drivingCourse[end].F_R
currentStepSize = settings.stepSize / 10.0^cycle
else else
error("ERROR at acceleration phase: With the step variable ",settings.stepVariable," the while loop will be left although v<v_reach and s<s_end in CS",characteristicSection.id," with s=" ,drivingCourse[end].s," m and v=",drivingCourse[end].v," m/s") error("ERROR at acceleration phase: With the step variable ",settings.stepVariable," the while loop will be left although v<v_reach and s<s_end in CS",characteristicSection.id," with s=" ,drivingCourse[end].s," m and v=",drivingCourse[end].v," m/s")
@ -432,30 +454,33 @@ function addAccelerationPhase!(characteristicSection::CharacteristicSection, dri
elseif drivingCourse[end].s>characteristicSection.s_end elseif drivingCourse[end].s>characteristicSection.s_end
drivingCourse[end].s=characteristicSection.s_end # rounding s down to s_end drivingCourse[end].s=characteristicSection.s_end # rounding s down to s_end
elseif drivingCourse[end].F_T <= drivingCourse[end].F_R
(characteristicSection, drivingCourse)=addDiminishingPhase!(characteristicSection, drivingCourse, settings, train, allCs)
drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type))
else else
end end
end end
end #for end #for
# if length(accelerationSection.dataPoints) > 1 # 09/09 new: it is possible that the acceleration starts at v_reach, accelerates a step, is to high and drops the last point. then there is only one data point which is not a section. | It should only be used in addAccelerationUntilBreaking! due to Operation Modes TODO if length(accelerationSection.dataPoints) > 1 # 11/21 new: it is possible that the acceleration starts at v_reach, accelerates a step, is to high and drops the last point. then there is only one data point which is not a section.
# calculate the accumulated acceleration section information
accelerationSection.v_exit=drivingCourse[end].v # exit speed (in m/s)
accelerationSection.s_end=drivingCourse[end].s # last position (in m)
accelerationSection.s_total=accelerationSection.s_end-accelerationSection.s_start # total length (in m)
accelerationSection.t_total=drivingCourse[end].t-drivingCourse[accelerationSection.dataPoints[1]].t # total running time (in s)
accelerationSection.E_total=drivingCourse[end].E-drivingCourse[accelerationSection.dataPoints[1]].E # total energy consumption (in Ws)
characteristicSection.t_total=characteristicSection.t_total+accelerationSection.t_total # total running time (in s)
characteristicSection.E_total=characteristicSection.E_total+accelerationSection.E_total # total energy consumption (in Ws)
# calculation the accumulated acceleration section information # TODO: this warning schould not be needed. just for testing
accelerationSection.v_exit=drivingCourse[end].v # exit speed (in m/s) if characteristicSection.v_reach < drivingCourse[end].v
accelerationSection.s_end=drivingCourse[end].s # last position (in m) println("WARNING, v is getting to high at the end of the acceleration phase. v=",drivingCourse[end].v ," > v_reach=",characteristicSection.v_reach)
accelerationSection.s_total=accelerationSection.s_end-accelerationSection.s_start # total length (in m) end
accelerationSection.t_total=drivingCourse[end].t-drivingCourse[accelerationSection.dataPoints[1]].t # total running time (in s)
accelerationSection.E_total=drivingCourse[end].E-drivingCourse[accelerationSection.dataPoints[1]].E # total energy consumption (in Ws)
characteristicSection.t_total=characteristicSection.t_total+accelerationSection.t_total # total running time (in s)
characteristicSection.E_total=characteristicSection.E_total+accelerationSection.E_total # total energy consumption (in Ws)
# TODO: this warning schould not be needed. just for testing merge!(characteristicSection.behaviorSections, Dict("acceleration"=>accelerationSection))
if characteristicSection.v_reach<drivingCourse[end].v
println("WARNING, v is getting to high at the end of the acceleration phase. v=",drivingCourse[end].v ," > v_reach=",characteristicSection.v_reach)
end end
merge!(characteristicSection.behaviorSections, Dict("acceleration"=>accelerationSection))
# end
end # else: just return the given data point number without changes due to the acceleration phase end # else: just return the given data point number without changes due to the acceleration phase
return (characteristicSection, drivingCourse) return (characteristicSection, drivingCourse)
@ -468,48 +493,18 @@ function addAccelerationPhaseUntilBraking!(characteristicSection::Characteristic
(characteristicSection, drivingCourse)=addStartingPhase!(characteristicSection, drivingCourse, settings, train, allCs) (characteristicSection, drivingCourse)=addStartingPhase!(characteristicSection, drivingCourse, settings, train, allCs)
end #if end #if
calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "acceleration")
if drivingCourse[end].F_T < drivingCourse[end].F_R
(characteristicSection, drivingCourse)=addDiminishingPhase!(characteristicSection, drivingCourse, settings, train, allCs)
drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "acceleration"))
end
# if the tail 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 tail of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept
formerSpeedLimits = detectFormerSpeedLimits(allCs, characteristicSection.id, drivingCourse[end], train.l_union) formerSpeedLimits = detectFormerSpeedLimits(allCs, characteristicSection.id, drivingCourse[end], train.l_union)
#(formerSpeedLimits, s_cruisingBeforeAcceleration) = detectFormerSpeedLimits(allCs, characteristicSection.id, drivingCourse[end], train.l_union)
#if s_cruisingBeforeAcceleration > 0.0
# (characteristicSection, drivingCourse)=addCruisingPhase!(characteristicSection, drivingCourse, s_cruisingBeforeAcceleration, settings, train, allCs, "cruisingBeforeAcceleration")
#else
# error("ERROR: cruisingBeforeAcceleration <=0.0 although it has to be >0.0 in CS ",csWithTrainHeadId)
#end
#= 07/30 *** TODO
# if the tail of the train is still in a former characteristic section it has to be checked if its speed limit can be kept
formerSpeedLimits=[]
if characteristicSection.id>1 && drivingCourse[end].s-train.l_union<characteristicSection.s_start
if abs(allCs[characteristicSection.id-1].v_limit-drivingCourse[end].v)<0.000001
s_braking=max(0.0, ceil((characteristicSection.v_exit^2-drivingCourse[end].v^2)/2/train.a_braking, digits=approximationLevel))
s_cruisingBeforeAcceleration=min(characteristicSection.s_end-drivingCourse[end].s-s_braking, train.l_union)
if s_cruisingBeforeAcceleration>0.0 # 11/23 old without F_T>F_R: if drivingCourse[end].v < characteristicSection.v_reach && drivingCourse[end].s<characteristicSection.s_end
(characteristicSection, drivingCourse)=addCruisingPhase!(characteristicSection, drivingCourse, s_cruisingBeforeAcceleration, settings, train, allCs, "cruisingBeforeAcceleration") if drivingCourse[end].v < characteristicSection.v_reach && drivingCourse[end].s<characteristicSection.s_end && drivingCourse[end].F_T > drivingCourse[end].F_R
else
error("ERROR: cruisingBeforeAcceleration <=0.0 although it has to be >0.0 in CS ",characteristicSection.id)
end
else # detecting the lower speed limits of former sections
csId=characteristicSection.id-1
while csId>0 && drivingCourse[end].s-train.l_union<allCs[csId].s_end
if allCs[csId].v_limit<characteristicSection.v_limit # TODO: is the position of trains end < movingSection.s_start, v_limit of the first CS is used
push!(formerSpeedLimits, [allCs[csId].s_end, allCs[csId].v_limit])
for i in 1:length(formerSpeedLimits)-1
if formerSpeedLimits[i][2]<=formerSpeedLimits[end][2]
pop!(formerSpeedLimits)
break
end
end
end
csId=csId-1
end
end
end
=#
# 09/09 old (for steep gradients <= is necessary): if drivingCourse[end].v<characteristicSection.v_reach && drivingCourse[end].s<characteristicSection.s_end
if drivingCourse[end].v <= characteristicSection.v_reach && drivingCourse[end].s<characteristicSection.s_end
accelerationSection=BehaviorSection() accelerationSection=BehaviorSection()
accelerationSection.type="acceleration" # type of behavior section accelerationSection.type="acceleration" # type of behavior section
accelerationSection.s_start=drivingCourse[end].s # first position (in m) accelerationSection.s_start=drivingCourse[end].s # first position (in m)
@ -517,24 +512,23 @@ function addAccelerationPhaseUntilBraking!(characteristicSection::Characteristic
push!(accelerationSection.dataPoints, drivingCourse[end].i) push!(accelerationSection.dataPoints, drivingCourse[end].i)
currentStepSize=settings.stepSize # initializing the step size that can be reduced near intersections currentStepSize=settings.stepSize # initializing the step size that can be reduced near intersections
# 08/23 : old for cycle in 1:5 # first cycle with normal step size, second cycle with reduced step size, third cycle with more reduced step size. fourth and fith are needed in case the velocity approaches 0.0 or v_reach
for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation
s_braking=max(0.0, ceil((characteristicSection.v_exit^2-drivingCourse[end].v^2)/2/train.a_braking, digits=approximationLevel)) s_braking=max(0.0, ceil((characteristicSection.v_exit^2-drivingCourse[end].v^2)/2/train.a_braking, digits=approximationLevel))
while drivingCourse[end].v <= characteristicSection.v_reach && drivingCourse[end].s+s_braking<characteristicSection.s_end && drivingCourse[end].v>0.0 # as long as s_i + s_braking < s_CSend while drivingCourse[end].v < characteristicSection.v_reach && drivingCourse[end].s+s_braking<characteristicSection.s_end && drivingCourse[end].F_T > drivingCourse[end].F_R # as long as s_i + s_braking < s_CSend
# 09/09 old (for steep gradients <= is necessary): while drivingCourse[end].v<characteristicSection.v_reach && drivingCourse[end].s+s_braking<characteristicSection.s_end && drivingCourse[end].v>0.0 # as long as s_i + s_braking < s_CSend # 12/03 old with v>0 while drivingCourse[end].v < characteristicSection.v_reach && drivingCourse[end].s+s_braking<characteristicSection.s_end && drivingCourse[end].v>0.0 && drivingCourse[end].F_T > drivingCourse[end].F_R # as long as s_i + s_braking < s_CSend
#11/22 drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type))
drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type))
# acceleration (in m/s^2): # acceleration (in m/s^2):
drivingCourse[end].a=(drivingCourse[end].F_T-drivingCourse[end].F_R)/train.m_union/train.ξ_union drivingCourse[end].a=(drivingCourse[end].F_T-drivingCourse[end].F_R)/train.m_union/train.ξ_union
if drivingCourse[end].a==0.0 # if drivingCourse[end].a==0.0
error("ERROR: a=0 m/s^2 in the acceleration phase ! with F_T=",drivingCourse[end].F_T," F_Rt=",drivingCourse[end].F_Rt," F_Rw=",drivingCourse[end].F_Rw," F_Rp=",drivingCourse[end].F_Rp) # error("ERROR: a=0 m/s^2 in the acceleration phase ! with F_T=",drivingCourse[end].F_T," F_Rt=",drivingCourse[end].F_Rt," F_Rw=",drivingCourse[end].F_Rw," F_Rp=",drivingCourse[end].F_Rp)
end # end
# create the next data point # create the next data point
push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, characteristicSection.id)) push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, characteristicSection.id))
push!(accelerationSection.dataPoints, drivingCourse[end].i) push!(accelerationSection.dataPoints, drivingCourse[end].i)
# 12/03: was moved behind considerFormerSpeedLimits: drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type))
if length(formerSpeedLimits) > 0 # If the tail of the train is located in a former characteristic section with lower speed limit check if is is possible to accelerate as normal if length(formerSpeedLimits) > 0 # If the tail of the train is located in a former characteristic section with lower speed limit check if is is possible to accelerate as normal
(characteristicSection, drivingCourse, formerSpeedLimits, accelerationSection, endOfCsReached) = considerFormerSpeedLimits!(characteristicSection, drivingCourse, settings, train, allCs, formerSpeedLimits, accelerationSection) (characteristicSection, drivingCourse, formerSpeedLimits, accelerationSection, endOfCsReached) = considerFormerSpeedLimits!(characteristicSection, drivingCourse, settings, train, allCs, formerSpeedLimits, accelerationSection)
@ -542,7 +536,7 @@ function addAccelerationPhaseUntilBraking!(characteristicSection::Characteristic
return (characteristicSection, drivingCourse) return (characteristicSection, drivingCourse)
end end
end end
drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type))
s_braking=max(0.0, ceil((characteristicSection.v_exit^2-drivingCourse[end].v^2)/2/train.a_braking, digits=approximationLevel)) s_braking=max(0.0, ceil((characteristicSection.v_exit^2-drivingCourse[end].v^2)/2/train.a_braking, digits=approximationLevel))
end #while end #while
@ -567,6 +561,9 @@ function addAccelerationPhaseUntilBraking!(characteristicSection::Characteristic
elseif drivingCourse[end].v==characteristicSection.v_reach elseif drivingCourse[end].v==characteristicSection.v_reach
break break
elseif drivingCourse[end].F_T <= drivingCourse[end].F_R
currentStepSize = settings.stepSize / 10.0^cycle
else else
error("ERROR at acceleration until braking phase: With the step variable ",settings.stepVariable," the while loop will be left although v<v_reach and s<s_end in CS",characteristicSection.id," with s=" ,drivingCourse[end].s," m and v=",drivingCourse[end].v," m/s") error("ERROR at acceleration until braking phase: With the step variable ",settings.stepVariable," the while loop will be left although v<v_reach and s<s_end in CS",characteristicSection.id," with s=" ,drivingCourse[end].s," m and v=",drivingCourse[end].v," m/s")
end end
@ -587,6 +584,11 @@ function addAccelerationPhaseUntilBraking!(characteristicSection::Characteristic
elseif drivingCourse[end].s + s_braking > characteristicSection.s_end elseif drivingCourse[end].s + s_braking > characteristicSection.s_end
pop!(drivingCourse) pop!(drivingCourse)
pop!(accelerationSection.dataPoints) pop!(accelerationSection.dataPoints)
elseif drivingCourse[end].F_T <= drivingCourse[end].F_R
(characteristicSection, drivingCourse)=addDiminishingPhase!(characteristicSection, drivingCourse, settings, train, allCs)
drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type))
else else
end end
@ -594,7 +596,7 @@ function addAccelerationPhaseUntilBraking!(characteristicSection::Characteristic
end #for end #for
if length(accelerationSection.dataPoints) > 1 # 09/09 new: it is possible that the acceleration starts at v_reach, accelerates a step, is to high and drops the last point. then there is only one data point which is not a section. if length(accelerationSection.dataPoints) > 1 # 09/09 new: it is possible that the acceleration starts at v_reach, accelerates a step, is to high and drops the last point. then there is only one data point which is not a section.
# calculation the accumulated acceleration section information # calculate the accumulated acceleration section information
accelerationSection.v_exit=drivingCourse[end].v # exit speed (in m/s) accelerationSection.v_exit=drivingCourse[end].v # exit speed (in m/s)
accelerationSection.s_end=drivingCourse[end].s # last position (in m) accelerationSection.s_end=drivingCourse[end].s # last position (in m)
accelerationSection.s_total=accelerationSection.s_end-accelerationSection.s_start # total length (in m) accelerationSection.s_total=accelerationSection.s_end-accelerationSection.s_start # total length (in m)
@ -615,11 +617,20 @@ end #function addAccelerationPhaseUntilBraking!
## This function calculates the data points of the cruising phase. ## This function calculates the data points of the cruising phase.
# Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for cruising if needed. # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for cruising if needed.
function addCruisingPhase!(characteristicSection::CharacteristicSection, drivingCourse::Vector{DataPoint}, s_cruising::AbstractFloat, settings::Settings, train::Train, allCs::Vector{CharacteristicSection}, cruisingType::String) function addCruisingPhase!(characteristicSection::CharacteristicSection, drivingCourse::Vector{DataPoint}, s_cruising::AbstractFloat, settings::Settings, train::Train, allCs::Vector{CharacteristicSection}, cruisingType::String)
if drivingCourse[end].v>0.0 && drivingCourse[end].v<=characteristicSection.v_reach && drivingCourse[end].s<characteristicSection.s_end # traction effort and resisting forces (in N)
calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "cruising") # TODO: or give cruisingSection.type instead of "cruising"?
if drivingCourse[end].F_T < drivingCourse[end].F_R
(characteristicSection, drivingCourse)=addDiminishingPhase!(characteristicSection, drivingCourse, settings, train, allCs)
drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "cruising"))
s_cruising=max(0.0, s_cruising-get(characteristicSection.behaviorSections, "diminishing", BehaviorSection()).s_total)
end
if drivingCourse[end].v>0.0 && drivingCourse[end].v<=characteristicSection.v_reach && drivingCourse[end].s<characteristicSection.s_end && drivingCourse[end].F_T >= drivingCourse[end].F_R
# 11/22 old: if drivingCourse[end].v>0.0 && drivingCourse[end].v<=characteristicSection.v_reach && drivingCourse[end].s<characteristicSection.s_end
cruisingSection=BehaviorSection() cruisingSection=BehaviorSection()
cruisingSection.type=cruisingType # type of behavior section cruisingSection.type=cruisingType # type of behavior section
cruisingSection.s_start=drivingCourse[end].s # first position (in m) cruisingSection.s_start=drivingCourse[end].s # first position (in m)
cruisingSection.s_end=min(drivingCourse[end].s+s_cruising, characteristicSection.s_end) # last position (in m) # 11/22: now it is at the end of the BS: cruisingSection.s_end=min(drivingCourse[end].s+s_cruising, characteristicSection.s_end) # last position (in m)
cruisingSection.v_entry=drivingCourse[end].v # entry speed (in m/s) cruisingSection.v_entry=drivingCourse[end].v # entry speed (in m/s)
push!(cruisingSection.dataPoints, drivingCourse[end].i) push!(cruisingSection.dataPoints, drivingCourse[end].i)
@ -627,241 +638,113 @@ function addCruisingPhase!(characteristicSection::CharacteristicSection, driving
s_cruising=min(s_cruising, characteristicSection.s_end-cruisingSection.s_start) s_cruising=min(s_cruising, characteristicSection.s_end-cruisingSection.s_start)
# traction effort and resisting forces (in N) # traction effort and resisting forces (in N)
drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "cruising")) # TODO: or give cruisingSection.type instead of "cruising"? calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "cruising") # TODO: or give cruisingSection.type instead of "cruising"?
# 11/05 old: drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "cruising")) # TODO: or give cruisingSection.type instead of "cruising"?
currentStepSize=settings.stepSize if settings.massModel=="homogeneous strip" && characteristicSection.id > 1
for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation currentStepSize=settings.stepSize
while drivingCourse[end].s<cruisingSection.s_start+s_cruising && (drivingCourse[end].F_T < drivingCourse[end].F_R || (settings.massModel=="homogeneous strip" && characteristicSection.id > 1 && drivingCourse[end].s < allCs[characteristicSection.id].s_start + train.l_union)) && drivingCourse[end].v>0.0 #&& drivingCourse[end].v<=characteristicSection.v_reach && drivingCourse[end].s<characteristicSection.s_end for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation
#TODO: maybe just consider former CS with different path resistance? while drivingCourse[end].s < characteristicSection.s_start + train.l_union && drivingCourse[end].s<cruisingSection.s_start+s_cruising && drivingCourse[end].F_T>=drivingCourse[end].F_R #&& drivingCourse[end].v<=characteristicSection.v_reach && drivingCourse[end].s<characteristicSection.s_end
#TODO: what about the case: After leaving a former CS with steep gradient the train can accelerate. Now in this tool the train will cruise at v_i. Just accelerating until v_reach could make problems for energy saving by shortening the acceleration phase # TODO: whithout allCs should work as well, no? while drivingCourse[end].s < allCs[characteristicSection.id].s_start + train.l_union && drivingCourse[end].s<cruisingSection.s_start+s_cruising && drivingCourse[end].F_T>=drivingCourse[end].F_R #&& drivingCourse[end].v<=characteristicSection.v_reach && drivingCourse[end].s<characteristicSection.s_end
# the tractive effort is lower than the resisiting forces and the train has use the highest possible effort to try to stay at v_reach OR the mass model homogeneous strip is used and parts of the train are still in former CS # the tractive effort is lower than the resisiting forces and the train has use the highest possible effort to try to stay at v_reach OR the mass model homogeneous strip is used and parts of the train are still in former CS
#TODO: maybe just consider former CS with different path resistance?
#TODO: what about the case: After leaving a former CS with steep gradient the train can accelerate. Now in this tool the train will cruise at v_i. Just accelerating until v_reach could make problems for energy saving by shortening the acceleration phase
#09/22: neu ist der Teil beim if. alt ist der Teil beim else TODO
if drivingCourse[end].F_T >= drivingCourse[end].F_R
# acceleration (in m/s^2): # acceleration (in m/s^2):
drivingCourse[end].a=0.0 drivingCourse[end].a=0.0
# create the next data point # create the next data point
push!(drivingCourse, moveAStep(drivingCourse[end], "s_cruising in m", train.l_union/(10.0^cycle), characteristicSection.id)) # TODO welche Schrittweite nehm ich hier? if settings.stepVariable=="s in m"
push!(cruisingSection.dataPoints, drivingCourse[end].i) push!(drivingCourse, moveAStep(drivingCourse[end], "s_cruising in m", currentStepSize, characteristicSection.id))
else
# acceleration (in m/s^2):
drivingCourse[end].a=(drivingCourse[end].F_T-drivingCourse[end].F_R)/train.m_union/train.ξ_union
# create the next data point
push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, characteristicSection.id))
push!(cruisingSection.dataPoints, drivingCourse[end].i)
end
# traction effort and resisting forces (in N)
drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "cruising"))
end #while
# check which limit was reached and adjust the currentStepSize for the next cycle
if cycle < approximationLevel+1
if drivingCourse[end].v<=0.0
currentStepSize = settings.stepSize / 10.0^cycle
elseif drivingCourse[end].s>cruisingSection.s_start+s_cruising # TODO also the following? drivingCourse[end].s > allCs[characteristicSection.id].s_start + train.l_union))
if settings.stepVariable == "s in m"
currentStepSize=cruisingSection.s_start+s_cruising-drivingCourse[end-1].s
else else
currentStepSize = settings.stepSize / 10.0^cycle push!(drivingCourse, moveAStep(drivingCourse[end], "s_cruising in m", train.l_union/(10.0^cycle), characteristicSection.id)) # TODO which step size should be used?
end end
#elseif drivingCourse[end].s>characteristicSection.s_end #TODO: is this necesaary if s_cruising is known? # now s_cruising will be limited to the end of CS at the beginning of this function
# if settings.stepVariable == "s in m"
# currentStepSize=characteristicSection.s_end-drivingCourse[end-1].s
# else
# currentStepSize = settings.stepSize / 10.0^cycle
# end
#elseif drivingCourse[end].v>characteristicSection.v_reach # copied from addAccelerationPhase. TODO is it necessary for homogeneous strip? #TODO: now, the train can't get faster in the cruising section. so v_reach can not be exceeded
# if settings.stepVariable=="v in m/s"
# currentStepSize=characteristicSection.v_reach-drivingCourse[end-1].v
# else
# currentStepSize = settings.stepSize / 10.0^cycle
# end
elseif drivingCourse[end].s==cruisingSection.s_start+s_cruising # || drivingCourse[end].s==characteristicSection.s_end
break
#elseif drivingCourse[end].v==characteristicSection.v_reach # copied from addAccelerationPhase. TODO 08/24 should it be used otherwise for homogeneous strip?
# break
elseif drivingCourse[end].F_T>=drivingCourse[end].F_R # TODO should not be necessary: && (settings.massModel=="mass point" || characteristicSection.id == 1 || drivingCourse[end].s >= allCs[characteristicSection.id].s_start+train.l_union)
drivingCourse[end].a=0.0 # acceleration (in m/s^2)
# calculate the remaining cruising way
s_cruisingRemaining=cruisingSection.s_start+s_cruising-drivingCourse[end].s
# create the next data point
push!(drivingCourse, moveAStep(drivingCourse[end], "s_cruising in m", s_cruisingRemaining, characteristicSection.id))
push!(cruisingSection.dataPoints, drivingCourse[end].i) push!(cruisingSection.dataPoints, drivingCourse[end].i)
break # for testing
if drivingCourse[end].F_T > drivingCourse[end].F_R && drivingCourse[end].F_R > 0.0
else # TODO copied from addAccelerationPhase -> probably not needed here !? error("In the cruising phase of CS",cruisingSection.id,": F_T=",drivingCourse[end].F_T," != F_R=",drivingCourse[end].F_R)
error("ERROR at cruising phase: With the step variable ",settings.stepVariable," the while loop will be left although the if cases don't apply in CS",characteristicSection.id," with s=" ,drivingCourse[end].s," m and v=",drivingCourse[end].v," m/s")
end
# delete last data point for recalculating the last step with reduced step size
pop!(drivingCourse)
pop!(cruisingSection.dataPoints)
else # if the level of approximation is reached
if drivingCourse[end].v<=0.0 # copied from addAccelerationPhase TODO: change error message?
error("ERROR: The train stops during the cruising phase in CS",characteristicSection.id," because the tractive effort is lower than the resistant forces.",
" Before the stop the last point has the values s=",drivingCourse[end-1].s," m v=",drivingCourse[end-1].v," m/s a=",drivingCourse[end-1].a," m/s^2",
" F_T=",drivingCourse[end-1].F_T," N F_Rt=",drivingCourse[end-1].F_Rt," N F_Rw=",drivingCourse[end-1].F_Rw," N F_Rp=",drivingCourse[end-1].F_Rp," N.")
#elseif drivingCourse[end].v > characteristicSection.v_reach # copied from addAccelerationPhase. TODO is it necessary for homogeneous strip?
# pop!(drivingCourse)
# pop!(cruisingSection.dataPoints)
#elseif drivingCourse[end].s>characteristicSection.s_end
# drivingCourse[end].s=characteristicSection.s_end # round s down to s_end
elseif drivingCourse[end].s>cruisingSection.s_start+s_cruising
if cruisingSection.type == "cruisingBeforeAcceleration"
else
pop!(drivingCourse)
pop!(cruisingSection.dataPoints)
end end
elseif drivingCourse[end].F_T>=drivingCourse[end].F_R # TODO should not be necessary: && (settings.massModel=="mass point" || characteristicSection.id == 1 || drivingCourse[end].s >= allCs[characteristicSection.id].s_start + train.l_union)
# it is calculated the same as for the other cycles
drivingCourse[end].a=0.0 # acceleration (in m/s^2)
# calculate the remaining cruising way
s_cruisingRemaining=cruisingSection.s_start+s_cruising-drivingCourse[end].s
# create the next data point
push!(drivingCourse, moveAStep(drivingCourse[end], "s_cruising in m", s_cruisingRemaining, characteristicSection.id))
push!(cruisingSection.dataPoints, drivingCourse[end].i)
break
else
end
end
end #for
#= 09/21 old. homogenous strip has to be added
if drivingCourse[end].F_T>=drivingCourse[end].F_R
drivingCourse[end].a=0.0 # acceleration (in m/s^2)
push!(drivingCourse, DataPoint())
drivingCourse[end].i=drivingCourse[end-1].i+1 # incrementing the number of the data point
push!(cruisingSection.dataPoints, drivingCourse[end].i)
# calculate s, t, v, E
drivingCourse[end].Δs=min(s_cruising, characteristicSection.s_end-drivingCourse[end-1].s) # step size (in m)
drivingCourse[end].Δt=drivingCourse[end].Δs/drivingCourse[end-1].v # step size (in s)
drivingCourse[end].Δv=0.0 # step size (in m/s)
# TODO moveAStep can not be used at the moment because of 1/a in the formulars. It has to be changed and then used with stepVariable="s in m", stepSize=min(s_cruising, characteristicSection.s_end-drivingCourse[end-1].s) -> see the three lines above
drivingCourse[end].s=drivingCourse[end-1].s+drivingCourse[end].Δs # position (in m)
drivingCourse[end].t=drivingCourse[end-1].t+drivingCourse[end].Δt # point in time (in s)
drivingCourse[end].v=drivingCourse[end-1].v # velocity (in m/s)
drivingCourse[end].ΔW_T=drivingCourse[end-1].F_T*drivingCourse[end].Δs # mechanical work in this step (in Ws)
drivingCourse[end].W_T=drivingCourse[end-1].W_T+drivingCourse[end].ΔW_T # mechanical work (in Ws)
drivingCourse[end].ΔE=drivingCourse[end].ΔW_T # energy consumption in this step (in Ws)
drivingCourse[end].E=drivingCourse[end-1].E+drivingCourse[end].ΔE # energy consumption (in Ws)
else # the tractive effort is lower than the resisiting forces and the train has use the highest possible effort to try to stay at v_reach
currentStepSize=settings.stepSize
for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation
while drivingCourse[end].v<=characteristicSection.v_reach && drivingCourse[end].s<characteristicSection.s_end && drivingCourse[end].v>0.0 # TODO: <= v_reach was inserted -> probably needed for homogeneous strip
# traction effort and resisting forces (in N) # traction effort and resisting forces (in N)
drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "cruising")) calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "cruising")
# acceleration (in m/s^2):
drivingCourse[end].a=(drivingCourse[end].F_T-drivingCourse[end].F_R)/train.m_union/train.ξ_union
if drivingCourse[end].a==0.0
# TODO: this part is important for mass strip
end
# create the next data point
push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, characteristicSection.id))
push!(cruisingSection.dataPoints, drivingCourse[end].i)
#= TODO: the following has probably to be considered with homogeneous strip:
if length(formerSpeedLimits) > 0 # If the tail of the train is located in a former characteristic section with lower speed limit check if is is possible to accelerate as normal
(characteristicSection, drivingCourse, formerSpeedLimits, cruisingSection, endOfCsReached) = considerFormerSpeedLimits!(characteristicSection, drivingCourse, settings, train, allCs, formerSpeedLimits, accelerationSection)
if endOfCsReached
return (characteristicSection, drivingCourse)
end #if
end #if
=#
end #while end #while
# 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 < approximationLevel+1 if cycle < approximationLevel+1
if drivingCourse[end].v<=0.0 if drivingCourse[end].s>cruisingSection.s_start+s_cruising # TODO also the following? drivingCourse[end].s > allCs[characteristicSection.id].s_start + train.l_union))
currentStepSize = settings.stepSize / 10.0^cycle
elseif drivingCourse[end].s>characteristicSection.s_end
if settings.stepVariable == "s in m" if settings.stepVariable == "s in m"
currentStepSize=characteristicSection.s_end-drivingCourse[end-1].s currentStepSize=cruisingSection.s_start+s_cruising-drivingCourse[end-1].s
else else
currentStepSize = settings.stepSize / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
end end
elseif drivingCourse[end].s==cruisingSection.s_start+s_cruising # || drivingCourse[end].s==characteristicSection.s_end
elseif drivingCourse[end].v>characteristicSection.v_reach # copied from addAccelerationPhase. TODO is it necessary for homogeneous strip? break
if settings.stepVariable=="v in m/s" elseif drivingCourse[end].F_T < drivingCourse[end].F_R
currentStepSize=characteristicSection.v_reach-drivingCourse[end-1].v # if settings.stepVariable == "s in m"
else # currentStepSize=cruisingSection.s_start+s_cruising-drivingCourse[end-1].s
currentStepSize = settings.stepSize / 10.0^cycle # else
end currentStepSize = settings.stepSize / 10.0^cycle
# end
elseif drivingCourse[end].s==characteristicSection.s_end elseif drivingCourse[end].s >= characteristicSection.s_start + train.l_union
# TODO: whithout allCs should work as well, no? elseif drivingCourse[end].s >= allCs[characteristicSection.id].s_start + train.l_union
break break
#elseif drivingCourse[end].v==characteristicSection.v_reach # copied from addAccelerationPhase. TODO should it be used otherwise for homogeneous strip?
# break
else # TODO copied from addAccelerationPhase -> probably not needed here !? else # TODO copied from addAccelerationPhase -> probably not needed here !?
error("ERROR at cruising phase: With the step variable ",settings.stepVariable," the while loop will be left although v<v_reach and s<s_end in CS",characteristicSection.id," with s=" ,drivingCourse[end].s," m and v=",drivingCourse[end].v," m/s") error("ERROR at cruising phase: With the step variable ",settings.stepVariable," the while loop will be left although the if cases don't apply in CS",characteristicSection.id," with s=" ,drivingCourse[end].s," m and v=",drivingCourse[end].v," m/s")
end end
# delete last data point for recalculating the last step with reduced step size # delete last data point for recalculating the last step with reduced step size
pop!(drivingCourse) pop!(drivingCourse)
pop!(cruisingSection.dataPoints) pop!(cruisingSection.dataPoints)
else # if the level of approximation is reached else # if the level of approximation is reached
if drivingCourse[end].v<=0.0 # copied from addAccelerationPhase TODO: change error message? if drivingCourse[end].s>cruisingSection.s_start+s_cruising
error("ERROR: The train stops during the crusing phase in CS",characteristicSection.id," because the tractive effort is lower than the resistant forces.", if cruisingSection.type == "cruisingBeforeAcceleration"
" Before the stop the last point has the values s=",drivingCourse[end-1].s," m v=",drivingCourse[end-1].v," m/s a=",drivingCourse[end-1].a," m/s^2", else
" F_T=",drivingCourse[end-1].F_T," N F_Rt=",drivingCourse[end-1].F_Rt," N F_Rw=",drivingCourse[end-1].F_Rw," N F_Rp=",drivingCourse[end-1].F_Rp," N.") pop!(drivingCourse)
elseif drivingCourse[end].v > characteristicSection.v_reach # copied from addAccelerationPhase. TODO is it necessary for homogeneous strip? pop!(cruisingSection.dataPoints)
pop!(drivingCourse) end
pop!(cruisingSection.dataPoints) # 11/21 |->
elseif drivingCourse[end].s>characteristicSection.s_end elseif drivingCourse[end].s==cruisingSection.s_start+s_cruising
drivingCourse[end].s=characteristicSection.s_end # round s down to s_end break
# 11/21 ->|
elseif drivingCourse[end].F_T < drivingCourse[end].F_R
(characteristicSection, drivingCourse)=addDiminishingPhase!(characteristicSection, drivingCourse, settings, train, allCs)
drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "cruising"))
# s_cruising=max(0.0, s_cruising-get(characteristicSection.behaviorSections, "diminishing", BehaviorSection()).s_total)
else else
end end
end end
end #for end #for
end end #if
=#
# TODO oder soll das lieber nach oben in den else des letzten Durchlaufs. Noch mal genauer ansehen, ob hier was doppelt gemoppelt ist
# if drivingCourse[end].s<cruisingSection.s_start+s_cruising
if drivingCourse[end].s<cruisingSection.s_start+s_cruising && drivingCourse[end].F_T >= drivingCourse[end].F_R
drivingCourse[end].a=0.0 # acceleration (in m/s^2)
# calculate the remaining cruising way
s_cruisingRemaining=cruisingSection.s_start+s_cruising-drivingCourse[end].s
# create the next data point
push!(drivingCourse, moveAStep(drivingCourse[end], "s_cruising in m", s_cruisingRemaining, characteristicSection.id))
push!(cruisingSection.dataPoints, drivingCourse[end].i)
end
# 08/24 old push!(cruisingSection.dataPoints, drivingCourse[end].i)
## new 09/06 TODO: if no acceleration is following the cruising it could be called cruising ## new 09/06 TODO: if no acceleration is following the cruising it could be called cruising
#if cruisingSection.type == "cruisingBeforeAcceleration" && drivingCourse[end].s == characteristicSection.s_end #if cruisingSection.type == "cruisingBeforeAcceleration" && drivingCourse[end].s == characteristicSection.s_end
# cruisingSection.type = "cruising" # cruisingSection.type = "cruising"
#end #end
# calculation the accumulated cruising section information # calculate the accumulated cruising section information
cruisingSection.v_exit=drivingCourse[end].v # exit speed (in m/s) cruisingSection.v_exit=drivingCourse[end].v # exit speed (in m/s)
cruisingSection.s_total=cruisingSection.s_end-cruisingSection.s_start # total length (in m) cruisingSection.s_end=drivingCourse[end].s # last position (in m)
cruisingSection.s_total=cruisingSection.s_end-cruisingSection.s_start # total length (in m)
cruisingSection.t_total=drivingCourse[end].t-drivingCourse[cruisingSection.dataPoints[1]].t # total running time (in s) cruisingSection.t_total=drivingCourse[end].t-drivingCourse[cruisingSection.dataPoints[1]].t # total running time (in s)
cruisingSection.E_total=drivingCourse[end].E-drivingCourse[cruisingSection.dataPoints[1]].E # total energy consumption (in Ws) cruisingSection.E_total=drivingCourse[end].E-drivingCourse[cruisingSection.dataPoints[1]].E # total energy consumption (in Ws)
@ -976,7 +859,7 @@ function addCoastingPhaseUntilBraking!(characteristicSection::CharacteristicSect
end end
end #for end #for
# calculation the accumulated coasting section information # calculate the accumulated coasting section information
coastingSection.v_exit=drivingCourse[end].v # exit speed (in m/s) coastingSection.v_exit=drivingCourse[end].v # exit speed (in m/s)
coastingSection.s_end=drivingCourse[end].s # last position (in m) coastingSection.s_end=drivingCourse[end].s # last position (in m)
coastingSection.s_total=coastingSection.s_end-coastingSection.s_start # total length (in m) coastingSection.s_total=coastingSection.s_end-coastingSection.s_start # total length (in m)
@ -1062,9 +945,7 @@ function addBrakingPhaseStepwise!(characteristicSection::CharacteristicSection,
currentStepSize=settings.stepSize # initializing the step size that can be reduced near intersections currentStepSize=settings.stepSize # initializing the step size that can be reduced near intersections
velocityIsPositive=true velocityIsPositive=true
# println("Bremsphase")
while drivingCourse[end].v>characteristicSection.v_exit && drivingCourse[end].s < characteristicSection.s_end && velocityIsPositive while drivingCourse[end].v>characteristicSection.v_exit && drivingCourse[end].s < characteristicSection.s_end && velocityIsPositive
# println(" while-Durchlauf mit v=",drivingCourse[end].v," und v_exit=",characteristicSection.v_exit)
# traction effort and resisting forces (in N): # traction effort and resisting forces (in N):
drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, brakingSection.type)) drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, brakingSection.type))
@ -1096,7 +977,7 @@ function addBrakingPhaseStepwise!(characteristicSection::CharacteristicSection,
#drivingCourse[end-1].a=round((drivingCourse[end].v^2-drivingCourse[end-1].v^2)/2/drivingCourse[end].Δs, digits=approximationLevel) # acceleration (in m/s^2) (rounding because it should not be less than a_braking) #drivingCourse[end-1].a=round((drivingCourse[end].v^2-drivingCourse[end-1].v^2)/2/drivingCourse[end].Δs, digits=approximationLevel) # acceleration (in m/s^2) (rounding because it should not be less than a_braking)
drivingCourse[end-1].a=(drivingCourse[end].v^2-drivingCourse[end-1].v^2)/2/drivingCourse[end].Δs # acceleration (in m/s^2) drivingCourse[end-1].a=(drivingCourse[end].v^2-drivingCourse[end-1].v^2)/2/drivingCourse[end].Δs # acceleration (in m/s^2)
println("a_braking_last=",drivingCourse[end-1].a," m/s^2 und a_braking_standard=" , train.a_braking) # println("a_braking_last=",drivingCourse[end-1].a," m/s^2 und a_braking_standard=" , train.a_braking)
# if drivingCourse[end-1].a<train.a_braking || drivingCourse[end-1].a>=0.0 # if drivingCourse[end-1].a<train.a_braking || drivingCourse[end-1].a>=0.0
# println("Warning: a_braking gets to high in CS ",characteristicSection.id, " with a=",drivingCourse[end-1].a ," > ",train.a_braking) # println("Warning: a_braking gets to high in CS ",characteristicSection.id, " with a=",drivingCourse[end-1].a ," > ",train.a_braking)
@ -1114,7 +995,7 @@ function addBrakingPhaseStepwise!(characteristicSection::CharacteristicSection,
end end
# calculation the accumulated coasting section information # calculate the accumulated coasting section information
brakingSection.v_exit=drivingCourse[end].v # exit speed (in m/s) brakingSection.v_exit=drivingCourse[end].v # exit speed (in m/s)
brakingSection.s_end=drivingCourse[end].s # last position (in m) brakingSection.s_end=drivingCourse[end].s # last position (in m)
brakingSection.s_total=brakingSection.s_end-brakingSection.s_start # total length (in m) brakingSection.s_total=brakingSection.s_end-brakingSection.s_start # total length (in m)
@ -1130,4 +1011,99 @@ function addBrakingPhaseStepwise!(characteristicSection::CharacteristicSection,
end #function addBrakingPhaseStepwise! end #function addBrakingPhaseStepwise!
## This function calculates the data points for diminishing run when using maximum tractive effort and still getting slower
function addDiminishingPhase!(characteristicSection::CharacteristicSection, drivingCourse::Vector{DataPoint}, settings::Settings, train::Train, allCs::Vector{CharacteristicSection})
drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "diminishing"))
if drivingCourse[end].F_T <= drivingCourse[end].F_R && drivingCourse[end].v > 0.0 && drivingCourse[end].s<characteristicSection.s_end
#drivingCourse[end].v>0.0 && drivingCourse[end].v<=characteristicSection.v_reach && drivingCourse[end].s<characteristicSection.s_end
diminishingSection=BehaviorSection()
diminishingSection.type="diminishing" # type of behavior section
diminishingSection.s_start=drivingCourse[end].s # first position (in m)
diminishingSection.v_entry=drivingCourse[end].v # entry speed (in m/s)
push!(diminishingSection.dataPoints, drivingCourse[end].i)
currentStepSize=settings.stepSize # initializing the step size that can be reduced near intersections
for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation
s_braking=max(0.0, ceil((characteristicSection.v_exit^2-drivingCourse[end].v^2)/2/train.a_braking, digits=approximationLevel))
while drivingCourse[end].F_T <= drivingCourse[end].F_R && drivingCourse[end].s+s_braking<characteristicSection.s_end && drivingCourse[end].v>0.0 # as long as s_i + s_braking < s_CSend
# 11/22 old without F_T<=F_R while drivingCourse[end].s+s_braking<characteristicSection.s_end && drivingCourse[end].v>0.0 # as long as s_i + s_braking < s_CSend
#11/22 drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, diminishingSection.type))
# acceleration (in m/s^2):
drivingCourse[end].a=(drivingCourse[end].F_T-drivingCourse[end].F_R)/train.m_union/train.ξ_union
# 11/21: old, only for cruising:
#if drivingCourse[end].a==0.0
# error("ERROR: a=0 m/s^2 in the diminishing phase ! with F_T=",drivingCourse[end].F_T," F_Rt=",drivingCourse[end].F_Rt," F_Rw=",drivingCourse[end].F_Rw," F_Rp=",drivingCourse[end].F_Rp)
#end
# create the next data point
push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, characteristicSection.id))
push!(diminishingSection.dataPoints, drivingCourse[end].i)
s_braking=max(0.0, ceil((characteristicSection.v_exit^2-drivingCourse[end].v^2)/2/train.a_braking, digits=approximationLevel))
drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, diminishingSection.type))
end #while
# check which limit was reached and adjust the currentStepSize for the next cycle
if cycle < approximationLevel+1
if drivingCourse[end].v<=0.0
currentStepSize = settings.stepSize / 10.0^cycle
elseif drivingCourse[end].s + s_braking > characteristicSection.s_end
currentStepSize = settings.stepSize / 10.0^cycle
elseif drivingCourse[end].s + s_braking==characteristicSection.s_end
# 11/21 old without s_braking: elseif drivingCourse[end].s==characteristicSection.s_end
break
elseif drivingCourse[end].F_T > drivingCourse[end].F_R
currentStepSize = settings.stepSize / 10.0^cycle
else
error("ERROR during diminishing run: With the step variable ",settings.stepVariable," the while loop will be left although s+s_braking<s_end && v>0.0 in CS",characteristicSection.id," with s=" ,drivingCourse[end].s," m and v=",drivingCourse[end].v," m/s")
end
# delete last data point for recalculating the last step with reduced step size
pop!(drivingCourse)
pop!(diminishingSection.dataPoints)
else # if the level of approximation is reached
if drivingCourse[end].v<=0.0
# push!(diminishingSection.dataPoints, drivingCourse[end].i)
error("ERROR: The train stops during diminishing run in CS",characteristicSection.id," because the maximum tractive effort is lower than the resistant forces.",
" Before the stop the last point has the values s=",drivingCourse[end-1].s," m v=",drivingCourse[end-1].v," m/s a=",drivingCourse[end-1].a," m/s^2",
" F_T=",drivingCourse[end-1].F_T," N F_Rt=",drivingCourse[end-1].F_Rt," N F_Rw=",drivingCourse[end-1].F_Rw," N F_Rp=",drivingCourse[end-1].F_Rp," N.")
elseif drivingCourse[end].s + s_braking > characteristicSection.s_end
pop!(drivingCourse)
pop!(diminishingSection.dataPoints)
elseif drivingCourse[end].F_T > drivingCourse[end].F_R
break
else
end
end
end #for
if length(diminishingSection.dataPoints) > 1 # TODO: necessary? May it be possible that there is no diminishing because braking has to start
# calculate the accumulated diminishing section information
diminishingSection.v_exit=drivingCourse[end].v # exit speed (in m/s)
diminishingSection.s_end=drivingCourse[end].s # last position (in m)
diminishingSection.s_total=diminishingSection.s_end-diminishingSection.s_start # total length (in m)
diminishingSection.t_total=drivingCourse[end].t-drivingCourse[diminishingSection.dataPoints[1]].t # total running time (in s)
diminishingSection.E_total=drivingCourse[end].E-drivingCourse[diminishingSection.dataPoints[1]].E # total energy consumption (in Ws)
characteristicSection.t_total=characteristicSection.t_total+diminishingSection.t_total # total running time (in s)
characteristicSection.E_total=characteristicSection.E_total+diminishingSection.E_total # total energy consumption (in Ws)
merge!(characteristicSection.behaviorSections, Dict("diminishing"=>diminishingSection))
end
end
return (characteristicSection, drivingCourse)
end #function addDiminishingPhase!
end #module MovingPhases end #module MovingPhases

View File

@ -11,13 +11,15 @@ export simulateMinimumRunningTime!, simulateMinimumEnergyConsumption
approximationLevel = 6 # TODO: define it in TrainRun and give it to each function? approximationLevel = 6 # TODO: define it in TrainRun and give it to each function?
# simulate a train run focussing on using the minimum possible running time
function simulateMinimumRunningTime!(movingSection::MovingSection, settings::Settings, train::Train) function simulateMinimumRunningTime!(movingSection::MovingSection, settings::Settings, train::Train)
# simulate a train run focussing on using the minimum possible running time # CSs=movingSection.characteristicSections
startingPoint=DataPoint() startingPoint=DataPoint()
startingPoint.i=1 startingPoint.i=1
startingPoint.s=movingSection.characteristicSections[1].s_start startingPoint.s=movingSection.characteristicSections[1].s_start
drivingCourse=[startingPoint] # List of data points drivingCourse=[startingPoint] # List of data points
# for CS in CSs
for csId in 1:length(movingSection.characteristicSections) for csId in 1:length(movingSection.characteristicSections)
# println("CS",csId) # println("CS",csId)
# check if the CS has a cruising section # check if the CS has a cruising section
@ -33,6 +35,7 @@ function simulateMinimumRunningTime!(movingSection::MovingSection, settings::Set
delete!(movingSection.characteristicSections[csId].behaviorSections, "starting") delete!(movingSection.characteristicSections[csId].behaviorSections, "starting")
delete!(movingSection.characteristicSections[csId].behaviorSections, "cruisingBeforeAcceleration") delete!(movingSection.characteristicSections[csId].behaviorSections, "cruisingBeforeAcceleration")
delete!(movingSection.characteristicSections[csId].behaviorSections, "acceleration") delete!(movingSection.characteristicSections[csId].behaviorSections, "acceleration")
delete!(movingSection.characteristicSections[csId].behaviorSections, "diminishing") # 11/22 added new
delete!(movingSection.characteristicSections[csId].behaviorSections, "cruising") delete!(movingSection.characteristicSections[csId].behaviorSections, "cruising")
movingSection.characteristicSections[csId].E_total=0.0 movingSection.characteristicSections[csId].E_total=0.0
movingSection.characteristicSections[csId].t_total=0.0 movingSection.characteristicSections[csId].t_total=0.0
@ -98,7 +101,7 @@ end #function simulateMinimumRunningTime
function simulateMinimumEnergyConsumption(movingSectionMinimumRunningTime::MovingSection, drivingCourseMinimumRunningTime::Vector{DataPoint}, settings::Settings, train::Train) function simulateMinimumEnergyConsumption(movingSectionMinimumRunningTime::MovingSection, drivingCourseMinimumRunningTime::Vector{DataPoint}, settings::Settings, train::Train)
# simulate a train run focussing on using the minimum possible energy consumption # simulate a train run focussing on using the minimum possible energy consumption
# booleans for choosing which methods are used for saving energy # booleans for choosing which methods are used for saving energy
doMethod1=true doMethod1=true
#doMethod1=false #doMethod1=false

View File

@ -112,13 +112,13 @@ function createOutputCsv(settings::Settings, pathName::String, trainName::String
outputArray="outputArrayMinimumEnergyConsumption" outputArray="outputArrayMinimumEnergyConsumption"
date = Dates.now() date = Dates.now()
dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS") dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS")
csvFilePath=settings.csvFolderPath*"\\"*dateString*"_MinimumEnergyConsumption.csv" csvFilePath=settings.csvDirectory*"\\"*dateString*"_MinimumEnergyConsumption.csv"
else else
operationMode="minimum running time" operationMode="minimum running time"
outputArray="outputArrayMinimumRunningTime" outputArray="outputArrayMinimumRunningTime"
date = Dates.now() date = Dates.now()
dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS") dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS")
csvFilePath=settings.csvFolderPath*"\\"*dateString*"_MinimumRunningTime.csv" csvFilePath=settings.csvDirectory*"\\"*dateString*"_MinimumRunningTime.csv"
end end
# creating information block # creating information block
@ -144,7 +144,7 @@ function createOutputCsv(settings::Settings, pathName::String, trainName::String
end # for end # for
# combining the columns in a data frame and saving it as a CSV-file at csvFolderPath # combining the columns in a data frame and saving it as a CSV-file at csvDirectory
if settings.detailOfOutput=="reduced" if settings.detailOfOutput=="reduced"
df=DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3]) df=DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3])
elseif settings.detailOfOutput=="driving course" elseif settings.detailOfOutput=="driving course"
@ -187,7 +187,7 @@ function createOutputCsv(settings::Settings, pathName::String, trainName::String
push!(allColumns, infoColumns[column]) push!(allColumns, infoColumns[column])
end # for end # for
#combining the columns in a data frame and saving it as a CSV-file at csvFolderPath #combining the columns in a data frame and saving it as a CSV-file at csvDirectory
if settings.detailOfOutput=="reduced" if settings.detailOfOutput=="reduced"
df=DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3]) df=DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3])
elseif settings.detailOfOutput=="driving course" elseif settings.detailOfOutput=="driving course"
@ -195,7 +195,7 @@ function createOutputCsv(settings::Settings, pathName::String, trainName::String
end end
date = Dates.now() date = Dates.now()
dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS") dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS")
csvFilePath=settings.csvFolderPath*"\\"*dateString*"_dataMinimumRunningTime.csv" csvFilePath=settings.csvDirectory*"\\"*dateString*"_dataMinimumRunningTime.csv"
CSV.write(csvFilePath, df, header=false) CSV.write(csvFilePath, df, header=false)
println("The output CSV file has been created for minimum running time at ",csvFilePath) println("The output CSV file has been created for minimum running time at ",csvFilePath)
end #if settings.operationModeMinimumRunningTime end #if settings.operationModeMinimumRunningTime
@ -232,10 +232,10 @@ function createOutputCsv(settings::Settings, pathName::String, trainName::String
df=DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3], c4=allColumns[4], c5=allColumns[5], c6=allColumns[6], c7=allColumns[7], c8=allColumns[8], c9=allColumns[9], c10=allColumns[10], c11=allColumns[11], c12=allColumns[12], c13=allColumns[13], c14=allColumns[14], c15=allColumns[15], c16=allColumns[16], c17=allColumns[17], c18=allColumns[18]) df=DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3], c4=allColumns[4], c5=allColumns[5], c6=allColumns[6], c7=allColumns[7], c8=allColumns[8], c9=allColumns[9], c10=allColumns[10], c11=allColumns[11], c12=allColumns[12], c13=allColumns[13], c14=allColumns[14], c15=allColumns[15], c16=allColumns[16], c17=allColumns[17], c18=allColumns[18])
end end
# creating a CSV-file at csvFolderPath # creating a CSV-file at csvDirectory
date = Dates.now() date = Dates.now()
dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS") dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS")
csvFilePath=settings.csvFolderPath*"\\"*dateString*"_dataMinimumEnergyConsumption.csv" csvFilePath=settings.csvDirectory*"\\"*dateString*"_dataMinimumEnergyConsumption.csv"
CSV.write(csvFilePath, df, header=false) CSV.write(csvFilePath, df, header=false)
println("The output CSV file has been created for minimum energy consumption at ",csvFilePath) println("The output CSV file has been created for minimum energy consumption at ",csvFilePath)
end # if settings.operationModeMinimumEnergyConsumption end # if settings.operationModeMinimumEnergyConsumption
@ -255,7 +255,7 @@ end #function printImportantValues
function printSectionInformation(movingSection::MovingSection) function printSectionInformation(movingSection::MovingSection)
println("MS mit s_total=", movingSection.s_total," mit t_total=", movingSection.t_total) println("MS mit s_total=", movingSection.s_total," mit t_total=", movingSection.t_total)
allBs=["starting", "cruisingBeforeAcceleration","acceleration", "cruising", "coasting","cruisingAfterCoasting", "braking"] allBs=["starting", "cruisingBeforeAcceleration","acceleration", "cruising", "diminishing", "coasting","cruisingAfterCoasting", "braking"]
for csId in 1:length(movingSection.characteristicSections) for csId in 1:length(movingSection.characteristicSections)
println("CS ",csId," mit s_total=", movingSection.characteristicSections[csId].s_total," mit t_total=", movingSection.characteristicSections[csId].t_total) println("CS ",csId," mit s_total=", movingSection.characteristicSections[csId].s_total," mit t_total=", movingSection.characteristicSections[csId].t_total)
for bs in 1: length(allBs) for bs in 1: length(allBs)

View File

@ -19,9 +19,9 @@ export calculateDrivingDynamics
# TODO: define it here and give it to each function? (MovingPhases, EnergySaving) # TODO: define it here and give it to each function? (MovingPhases, EnergySaving)
""" """
calculateDrivingDynamics(trainFilePath::String, pathFilePath::String, settingsFilePath::String) calculateDrivingDynamics(trainDirectory::String, pathDirectory::String, settingsDirectory::String)
Calculate the driving dynamics of a train run on a path with special settings with information from the corresponding YAML files with the file paths `trainFilePath`, `pathFilePath`, `settingsFilePath`. Calculate the driving dynamics of a train run on a path with special settings with information from the corresponding YAML files with the file paths `trainDirectory`, `pathDirectory`, `settingsDirectory`.
# Examples # Examples
```julia-repl ```julia-repl
@ -29,11 +29,11 @@ julia> calculateDrivingDynamics(C:\\folder\\train.yaml, C:\\folder\\path.yaml, C
todo !!! todo !!!
``` ```
""" """
function calculateDrivingDynamics(trainFilePath::String, pathFilePath::String, settingsFilePath::String) function calculateDrivingDynamics(trainDirectory::String, pathDirectory::String, settingsDirectory::String)
print("\n\n\n") print("\n\n\n")
# input # input
(train, path, settings)=readInput(trainFilePath, pathFilePath, settingsFilePath) (train, path, settings)=readInput(trainDirectory, pathDirectory, settingsDirectory)
println("The input has been saved.") println("The input has been saved.")
@ -53,7 +53,7 @@ function calculateDrivingDynamics(trainFilePath::String, pathFilePath::String, s
if settings.operationModeMinimumEnergyConsumption==true if settings.operationModeMinimumEnergyConsumption==true
(movingSectionMinimumEnergyConsumption, drivingCourseMinimumEnergyConsumption)=simulateMinimumEnergyConsumption(movingSectionMinimumRunningTime, drivingCourseMinimumRunningTime, settings, train) (movingSectionMinimumEnergyConsumption, drivingCourseMinimumEnergyConsumption)=simulateMinimumEnergyConsumption(movingSectionMinimumRunningTime, drivingCourseMinimumRunningTime, settings, train)
# printSectionInformation(movingSectionMinimumEnergyConsumption) # printSectionInformation(movingSectionMinimumEnergyConsumption)
println("The driving course for lowest the energy consumption has been calculated.") println("The driving course for the lowest energy consumption has been calculated.")
end #if end #if
#output #output

View File

@ -11,7 +11,7 @@ mutable struct Settings
operationModeMinimumEnergyConsumption::Bool # operation mode "minimum energy consumption" operationModeMinimumEnergyConsumption::Bool # operation mode "minimum energy consumption"
# output: # output:
typeOfOutput::String # output as "julia dictionary" or as "CSV" typeOfOutput::String # output as "julia dictionary" or as "CSV"
csvFolderPath::String # path of the folder in which the CSV fiiles willl be saved csvDirectory::String # directory in which the CSV files will be saved
detailOfOutput::String # detail of output "reduced" or "everything" detailOfOutput::String # detail of output "reduced" or "everything"
end # mutable struct Settings end # mutable struct Settings
Settings()=Settings("", "", 0.0, false, false, "", "", "") Settings()=Settings("", "", 0.0, false, false, "", "", "")
@ -26,8 +26,10 @@ mutable struct Train
v_limit::AbstractFloat # trains speed limit (in m/s) v_limit::AbstractFloat # trains speed limit (in m/s)
a_braking::AbstractFloat # braking acceleration (in m/s^2) a_braking::AbstractFloat # braking acceleration (in m/s^2)
m_union::AbstractFloat # total mass (in kg) m_union::AbstractFloat # total mass (in kg)
# m_train
ξ_union::AbstractFloat # rotation mass factor of the whole train union (without unit) ξ_union::AbstractFloat # rotation mass factor of the whole train union (without unit)
# if not available use ξ_t and ξ_w # if not available use ξ_t and ξ_w
# ξ_train
# traction unit # traction unit
m_t::AbstractFloat # mass of the traction unit (in kg) m_t::AbstractFloat # mass of the traction unit (in kg)
@ -35,7 +37,7 @@ mutable struct Train
m_tc::AbstractFloat # mass on the traction units carrying axles (in kg) m_tc::AbstractFloat # mass on the traction units carrying axles (in kg)
ξ_t::AbstractFloat # rotation mass factor of the traction unit (without unit) ξ_t::AbstractFloat # rotation mass factor of the traction unit (without unit)
# in case ξ_union is not available # in case ξ_union is not available
tractiveEffortArray # list values for tractive effort (in [m/s , N]) tractiveEffortVelocityPairs # list of velocities and their corresponding tractive effort (in [m/s , N])
f_Rtd0::AbstractFloat # coefficient for basic resistance due to the traction units driving axles (in ‰) f_Rtd0::AbstractFloat # coefficient for basic resistance due to the traction units driving axles (in ‰)
f_Rtc0::AbstractFloat # coefficient for basic resistance due to the traction units carring axles (in ‰) f_Rtc0::AbstractFloat # coefficient for basic resistance due to the traction units carring axles (in ‰)
@ -89,15 +91,21 @@ mutable struct DataPoint
Δv::AbstractFloat # step size (in m/s) Δv::AbstractFloat # step size (in m/s)
a::AbstractFloat # acceleration (in m/s^2) a::AbstractFloat # acceleration (in m/s^2)
W_T::AbstractFloat # mechanical work (in Ws) W_T::AbstractFloat # mechanical work (in Ws)
# W
ΔW_T::AbstractFloat # mechanical work in this step (in Ws) ΔW_T::AbstractFloat # mechanical work in this step (in Ws)
# ΔW
E::AbstractFloat # energy consumption (in Ws) E::AbstractFloat # energy consumption (in Ws)
ΔE::AbstractFloat # energy consumption in this step (in Ws) ΔE::AbstractFloat # energy consumption in this step (in Ws)
F_T::AbstractFloat # tractive effort (in N) F_T::AbstractFloat # tractive effort (in N)
F_R::AbstractFloat # resisting force (in N) F_R::AbstractFloat # resisting force (in N)
F_Rp::AbstractFloat # line resistanc (in N) F_Rp::AbstractFloat # path resistance (in N)
F_Runion::AbstractFloat # vehicle resistance (in N) # R_path
F_Runion::AbstractFloat # train resistance (in N)
# R_train
F_Rt::AbstractFloat # traction unit resistance (in N) F_Rt::AbstractFloat # traction unit resistance (in N)
# R_traction
F_Rw::AbstractFloat # set of wagons resistance (in N) F_Rw::AbstractFloat # set of wagons resistance (in N)
# R_consist
end # mutable struct DataPoint end # mutable struct DataPoint
DataPoint()=DataPoint(0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) DataPoint()=DataPoint(0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
# tried to insert copy on 15.07.2021 copy(original::DataPoint)=DataPoint(original.i, original.s, original.Δs, original.t, original.Δt, original.v, original.Δv, original.a, original.W_T, original.ΔW_T, original.E, original.ΔE, original.F_T, original.F_R, original.F_Rp, original.F_Runion, original.F_Rt, original.F_Rw) # tried to insert copy on 15.07.2021 copy(original::DataPoint)=DataPoint(original.i, original.s, original.Δs, original.t, original.Δt, original.v, original.Δv, original.a, original.W_T, original.ΔW_T, original.E, original.ΔE, original.F_T, original.F_R, original.F_Rp, original.F_Runion, original.F_Rt, original.F_Rw)
@ -109,6 +117,7 @@ DataPoint(original::DataPoint)=DataPoint(original.i, original.s, original.Δs, o
## smallest section of the path is the behavior section. It relates to the containing data points via their identifier. ## smallest section of the path is the behavior section. It relates to the containing data points via their identifier.
mutable struct BehaviorSection mutable struct BehaviorSection
type::String # type of behavior section: "starting", "cruisingBeforeAcceleration", "acceleration", "cruising", "coasting", "cruisingAfterCoasting" or "braking" type::String # type of behavior section: "starting", "cruisingBeforeAcceleration", "acceleration", "cruising", "coasting", "cruisingAfterCoasting" or "braking"
# enum-type. breakFree, clearing, diminishing, standStill, "acceleration", "cruising", "coasting", "braking"
s_total::AbstractFloat # total length (in m) s_total::AbstractFloat # total length (in m)
s_start::AbstractFloat # first position (in m) s_start::AbstractFloat # first position (in m)
s_end::AbstractFloat # last position (in m) s_end::AbstractFloat # last position (in m)
@ -131,15 +140,21 @@ end
mutable struct CharacteristicSection mutable struct CharacteristicSection
id::Integer # identifier id::Integer # identifier
s_total::AbstractFloat # total length (in m) s_total::AbstractFloat # total length (in m)
# length::AbstractFloat # total length (in m)
s_start::AbstractFloat # first position (in m) s_start::AbstractFloat # first position (in m)
# s_entry
s_end::AbstractFloat # last position (in m) s_end::AbstractFloat # last position (in m)
# s_exit
t_total::AbstractFloat # total running time (in s) t_total::AbstractFloat # total running time (in s)
# t
E_total::AbstractFloat # total energy consumption (in Ws) E_total::AbstractFloat # total energy consumption (in Ws)
# E
v_limit::AbstractFloat # speed limit (in m/s) v_limit::AbstractFloat # speed limit (in m/s)
v_reach::AbstractFloat # maximum reachable speed (in m/s) v_reach::AbstractFloat # maximum reachable speed (in m/s)
# v_target
v_entry::AbstractFloat # maximum entry speed (in m/s) v_entry::AbstractFloat # maximum entry speed (in m/s)
v_exit::AbstractFloat # maximum exit speed (in m/s) v_exit::AbstractFloat # maximum exit speed (in m/s)
f_Rp::AbstractFloat # spedific line resistance (in ‰) f_Rp::AbstractFloat # spedific path resistance (in ‰)
behaviorSections::AbstractDict{String, BehaviorSection} # list of containing behavior sections behaviorSections::AbstractDict{String, BehaviorSection} # list of containing behavior sections
end # mutable struct CharacteristicSection end # mutable struct CharacteristicSection
CharacteristicSection()=CharacteristicSection(0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Dict{String, BehaviorSection}()) CharacteristicSection()=CharacteristicSection(0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Dict{String, BehaviorSection}())