commit
e5c08d1410
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -23,10 +23,18 @@ Categories: Added, Changed, Deprecated, Removed, Fixed, and Security.
|
|||
* renamed Validate.jl into types.jl
|
||||
* renamed TrainRunCalc.jl into calc.jl
|
||||
* moved trainrun function from calc.jl to TrainRun.jl
|
||||
* moved createDataPoint() from behavior.jl to types.jl
|
||||
* moved createBehaviorSection() from behavior.jl to types.jl
|
||||
* moved createMovingSection() from characteristics.jl to types.jl
|
||||
* moved createCharacteristicSection() from characteristics.jl to types.jl
|
||||
* moved createDataPoint() from behavior.jl to constructors.jl
|
||||
* moved createBehaviorSection() from behavior.jl to constructors.jl
|
||||
* moved createMovingSection() from characteristics.jl to constructors.jl
|
||||
* moved createCharacteristicSection() from characteristics.jl to constructors.jl
|
||||
* removed characteristics.jl and moved all functions inside to behavior.jl
|
||||
* moved calculateTractiveEffort() from behavior.jl to calc.jl
|
||||
* moved calculatePathResistance() from behavior.jl to calc.jl
|
||||
* moved calculateForces!() from behavior.jl to calc.jl
|
||||
* moved moveAStep() from behavior.jl to calc.jl
|
||||
* moved getCurrentSpeedLimit() from behavior.jl to calc.jl
|
||||
* moved getNextPointOfInterest() from behavior.jl to calc.jl
|
||||
* moved determineCharacteristics() from behavior.jl to calc.jl
|
||||
* changed title of include files from upper case to lower case
|
||||
* changed seperation of submodules into a single module with file include
|
||||
* updated test files to railtoolkit/schema (2022.05)
|
||||
|
|
|
@ -1,32 +1,24 @@
|
|||
#!/usr/bin/env julia
|
||||
|
||||
import TrainRuns
|
||||
using TrainRuns
|
||||
using CSV
|
||||
|
||||
paths=[]
|
||||
push!(paths, importFromYaml(:path, "data/paths/path_1_10km_nConst_vConst.yaml"))
|
||||
push!(paths, importFromYaml(:path, "data/paths/path_2_10km_nVar_vConst.yaml"))
|
||||
push!(paths, importFromYaml(:path, "data/paths/path_3_10km_nConst_vVar.yaml"))
|
||||
push!(paths, importFromYaml(:path, "data/paths/path_4_real_Germany_EastSaxony_DG-DN.yaml"))
|
||||
|
||||
settings=[]
|
||||
push!(settings, importFromYaml(:settings, "data/settings/settings_distanceStep_massPoint.yaml"))
|
||||
push!(paths, Path("test/data/paths/const.yaml"))
|
||||
push!(paths, Path("test/data/paths/slope.yaml"))
|
||||
push!(paths, Path("test/data/paths/speed.yaml"))
|
||||
push!(paths, Path("test/data/paths/realworld.yaml"))
|
||||
|
||||
trains=[]
|
||||
push!(trains, importFromYaml(:train, "data/trains/train_freight_V90withOreConsist.yaml"))
|
||||
push!(trains, importFromYaml(:train, "data/trains/train_passenger_SiemensDesiroClassic.yaml"))
|
||||
push!(trains, importFromYaml(:train, "data/trains/train_passenger_IC2.yaml"))
|
||||
push!(trains, Train("test/data/trains/freight.yaml"))
|
||||
push!(trains, Train("test/data/trains/local.yaml"))
|
||||
push!(trains, Train("test/data/trains/longdistance.yaml"))
|
||||
|
||||
for path in paths
|
||||
# println(" - - - - - - - - -")
|
||||
# println("path: ", path[:name])
|
||||
for train in trains
|
||||
# println("train: ", train[:name])
|
||||
for settings in settings
|
||||
resultsDict = trainrun(train, path, settings)
|
||||
if haskey(settings, :outputFormat) && settings[:outputFormat] == "CSV"
|
||||
exportToCsv(resultsDict, settings)
|
||||
sleep(2)
|
||||
end
|
||||
end
|
||||
settings = Settings("test/data/settings/driving_course.yaml")
|
||||
|
||||
for p in 1:length(paths)
|
||||
for t in 1:length(trains)
|
||||
driving_course = trainrun(trains[t], paths[p], settings)
|
||||
CSV.write("docs/examples/drivingCourse_path"*string(p)*"_train"*string(t)*".csv", driving_course)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,6 +5,6 @@ using TrainRuns
|
|||
train = Train("test/data/trains/freight.yaml")
|
||||
path = Path("test/data/paths/const.yaml")
|
||||
|
||||
runtime = trainrun(train, path)
|
||||
runtime = trainrun(train, path)[end, :t]
|
||||
|
||||
println("The train needs $runtime seconds for the running path.")
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#!/usr/bin/env julia
|
||||
# -*- coding: UTF-8 -*-
|
||||
# __julia-version__ = 1.7.2
|
||||
# __author__ = "Max Kannenberg, Martin Scheidt"
|
||||
# __copyright__ = "2020-2022"
|
||||
# __license__ = "ISC"
|
||||
|
@ -13,13 +12,13 @@ using UUIDs, Dates, Statistics
|
|||
## loading external packages
|
||||
using YAML, JSONSchema, DataFrames
|
||||
|
||||
export
|
||||
export
|
||||
## Interface
|
||||
trainrun, Train, Path, Settings
|
||||
|
||||
## global variables
|
||||
global g = 9.80665 # acceleration due to gravity (in m/s^2)
|
||||
global μ = 0.2 # friction as constant, todo: implement as function
|
||||
global μ = 0.2 # friction as constant, TODO: implement as function
|
||||
global Δv_air = 15.0/3.6 # coefficient for velocitiy difference between train and outdoor air (in m/s)
|
||||
|
||||
## include package files
|
||||
|
@ -27,7 +26,6 @@ include("types.jl")
|
|||
include("constructors.jl")
|
||||
include("formulary.jl")
|
||||
include("calc.jl")
|
||||
include("characteristics.jl")
|
||||
include("behavior.jl")
|
||||
include("output.jl")
|
||||
|
||||
|
@ -49,14 +47,14 @@ xxx.xx # in seconds
|
|||
function trainrun(train::Train, path::Path, settings=Settings()::Settings)
|
||||
# prepare the input data
|
||||
movingSection = determineCharacteristics(path, train, settings)
|
||||
settings.outputDetail == :everything && println("The moving section has been prepared.")
|
||||
# settings.outputDetail == :verbose && println("The moving section has been prepared.")
|
||||
|
||||
# calculate the train run for oparation mode "minimum running time"
|
||||
(movingSection, drivingCourse) = calculateMinimumRunningTime!(movingSection, settings, train)
|
||||
settings.outputDetail == :everything && println("The driving course for the shortest running time has been calculated.")
|
||||
# settings.outputDetail == :verbose && println("The driving course for the shortest running time has been calculated.")
|
||||
|
||||
# accumulate data and create an output dictionary
|
||||
output = createOutput(train, settings, path, movingSection, drivingCourse)
|
||||
output = createOutput(settings, drivingCourse, movingSection[:pointsOfInterest])
|
||||
|
||||
return output
|
||||
end # function trainrun
|
||||
|
|
406
src/behavior.jl
406
src/behavior.jl
|
@ -1,192 +1,9 @@
|
|||
#!/usr/bin/env julia
|
||||
# -*- coding: UTF-8 -*-
|
||||
# __julia-version__ = 1.7.2
|
||||
# __author__ = "Max Kannenberg"
|
||||
# __copyright__ = "2020-2022"
|
||||
# __license__ = "ISC"
|
||||
|
||||
"""
|
||||
calculateTractiveEffort(v, tractiveEffortVelocityPairs)
|
||||
|
||||
Calculate the trains tractive effort with the `tractiveEffortVelocityPairs` dependend on the velocity `v`.
|
||||
|
||||
...
|
||||
# Arguments
|
||||
- `v::AbstractFloat`: the current velocity in m/s.
|
||||
- `tractiveEffortVelocityPairs::Array{}`: the trains pairs for velocity in m/s and tractive effort in N as one array containing an array for each pair.
|
||||
...
|
||||
|
||||
# Examples
|
||||
```julia-repl
|
||||
julia> calculateTractiveEffort(20.0, [(0.0, 180000), (20.0, 100000), (40.0, 60000), (60.0, 40000), (80.0, 30000)])
|
||||
100000
|
||||
|
||||
julia> calculateTractiveEffort(30.0, [(0.0, 180000), (20.0, 100000), (40.0, 60000), (60.0, 40000), (80.0, 30000)])
|
||||
80000
|
||||
```
|
||||
"""
|
||||
function calculateTractiveEffort(v::AbstractFloat, tractiveEffortVelocityPairs::Array{})
|
||||
for row in 1:length(tractiveEffortVelocityPairs)
|
||||
nextPair = tractiveEffortVelocityPairs[row]
|
||||
if nextPair[1] == v
|
||||
return nextPair[2]
|
||||
elseif nextPair[1] > v
|
||||
# interpolate for a straight line between the two surrounding points with the formula: F=(v-v_(row-1))*(F_row-F_(row-1))/(v_row-v_(row-1))+F_(row-1)
|
||||
previousPair = tractiveEffortVelocityPairs[row-1]
|
||||
F_T_interpolation = (v-previousPair[1]) * (nextPair[2]-previousPair[2]) / (nextPair[1]-previousPair[1]) + previousPair[2]
|
||||
return F_T_interpolation
|
||||
end #if
|
||||
end #for
|
||||
# if v gets higher than the velocities in tractiveEffortVelocityPairs the last tractive effort will be used
|
||||
# TODO: also an extrapolation could be used
|
||||
return tractiveEffortVelocityPairs[end][2]
|
||||
end #function calculateTractiveEffort
|
||||
|
||||
"""
|
||||
calculate and return the path resistance dependend on the trains position and mass model
|
||||
"""
|
||||
function calculatePathResistance(CSs::Vector{Dict}, csId::Integer, s::Real, massModel, train::Train)
|
||||
|
||||
if massModel == :mass_point
|
||||
pathResistance = calcForceFromCoefficient(CSs[csId][:r_path], train.m_train_full)
|
||||
elseif massModel == :homogeneous_strip
|
||||
pathResistance = 0.0
|
||||
s_rear = s - train.length # position of the rear of the train
|
||||
while csId > 0 && s_rear < CSs[csId][:s_exit]
|
||||
pathResistance = pathResistance + (min(s, CSs[csId][:s_exit]) - max(s_rear, CSs[csId][:s_entry])) / train.length * calcForceFromCoefficient(CSs[csId][:r_path], train.m_train_full)
|
||||
csId = csId-1
|
||||
if csId == 0
|
||||
# TODO: currently for values < movingSection[:s_entry] the values of movingSection[:s_entry] will be used
|
||||
return pathResistance + (CSs[1][:s_entry] - s_rear) / train.length * calcForceFromCoefficient(CSs[1][:r_path], train.m_train_full)
|
||||
end #if
|
||||
end #while
|
||||
end #if
|
||||
|
||||
return pathResistance
|
||||
end #function calculatePathResistance
|
||||
|
||||
"""
|
||||
calculate and return tractive and resisting forces for a data point
|
||||
"""
|
||||
function calculateForces!(dataPoint::Dict, CSs::Vector{Dict}, csId::Integer, bsType::String, train::Train, massModel)
|
||||
# calculate resisting forces
|
||||
dataPoint[:R_traction] = calcTractionUnitResistance(dataPoint[:v], train)
|
||||
dataPoint[:R_wagons] = calcWagonsResistance(dataPoint[:v], train)
|
||||
dataPoint[:R_train] = dataPoint[:R_traction] + dataPoint[:R_wagons]
|
||||
dataPoint[:R_path] = calculatePathResistance(CSs, csId, dataPoint[:s], massModel, train)
|
||||
dataPoint[:F_R] = dataPoint[:R_train] + dataPoint[:R_path]
|
||||
|
||||
# calculate tractive effort
|
||||
if bsType == "braking" || bsType == "coasting"
|
||||
dataPoint[:F_T] = 0.0
|
||||
elseif bsType == "cruising"
|
||||
dataPoint[:F_T] = min(max(0.0, dataPoint[:F_R]), calculateTractiveEffort(dataPoint[:v], train.tractiveEffort))
|
||||
else # bsType == "accelerating" || bsType == "diminishing" || 'default'
|
||||
dataPoint[:F_T] = calculateTractiveEffort(dataPoint[:v], train.tractiveEffort)
|
||||
end
|
||||
|
||||
return dataPoint
|
||||
end #function calculateForces!
|
||||
|
||||
|
||||
"""
|
||||
TODO
|
||||
"""
|
||||
function moveAStep(previousPoint::Dict, stepVariable::Symbol, stepSize::Real, csId::Integer)
|
||||
# stepSize is the currentStepSize depending on the accessing function
|
||||
# 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. =#
|
||||
|
||||
# create the next data point
|
||||
newPoint = createDataPoint()
|
||||
newPoint[:i] = previousPoint[:i]+1 # identifier
|
||||
|
||||
# calculate s, t, v, E
|
||||
if stepVariable == :distance # distance step method
|
||||
newPoint[:Δs] = stepSize # step size (in m)
|
||||
if previousPoint[:a] == 0.0
|
||||
if previousPoint[:v] == 0.0
|
||||
error("ERROR: The train tries to cruise at v=0.0 m/s at s=",previousPoint[:s]," in CS",csId,".")
|
||||
end
|
||||
newPoint[:Δt] = calc_Δt_with_constant_v(newPoint[:Δs], previousPoint[:v]) # step size (in s)
|
||||
newPoint[:Δv] = 0.0 # step size (in m/s)
|
||||
else
|
||||
# check if the parts of the following square roots will be <0.0 in the functions calc_Δt_with_Δs and calc_Δv_with_Δs
|
||||
squareRootPartIsNegative = (previousPoint[:v]/previousPoint[:a])^2+2*newPoint[:Δs]/previousPoint[:a] < 0.0 || previousPoint[:v]^2+2*newPoint[:Δs]*previousPoint[:a] < 0.0
|
||||
if previousPoint[:a] < 0.0 && squareRootPartIsNegative
|
||||
error("ERROR: The train stops during the accelerating section in CS",csId," because the tractive effort is lower than the resistant forces.",
|
||||
" Before the stop the last point has the values s=",previousPoint[:s]," m, v=",previousPoint[:v]," m/s, a=",previousPoint[:a]," m/s^2,",
|
||||
" F_T=",previousPoint[:F_T]," N, R_traction=",previousPoint[:R_traction]," N, R_wagons=",previousPoint[:R_wagons]," N, R_path=",previousPoint[:R_path]," N.")
|
||||
end
|
||||
newPoint[:Δt] = calc_Δt_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in s)
|
||||
newPoint[:Δv] = calc_Δv_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in m/s)
|
||||
end
|
||||
|
||||
elseif stepVariable == :time # time step method
|
||||
newPoint[:Δt] = stepSize # step size (in s)
|
||||
newPoint[:Δs] = calc_Δs_with_Δt(newPoint[:Δt], previousPoint[:a], previousPoint[:v]) # step size (in m)
|
||||
newPoint[:Δv] = calc_Δv_with_Δt(newPoint[:Δt], previousPoint[:a]) # step size (in m/s)
|
||||
|
||||
elseif stepVariable == :velocity # velocity step method
|
||||
if previousPoint[:a] == 0.0
|
||||
if previousPoint[:v] == 0.0
|
||||
error("ERROR: The train tries to cruise at v=0.0 m/s at s=",previousPoint[:s]," in CS",csId,".")
|
||||
end
|
||||
newPoint[:Δs] = stepSize # step size (in m)
|
||||
# TODO what is the best default step size for constant v? define Δs or Δt?
|
||||
newPoint[:Δt] = calc_Δt_with_constant_v(newPoint[:Δs], previousPoint[:v]) # step size (in s)
|
||||
newPoint[:Δv] = 0.0 # step size (in m/s)
|
||||
else
|
||||
newPoint[:Δv] = stepSize * sign(previousPoint[:a]) # step size (in m/s)
|
||||
newPoint[:Δs] = calc_Δs_with_Δv(newPoint[:Δv], previousPoint[:a], previousPoint[:v]) # step size (in m)
|
||||
newPoint[:Δt] = calc_Δt_with_Δv(newPoint[:Δv], previousPoint[:a]) # step size (in s)
|
||||
end
|
||||
end #if
|
||||
|
||||
newPoint[:s] = previousPoint[:s] + newPoint[:Δs] # position (in m)
|
||||
newPoint[:t] = previousPoint[:t] + newPoint[:Δt] # point in time (in s)
|
||||
newPoint[:v] = previousPoint[:v] + newPoint[:Δv] # velocity (in m/s)
|
||||
newPoint[:ΔW] = calc_ΔW(previousPoint[:F_T], newPoint[:Δs]) # mechanical work in this step (in Ws)
|
||||
newPoint[:W] = previousPoint[:W] + newPoint[:ΔW] # mechanical work (in Ws)
|
||||
newPoint[:ΔE] = calc_ΔE(newPoint[:ΔW]) # energy consumption in this step (in Ws)
|
||||
newPoint[:E] = previousPoint[:E] + newPoint[:ΔE] # energy consumption (in Ws)
|
||||
|
||||
|
||||
return newPoint
|
||||
end #function moveAStep
|
||||
|
||||
"""
|
||||
# if the rear of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept
|
||||
"""
|
||||
function getCurrentSpeedLimit(CSs::Vector{Dict}, csWithTrainHeadId::Integer, s::Real, trainLength::Real)
|
||||
v_limit = CSs[csWithTrainHeadId][:v_limit]
|
||||
s_exit = CSs[csWithTrainHeadId][:s_exit]
|
||||
if csWithTrainHeadId > 1 && s -trainLength < CSs[csWithTrainHeadId][:s_entry]
|
||||
formerCsId = csWithTrainHeadId-1
|
||||
while formerCsId > 0 && s -trainLength < CSs[formerCsId][:s_exit]
|
||||
if CSs[formerCsId][:v_limit] < v_limit # TODO: is the position of the train's rear < movingSection[:s_entry], v_limit of the first CS is used
|
||||
v_limit = CSs[formerCsId][:v_limit]
|
||||
s_exit = CSs[formerCsId][:s_exit]
|
||||
end
|
||||
formerCsId = formerCsId -1
|
||||
end
|
||||
end
|
||||
currentSpeedLimit = Dict(:v => v_limit, :s_end => s_exit + trainLength)
|
||||
return currentSpeedLimit
|
||||
end #function getCurrentSpeedLimit
|
||||
|
||||
"""
|
||||
?
|
||||
"""
|
||||
function getNextPointOfInterest(pointsOfInterest::Vector{Tuple}, s::Real)
|
||||
for s_POI in pointsOfInterest
|
||||
if s_POI[1] > s
|
||||
return s_POI
|
||||
end
|
||||
end
|
||||
error("ERROR in getNextPointOfInterest: There is no POI higher than s=",s," m.")
|
||||
end #function getNextPointOfInterest
|
||||
|
||||
## This function calculates the data points of the breakFree section.
|
||||
# Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for breakFree if needed.
|
||||
# Info: currently the values of the breakFree section will be calculated like in the accelerating section
|
||||
|
@ -196,7 +13,7 @@ function addBreakFreeSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:
|
|||
trainIsHalting = drivingCourse[end][:v] == 0.0
|
||||
|
||||
if trainIsHalting && !endOfCSReached
|
||||
BS = createBehaviorSection("breakFree", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i])
|
||||
BS = BehaviorSection("breakFree", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i])
|
||||
drivingCourse[end][:behavior] = BS[:type]
|
||||
|
||||
# traction effort and resisting forces (in N)
|
||||
|
@ -221,18 +38,15 @@ function addBreakFreeSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:
|
|||
|
||||
# remove the accelerating section from the CS
|
||||
CS[:t] = CS[:t] - get(CS[:behaviorSections], :accelerating, Dict(:t=>0.0))[:t] # total running time (in s)
|
||||
CS[:E] = CS[:E] - get(CS[:behaviorSections], :accelerating, Dict(:E=>0.0))[:E] # total energy consumption (in Ws)
|
||||
delete!(CS[:behaviorSections], :accelerating)
|
||||
|
||||
# calculate the accumulated breakFree section information
|
||||
merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m)
|
||||
:s_exit => drivingCourse[end][:s], # last position (in m)
|
||||
:t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s)
|
||||
:E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws)
|
||||
:v_exit => drivingCourse[end][:v])) # exit speed (in m/s)))
|
||||
|
||||
CS[:t] = CS[:t] + BS[:t] # total running time (in s)
|
||||
CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws)
|
||||
|
||||
merge!(CS[:behaviorSections], Dict(:breakFree => BS))
|
||||
end # else: return the characteristic section without a breakFree section
|
||||
|
@ -242,7 +56,7 @@ function addBreakFreeSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:
|
|||
if haskey(stateFlags, :usedForDefiningCharacteristics) && stateFlags[:usedForDefiningCharacteristics]
|
||||
s_braking = 0.0
|
||||
else
|
||||
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking)
|
||||
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
|
||||
end
|
||||
|
||||
# reset state flags
|
||||
|
@ -268,7 +82,7 @@ function addClearingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
|
|||
s_braking = 0.0
|
||||
else
|
||||
ignoreBraking = false
|
||||
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking)
|
||||
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
|
||||
end
|
||||
|
||||
s_clearing = min(CS[:s_exit]-drivingCourse[end][:s]-s_braking, currentSpeedLimit[:s_end] - drivingCourse[end][:s])
|
||||
|
@ -306,7 +120,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla
|
|||
s_braking = 0.0
|
||||
else
|
||||
ignoreBraking = false
|
||||
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking)
|
||||
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
|
||||
end
|
||||
|
||||
# conditions for the accelerating section
|
||||
|
@ -318,7 +132,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla
|
|||
|
||||
# use the conditions for the accelerating section
|
||||
if !targetSpeedReached && !endOfCSReached && tractionSurplus && !brakingStartReached
|
||||
BS = createBehaviorSection("accelerating", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i])
|
||||
BS = BehaviorSection("accelerating", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i])
|
||||
drivingCourse[end][:behavior] = BS[:type]
|
||||
|
||||
currentSpeedLimit = getCurrentSpeedLimit(CSs, CS[:id], drivingCourse[end][:s], train.length)
|
||||
|
@ -333,7 +147,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla
|
|||
|
||||
for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation
|
||||
if !ignoreBraking
|
||||
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking)
|
||||
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
|
||||
end
|
||||
|
||||
while !targetSpeedReached && !speedLimitReached && !brakingStartReached && !pointOfInterestReached && tractionSurplus && !previousSpeedLimitReached
|
||||
|
@ -344,7 +158,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla
|
|||
end
|
||||
|
||||
# acceleration (in m/s^2):
|
||||
drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train.m_train_full, train.ξ_train)
|
||||
drivingCourse[end][:a] = acceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train.m_train_full, train.ξ_train)
|
||||
|
||||
# create the next data point
|
||||
push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, CS[:id]))
|
||||
|
@ -355,7 +169,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla
|
|||
|
||||
# conditions for the next while cycle
|
||||
if !ignoreBraking
|
||||
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking)
|
||||
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
|
||||
end
|
||||
brakingStartReached = drivingCourse[end][:s] +s_braking >= CS[:s_exit]
|
||||
speedLimitReached = drivingCourse[end][:v] > CS[:v_limit]
|
||||
|
@ -504,6 +318,9 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla
|
|||
if drivingCourse[end][:s] == CS[:s_exit]
|
||||
endOfCSReached = true
|
||||
end
|
||||
if drivingCourse[end][:s] == nextPointOfInterest[1]
|
||||
drivingCourse[end][:label] = nextPointOfInterest[2]
|
||||
end
|
||||
|
||||
end #while
|
||||
|
||||
|
@ -512,12 +329,10 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla
|
|||
merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m)
|
||||
:s_exit => drivingCourse[end][:s], # last position (in m)
|
||||
:t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s)
|
||||
:E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws)
|
||||
:v_exit => drivingCourse[end][:v])) # exit speed (in m/s)))
|
||||
|
||||
# 03/10 old: CS[:v_peak] = max(drivingCourse[end][:v], CS[:v_entry]) # setting v_peak to the last data points velocity which is the highest reachable value in this characteristic section or to v_entry in case it is higher when running on a path with high resistances
|
||||
CS[:t] = CS[:t] + BS[:t] # total running time (in s)
|
||||
CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws)
|
||||
|
||||
mergeBehaviorSection!(CS[:behaviorSections], BS)
|
||||
end
|
||||
|
@ -554,11 +369,11 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
|
|||
s_braking = 0.0
|
||||
else
|
||||
ignoreBraking = false
|
||||
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking)
|
||||
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
|
||||
end
|
||||
|
||||
# conditions for cruising section
|
||||
#s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking)
|
||||
#s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
|
||||
brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached]
|
||||
speedIsValid = drivingCourse[end][:v]>0.0 && drivingCourse[end][:v]<=CS[:v_peak]
|
||||
tractionDeficit = drivingCourse[end][:F_T] < drivingCourse[end][:F_R]
|
||||
|
@ -568,7 +383,7 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
|
|||
|
||||
if speedIsValid && !brakingStartReached && !tractionDeficit && !targetPositionReached
|
||||
# 03/04 old: if drivingCourse[end][:v]>0.0 && drivingCourse[end][:v]<=CS[:v_peak] && !brakingStartReached && drivingCourse[end][:F_T] >= drivingCourse[end][:F_R]
|
||||
BS = createBehaviorSection(cruisingType, drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i])
|
||||
BS = BehaviorSection(cruisingType, drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i])
|
||||
drivingCourse[end][:behavior] = BS[:type]
|
||||
# TODO: necessary?
|
||||
s_cruising = min(s_cruising, CS[:s_exit]-BS[:s_entry])
|
||||
|
@ -592,7 +407,7 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
|
|||
# use the conditions for the cruising section
|
||||
while trainInPreviousCS && !targetPositionReached && !tractionDeficit && (trainIsClearing || (trainIsBrakingDownhill == resistingForceNegative)) # while clearing tractive or braking force can be used
|
||||
currentStepSize = settings.stepSize
|
||||
nextPointOfInterest[1] = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])
|
||||
nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])
|
||||
pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1]
|
||||
|
||||
for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation
|
||||
|
@ -715,6 +530,11 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
|
|||
end
|
||||
end
|
||||
end #for
|
||||
|
||||
if drivingCourse[end][:s] == nextPointOfInterest[1]
|
||||
drivingCourse[end][:label] = nextPointOfInterest[2]
|
||||
end
|
||||
|
||||
end #while
|
||||
end #if
|
||||
|
||||
|
@ -725,7 +545,10 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
|
|||
|
||||
while !targetPositionReached && !tractionDeficit && (trainIsClearing || (trainIsBrakingDownhill == resistingForceNegative)) # while clearing tractive or braking force can be used
|
||||
# 03/09 old: while drivingCourse[end][:s] < BS[:s_entry]+s_cruising && drivingCourse[end][:F_T] >= drivingCourse[end][:F_R]
|
||||
nextPointOfInterest = min(BS[:s_entry]+s_cruising, getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])[1])
|
||||
nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])
|
||||
if nextPointOfInterest[1] > BS[:s_entry]+s_cruising
|
||||
nextPointOfInterest = [BS[:s_entry]+s_cruising, ""]
|
||||
end
|
||||
|
||||
# tractive effort (in N):
|
||||
#03/25 drivingCourse[end][:F_T] = min(drivingCourse[end][:F_T], max(0.0, drivingCourse[end][:F_R]))
|
||||
|
@ -746,6 +569,9 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
|
|||
# create the next data point
|
||||
push!(drivingCourse, moveAStep(drivingCourse[end], :distance, s_cruisingRemaining, CS[:id]))
|
||||
drivingCourse[end][:behavior] = BS[:type]
|
||||
if drivingCourse[end][:s] == nextPointOfInterest[1]
|
||||
drivingCourse[end][:label] = nextPointOfInterest[2]
|
||||
end
|
||||
push!(BS[:dataPoints], drivingCourse[end][:i])
|
||||
|
||||
calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel)
|
||||
|
@ -769,11 +595,9 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
|
|||
merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m)
|
||||
:s_exit => drivingCourse[end][:s], # last position (in m)
|
||||
:t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s)
|
||||
:E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws)
|
||||
:v_exit => drivingCourse[end][:v])) # exit speed (in m/s)))
|
||||
|
||||
CS[:t] = CS[:t] + BS[:t] # total running time (in s)
|
||||
CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws)
|
||||
|
||||
mergeBehaviorSection!(CS[:behaviorSections], BS)
|
||||
end # else: return the characteristic section without a cruising section
|
||||
|
@ -781,7 +605,7 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
|
|||
# set state flags
|
||||
stateFlags[:endOfCSReached] = drivingCourse[end][:s] == CS[:s_exit]
|
||||
if !ignoreBraking
|
||||
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking)
|
||||
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
|
||||
end
|
||||
stateFlags[:brakingStartReached] = brakingStartReached || drivingCourse[end][:s] + s_braking >= CS[:s_exit]
|
||||
stateFlags[:tractionDeficit] = tractionDeficit
|
||||
|
@ -803,31 +627,31 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag
|
|||
s_braking = 0.0
|
||||
else
|
||||
ignoreBraking = false
|
||||
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking)
|
||||
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
|
||||
end
|
||||
|
||||
# conditions for diminishing section
|
||||
targetSpeedReached = drivingCourse[end][:v] <= 0.0
|
||||
endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached]
|
||||
tractionDeficit = drivingCourse[end][:F_T] < drivingCourse[end][:F_R] #|| stateFlags[:tractionDeficit]
|
||||
#s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking)
|
||||
#s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
|
||||
brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached]
|
||||
|
||||
# use the conditions for the diminishing section
|
||||
if tractionDeficit && !targetSpeedReached && !endOfCSReached
|
||||
BS = createBehaviorSection("diminishing", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i])
|
||||
BS = BehaviorSection("diminishing", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i])
|
||||
drivingCourse[end][:behavior] = BS[:type]
|
||||
|
||||
while tractionDeficit && !targetSpeedReached && !endOfCSReached && !brakingStartReached
|
||||
currentStepSize=settings.stepSize # initialize the step size that can be reduced near intersections
|
||||
nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])[1]
|
||||
nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])
|
||||
pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1]
|
||||
|
||||
for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation
|
||||
while tractionDeficit && !brakingStartReached && !pointOfInterestReached && !targetSpeedReached
|
||||
# 03/09 old: while drivingCourse[end][:F_T] < drivingCourse[end][:F_R] && !brakingStartReached && drivingCourse[end][:s] < nextPointOfInterest[1] && drivingCourse[end][:v]>0.0 # as long as s_i + s_braking < s_end
|
||||
# acceleration (in m/s^2):
|
||||
drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train.m_train_full, train.ξ_train)
|
||||
drivingCourse[end][:a] = acceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train.m_train_full, train.ξ_train)
|
||||
|
||||
# create the next data point
|
||||
push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, CS[:id]))
|
||||
|
@ -838,7 +662,7 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag
|
|||
|
||||
# conditions for the next while cycle
|
||||
if !ignoreBraking
|
||||
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking)
|
||||
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
|
||||
end
|
||||
brakingStartReached = drivingCourse[end][:s] +s_braking >= CS[:s_exit]
|
||||
pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1]
|
||||
|
@ -856,11 +680,11 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag
|
|||
# check which limit was reached and adjust the currentStepSize for the next cycle
|
||||
if cycle < settings.approxLevel+1
|
||||
if drivingCourse[end][:v] < 0.0
|
||||
if settings.stepVariable == velocity
|
||||
currentStepSize = drivingCourse[end-1][:v]
|
||||
else
|
||||
# if settings.stepVariable == :velocity
|
||||
# currentStepSize = drivingCourse[end-1][:v]
|
||||
# else
|
||||
currentStepSize = settings.stepSize / 10.0^cycle
|
||||
end
|
||||
# end
|
||||
elseif drivingCourse[end][:F_T] > drivingCourse[end][:F_R]
|
||||
testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: F_T=", drivingCourse[end][:F_T]," > F_R=",drivingCourse[end][:F_R]) # for testing
|
||||
currentStepSize = settings.stepSize / 10.0^cycle
|
||||
|
@ -951,6 +775,10 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag
|
|||
# end
|
||||
end #if
|
||||
end #for
|
||||
|
||||
if drivingCourse[end][:s] == nextPointOfInterest[1]
|
||||
drivingCourse[end][:label] = nextPointOfInterest[2]
|
||||
end
|
||||
end #while
|
||||
|
||||
if length(BS[:dataPoints]) > 1 # TODO: necessary? May it be possible that there is no diminishing because braking has to start?
|
||||
|
@ -958,11 +786,9 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag
|
|||
merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m)
|
||||
:s_exit => drivingCourse[end][:s], # last position (in m)
|
||||
:t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s)
|
||||
:E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws)
|
||||
:v_exit => drivingCourse[end][:v])) # exit speed (in m/s)))
|
||||
|
||||
CS[:t] = CS[:t] + BS[:t] # total running time (in s)
|
||||
CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws)
|
||||
|
||||
mergeBehaviorSection!(CS[:behaviorSections], BS)
|
||||
end
|
||||
|
@ -990,12 +816,12 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
|
|||
targetSpeedReached = drivingCourse[end][:v] <= CS[:v_exit]
|
||||
endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached]
|
||||
|
||||
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking)
|
||||
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
|
||||
brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached]
|
||||
|
||||
# use the conditions for the coasting section
|
||||
if !targetSpeedReached && !endOfCSReached
|
||||
BS = createBehaviorSection("coasting", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i])
|
||||
BS = BehaviorSection("coasting", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i])
|
||||
drivingCourse[end][:behavior] = BS[:type]
|
||||
|
||||
while !targetSpeedReached && !endOfCSReached && !brakingStartReached
|
||||
|
@ -1010,7 +836,7 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
|
|||
calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings.massModel)
|
||||
|
||||
# acceleration (in m/s^2):
|
||||
drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train.m_train_full, train.ξ_train)
|
||||
drivingCourse[end][:a] = acceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train.m_train_full, train.ξ_train)
|
||||
|
||||
# create the next data point
|
||||
push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, CS[:id]))
|
||||
|
@ -1018,7 +844,7 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
|
|||
push!(BS[:dataPoints], drivingCourse[end][:i])
|
||||
|
||||
# conditions for the next while cycle
|
||||
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking)
|
||||
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
|
||||
brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit]
|
||||
pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1]
|
||||
targetSpeedReached = drivingCourse[end][:v] <= CS[:v_exit] || drivingCourse[end][:v] > CS[:v_peak]
|
||||
|
@ -1043,14 +869,14 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
|
|||
|
||||
elseif drivingCourse[end][:v] < CS[:v_exit] # TODO: if accelereation and coasting functions will be combined this case is only for coasting
|
||||
testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: v=", drivingCourse[end][:v]," < v_exit=", CS[:v_exit]) # for testing
|
||||
if settings.stepVariable == velocity
|
||||
if settings.stepVariable == :velocity
|
||||
currentStepSize = drivingCourse[end-1][:v] - CS[:v_exit]
|
||||
else
|
||||
currentStepSize = settings.stepSize / 10.0^cycle
|
||||
end
|
||||
elseif drivingCourse[end][:v] > CS[:v_peak]
|
||||
testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: v=", drivingCourse[end][:v]," > v_peak=", CS[:v_peak]) # for testing
|
||||
if settings.stepVariable == velocity
|
||||
if settings.stepVariable == :velocity
|
||||
currentStepSize = CS[:v_peak] - drivingCourse[end-1][:v]
|
||||
else
|
||||
currentStepSize = settings.stepSize / 10.0^cycle
|
||||
|
@ -1115,6 +941,11 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
|
|||
end
|
||||
end
|
||||
end #for
|
||||
|
||||
if drivingCourse[end][:s] == nextPointOfInterest[1]
|
||||
drivingCourse[end][:label] = nextPointOfInterest[2]
|
||||
end
|
||||
|
||||
end #while
|
||||
|
||||
stateFlags[:speedLimitReached] = false
|
||||
|
@ -1123,11 +954,9 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
|
|||
merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m)
|
||||
:s_exit => drivingCourse[end][:s], # last position (in m)
|
||||
:t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s)
|
||||
:E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws)
|
||||
:v_exit => drivingCourse[end][:v])) # exit speed (in m/s)))
|
||||
|
||||
CS[:t] = CS[:t] + BS[:t] # total running time (in s)
|
||||
CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws)
|
||||
|
||||
merge!(CS[:behaviorSections], Dict(:coasting=>BS))
|
||||
end
|
||||
|
@ -1152,7 +981,7 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D
|
|||
|
||||
# use the conditions for the braking section
|
||||
if !targetSpeedReached && !endOfCSReached
|
||||
BS = createBehaviorSection("braking", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i])
|
||||
BS = BehaviorSection("braking", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i])
|
||||
drivingCourse[end][:behavior] = BS[:type]
|
||||
|
||||
while !targetSpeedReached && !endOfCSReached
|
||||
|
@ -1168,11 +997,11 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D
|
|||
|
||||
# acceleration (in m/s^2):
|
||||
drivingCourse[end][:a] = train.a_braking
|
||||
# TODO or: drivingCourse[end][:a] = calcBrakingAcceleration(drivingCourse[end][:v], CS[:v_exit], CS[:s_exit]-drivingCourse[end][:s])
|
||||
# TODO or: drivingCourse[end][:a] = brakingAcceleration(drivingCourse[end][:v], CS[:v_exit], CS[:s_exit]-drivingCourse[end][:s])
|
||||
|
||||
if settings.stepVariable == :distance && ((drivingCourse[end][:v]/drivingCourse[end][:a])^2+2*currentStepSize/drivingCourse[end][:a])<0.0 || (drivingCourse[end][:v]^2+2*currentStepSize*drivingCourse[end][:a])<0.0
|
||||
# create empty data point and set it for the values of s_exit and v_exit
|
||||
push!(drivingCourse, createDataPoint())
|
||||
push!(drivingCourse, DataPoint())
|
||||
drivingCourse[end][:i] = drivingCourse[end-1][:i]+1
|
||||
drivingCourse[end][:behavior] = BS[:type]
|
||||
push!(BS[:dataPoints], drivingCourse[end][:i])
|
||||
|
@ -1272,17 +1101,20 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D
|
|||
end
|
||||
end
|
||||
end #for
|
||||
|
||||
if drivingCourse[end][:s] == nextPointOfInterest[1]
|
||||
drivingCourse[end][:label] = nextPointOfInterest[2]
|
||||
end
|
||||
|
||||
end #while
|
||||
|
||||
# calculate the accumulated coasting section information
|
||||
merge!(BS, Dict(:length => drivingCourse[end][:s] - BS[:s_entry], # total length (in m)
|
||||
:s_exit => drivingCourse[end][:s], # last position (in m)
|
||||
:t => drivingCourse[end][:t] - drivingCourse[BS[:dataPoints][1]][:t], # total running time (in s)
|
||||
:E => drivingCourse[end][:E] - drivingCourse[BS[:dataPoints][1]][:E], # total energy consumption (in Ws)
|
||||
:v_exit => drivingCourse[end][:v])) # exit speed (in m/s)))
|
||||
|
||||
CS[:t] = CS[:t] + BS[:t] # total running time (in s)
|
||||
CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws)
|
||||
|
||||
merge!(CS[:behaviorSections], Dict(:braking=>BS))
|
||||
end # else: return the characteristic section without a braking section
|
||||
|
@ -1300,14 +1132,13 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D
|
|||
end #function addBrakingSection!
|
||||
|
||||
|
||||
## This function calculates the data point of the standstill.
|
||||
# Therefore it gets its first data point and the characteristic section and returns the characteristic section including the standstill if needed.
|
||||
function addStandstill!(CS::Dict, drivingCourse::Vector{Dict}, settings::Settings, train::Train, CSs::Vector{Dict})
|
||||
## This function calculates the data point of the halt.
|
||||
# Therefore it gets its first data point and the characteristic section and returns the characteristic section including the halt if needed.
|
||||
function addHalt!(CS::Dict, drivingCourse::Vector{Dict}, settings::Settings, train::Train, CSs::Vector{Dict})
|
||||
if drivingCourse[end][:v] == 0.0
|
||||
BS = createBehaviorSection("standstill", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i])
|
||||
BS = BehaviorSection("standstill", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i])
|
||||
merge!(BS, Dict(:length => 0.0, # total length (in m)
|
||||
:t => 0.0, # total running time (in s)
|
||||
:E => 0.0, # total energy consumption (in Ws)
|
||||
:s_exit => drivingCourse[end][:s], # last position (in m)
|
||||
:v_exit => drivingCourse[end][:v])) # exit speed (in m/s)))
|
||||
drivingCourse[end][:behavior] = BS[:type]
|
||||
|
@ -1315,10 +1146,10 @@ function addStandstill!(CS::Dict, drivingCourse::Vector{Dict}, settings::Setting
|
|||
# traction effort and resisting forces (in N)
|
||||
calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings.massModel)
|
||||
|
||||
merge!(CS[:behaviorSections], Dict(:standstill => BS))
|
||||
end # else: return the characteristic section without a standstillSection section
|
||||
merge!(CS[:behaviorSections], Dict(:halt => BS))
|
||||
end # else: return the characteristic section without a halt section section
|
||||
return (CS, drivingCourse)
|
||||
end #function addStandstill!
|
||||
end #function addHalt!
|
||||
|
||||
function mergeBehaviorSection!(BSs::Dict, BS::Dict)
|
||||
if !haskey(BSs, Symbol(BS[:type]))
|
||||
|
@ -1344,16 +1175,103 @@ function recalculateLastBrakingPoint!(drivingCourse, s_target, v_target)
|
|||
currentPoint[:Δv] = currentPoint[:v] - previousPoint[:v] # step size (in m/s)
|
||||
|
||||
# calculate other values
|
||||
previousPoint[:a] = calcBrakingAcceleration(previousPoint[:v], currentPoint[:v], currentPoint[:Δs])
|
||||
previousPoint[:a] = brakingAcceleration(previousPoint[:v], currentPoint[:v], currentPoint[:Δs])
|
||||
# # TODO: just for testing
|
||||
# if previousPoint[:a]<train.a_braking || previousPoint[:a]>=0.0
|
||||
# println("Warning: a_braking gets to high in CS ",CS[:id], " with a=",previousPoint[:a] ," > ",train.a_braking)
|
||||
# end
|
||||
currentPoint[:Δt] = calc_Δt_with_Δv(currentPoint[:Δv], previousPoint[:a]) # step size (in s)
|
||||
currentPoint[:Δt] = Δt_with_Δv(currentPoint[:Δv], previousPoint[:a]) # step size (in s)
|
||||
currentPoint[:t] = previousPoint[:t] + currentPoint[:Δt] # point in time (in s)
|
||||
|
||||
currentPoint[:ΔW] = 0.0 # mechanical work in this step (in Ws)
|
||||
currentPoint[:W] = previousPoint[:W] + currentPoint[:ΔW] # mechanical work (in Ws)
|
||||
currentPoint[:ΔE] = currentPoint[:ΔW] # energy consumption in this step (in Ws)
|
||||
currentPoint[:E] = previousPoint[:E] + currentPoint[:ΔE] # energy consumption (in Ws)
|
||||
end #function recalculateLastBrakingPoint
|
||||
|
||||
## define the intersection velocities between the characterisitc sections to secure braking behavior
|
||||
function secureBrakingBehavior!(movingSection::Dict, a_braking::Real, approxLevel::Integer)
|
||||
# this function limits the entry and exit velocity of the characteristic sections to secure that the train stops at the moving sections end
|
||||
CSs = movingSection[:characteristicSections]
|
||||
|
||||
csId = length(CSs)
|
||||
followingCSv_entry = 0.0 # the exit velocity of the last characteristic section is 0.0 m/s
|
||||
while csId >= 1
|
||||
CS = CSs[csId]
|
||||
|
||||
CS[:v_exit] = min(CS[:v_limit], followingCSv_entry)
|
||||
|
||||
v_entryMax = brakingStartVelocity(CS[:v_exit], a_braking, CS[:length], approxLevel)
|
||||
|
||||
CS[:v_entry] = min(CS[:v_limit], v_entryMax)
|
||||
CS[:v_peak] = CS[:v_entry]
|
||||
|
||||
|
||||
# reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit
|
||||
CS[:behaviorSections] = Dict()
|
||||
CS[:t] = 0.0
|
||||
|
||||
followingCSv_entry = CS[:v_entry]
|
||||
csId = csId - 1
|
||||
end #while
|
||||
return movingSection
|
||||
end #function secureBrakingBehavior!
|
||||
|
||||
## define the intersection velocities between the characterisitc sections to secure accelerating behavior
|
||||
function secureAcceleratingBehavior!(movingSection::Dict, settings::Settings, train::Train)
|
||||
# this function limits the entry and exit velocity of the characteristic sections in case that the train accelerates in every section and cruises aterwards
|
||||
CSs = movingSection[:characteristicSections]
|
||||
|
||||
CSs[1][:v_entry] = 0.0 # the entry velocity of the first characteristic section is 0.0 m/s
|
||||
startingPoint = DataPoint()
|
||||
startingPoint[:i] = 1
|
||||
|
||||
previousCSv_exit = CSs[1][:v_entry]
|
||||
for CS in CSs
|
||||
CS[:v_entry] = min(CS[:v_entry], previousCSv_exit)
|
||||
startingPoint[:s] = CS[:s_entry]
|
||||
startingPoint[:v] = CS[:v_entry]
|
||||
calculateForces!(startingPoint, CSs, CS[:id], "accelerating", train, settings.massModel) # traction effort and resisting forces (in N)
|
||||
acceleratingCourse::Vector{Dict} = [startingPoint] # List of data points
|
||||
|
||||
if CS[:v_entry] < CS[:v_peak]
|
||||
# conditions for entering the accelerating phase
|
||||
stateFlags = Dict(:endOfCSReached => false,
|
||||
:brakingStartReached => false,
|
||||
:tractionDeficit => false,
|
||||
:resistingForceNegative => false,
|
||||
:previousSpeedLimitReached => false,
|
||||
:speedLimitReached => false,
|
||||
:error => false,
|
||||
:usedForDefiningCharacteristics => true) # because usedForDefiningCharacteristics == true the braking distance will be ignored during securing the accelerating phase
|
||||
v_peak = CS[:v_entry]
|
||||
(CS, acceleratingCourse, stateFlags) = addBreakFreeSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs)
|
||||
while !stateFlags[:speedLimitReached] && !stateFlags[:endOfCSReached]
|
||||
if !stateFlags[:tractionDeficit]
|
||||
if !stateFlags[:previousSpeedLimitReached]
|
||||
(CS, acceleratingCourse, stateFlags) = addAcceleratingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function changes the acceleratingCourse
|
||||
|
||||
elseif stateFlags[:previousSpeedLimitReached]
|
||||
(CS, acceleratingCourse, stateFlags) = addClearingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function is needed in case the train is not allowed to accelerate because of a previous speed limit
|
||||
end
|
||||
else
|
||||
if settings.massModel == :mass_point || acceleratingCourse[end][:s] > CS[:s_entry] + train.length
|
||||
break
|
||||
else
|
||||
(CS, acceleratingCourse, stateFlags) = addDiminishingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function is needed in case the resisitng forces are higher than the maximum possible tractive effort
|
||||
end
|
||||
end
|
||||
v_peak = max(v_peak, acceleratingCourse[end][:v])
|
||||
end
|
||||
|
||||
# CS[:v_peak] = max(CS[:v_entry], acceleratingCourse[end][:v])
|
||||
CS[:v_peak] = v_peak
|
||||
CS[:v_exit] = min(CS[:v_exit], CS[:v_peak], acceleratingCourse[end][:v])
|
||||
else #CS[:v_entry] == CS[:v_peak]
|
||||
# v_exit stays the same
|
||||
end #if
|
||||
|
||||
previousCSv_exit = CS[:v_exit]
|
||||
|
||||
# reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit
|
||||
CS[:behaviorSections] = Dict()
|
||||
CS[:t] = 0.0
|
||||
end #for
|
||||
|
||||
return movingSection
|
||||
end #function secureAcceleratingBehavior!
|
||||
|
|
222
src/calc.jl
222
src/calc.jl
|
@ -1,6 +1,5 @@
|
|||
#!/usr/bin/env julia
|
||||
# -*- coding: UTF-8 -*-
|
||||
# __julia-version__ = 1.7.2
|
||||
# __author__ = "Max Kannenberg"
|
||||
# __copyright__ = "2020-2022"
|
||||
# __license__ = "ISC"
|
||||
|
@ -12,10 +11,10 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t
|
|||
CSs::Vector{Dict} = movingSection[:characteristicSections]
|
||||
|
||||
if settings.massModel == :homogeneous_strip && settings.stepVariable == speed
|
||||
println("WARNING: ! ! ! TrainRun.jl doesn't work reliably for the mass model homogeneous strip with step size v in m/s. The calculation time can be extremely high when calcutlating paths with steep gradients ! ! !")
|
||||
println("WARNING: ! ! ! TrainRuns.jl doesn't work reliably for the mass model homogeneous strip with step size v in m/s. The calculation time can be extremely high when calcutlating paths with steep gradients ! ! !")
|
||||
end
|
||||
|
||||
startingPoint=createDataPoint()
|
||||
startingPoint=DataPoint()
|
||||
startingPoint[:i]=1
|
||||
startingPoint[:s]=CSs[1][:s_entry]
|
||||
calculateForces!(startingPoint, CSs, 1, "default", train, settings.massModel) # traction effort and resisting forces (in N)
|
||||
|
@ -32,7 +31,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t
|
|||
end
|
||||
|
||||
# determine the different flags for switching between the states for creatinge moving phases
|
||||
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking)
|
||||
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
|
||||
calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel) # tractive effort and resisting forces (in N)
|
||||
|
||||
previousSpeedLimitReached = false
|
||||
|
@ -44,7 +43,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t
|
|||
:speedLimitReached => drivingCourse[end][:v] > CS[:v_limit],
|
||||
:error => false)
|
||||
|
||||
# determine the behavior sections for this characteristic section. It has to be at least one of those BS: "breakFree", "clearing", "accelerating", "cruising", "diminishing", "coasting", "braking" or "standstill")
|
||||
# determine the behavior sections for this characteristic section. It has to be at least one of those BS: "breakFree", "clearing", "accelerating", "cruising", "diminishing", "coasting", "braking" or "halt")
|
||||
while !stateFlags[:endOfCSReached] # s < s_exit
|
||||
if !stateFlags[:brakingStartReached] # s+s_braking < s_exit
|
||||
if !stateFlags[:tractionDeficit]
|
||||
|
@ -62,14 +61,14 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t
|
|||
if settings.stepVariable == :distance
|
||||
s_cruising = settings.stepSize
|
||||
elseif settings.stepVariable == time
|
||||
s_cruising = calc_Δs_with_Δt(settings.stepSize, drivingCourse[end][:a], drivingCourse[end][:v])
|
||||
s_cruising = Δs_with_Δt(settings.stepSize, drivingCourse[end][:a], drivingCourse[end][:v])
|
||||
elseif settings.stepVariable == velocity
|
||||
s_cruising = train.length/(10.0) # TODO which step size should be used?
|
||||
end
|
||||
(CS, drivingCourse, stateFlags) = addCruisingSection!(CS, drivingCourse, stateFlags, s_cruising, settings, train, CSs, "cruising")
|
||||
|
||||
elseif drivingCourse[end][:F_R] < 0 && stateFlags[:speedLimitReached]
|
||||
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking)
|
||||
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
|
||||
s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking
|
||||
|
||||
if s_cruising > 0.0
|
||||
|
@ -79,7 +78,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t
|
|||
end
|
||||
|
||||
elseif drivingCourse[end][:F_T] == drivingCourse[end][:F_R] || stateFlags[:speedLimitReached]
|
||||
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking)
|
||||
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
|
||||
s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking
|
||||
|
||||
if s_cruising > 0.0 # TODO: define a minimum cruising length?
|
||||
|
@ -103,7 +102,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t
|
|||
end
|
||||
end
|
||||
#if s == s_exit
|
||||
# standstill
|
||||
# halt
|
||||
#end
|
||||
|
||||
|
||||
|
@ -116,10 +115,211 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t
|
|||
end
|
||||
end #for
|
||||
|
||||
(CSs[end], drivingCourse) = addStandstill!(CSs[end], drivingCourse, settings, train, CSs)
|
||||
(CSs[end], drivingCourse) = addHalt!(CSs[end], drivingCourse, settings, train, CSs)
|
||||
|
||||
movingSection[:t] = drivingCourse[end][:t] # total running time (in s)
|
||||
movingSection[:E] = drivingCourse[end][:E] # total energy consumption (in Ws)
|
||||
|
||||
return (movingSection, drivingCourse)
|
||||
end #function calculateMinimumRunningTime
|
||||
|
||||
|
||||
"""
|
||||
calculateTractiveEffort(v, tractiveEffortVelocityPairs)
|
||||
|
||||
Calculate the trains tractive effort with the `tractiveEffortVelocityPairs` dependend on the velocity `v`.
|
||||
|
||||
...
|
||||
# Arguments
|
||||
- `v::AbstractFloat`: the current velocity in m/s.
|
||||
- `tractiveEffortVelocityPairs::Array{}`: the trains pairs for velocity in m/s and tractive effort in N as one array containing an array for each pair.
|
||||
...
|
||||
|
||||
# Examples
|
||||
```julia-repl
|
||||
julia> calculateTractiveEffort(20.0, [(0.0, 180000), (20.0, 100000), (40.0, 60000), (60.0, 40000), (80.0, 30000)])
|
||||
100000
|
||||
|
||||
julia> calculateTractiveEffort(30.0, [(0.0, 180000), (20.0, 100000), (40.0, 60000), (60.0, 40000), (80.0, 30000)])
|
||||
80000
|
||||
```
|
||||
"""
|
||||
function calculateTractiveEffort(v::AbstractFloat, tractiveEffortVelocityPairs::Array{})
|
||||
if v < 0.0
|
||||
#println("v=",v)
|
||||
return 0.0
|
||||
end
|
||||
|
||||
for row in 1:length(tractiveEffortVelocityPairs)
|
||||
nextPair = tractiveEffortVelocityPairs[row]
|
||||
if nextPair[1] == v
|
||||
return nextPair[2]
|
||||
elseif nextPair[1] > v
|
||||
# interpolate for a straight line between the two surrounding points with the formula: F=(v-v_(row-1))*(F_row-F_(row-1))/(v_row-v_(row-1))+F_(row-1)
|
||||
previousPair = tractiveEffortVelocityPairs[row-1]
|
||||
F_T_interpolation = (v-previousPair[1]) * (nextPair[2]-previousPair[2]) / (nextPair[1]-previousPair[1]) + previousPair[2]
|
||||
return F_T_interpolation
|
||||
end #if
|
||||
end #for
|
||||
# if v gets higher than the velocities in tractiveEffortVelocityPairs the last tractive effort will be used
|
||||
# TODO: also an extrapolation could be used
|
||||
return tractiveEffortVelocityPairs[end][2]
|
||||
end #function calculateTractiveEffort
|
||||
|
||||
|
||||
"""
|
||||
calculate and return the path resistance dependend on the trains position and mass model
|
||||
"""
|
||||
function calculatePathResistance(CSs::Vector{Dict}, csId::Integer, s::Real, massModel, train::Train)
|
||||
|
||||
if massModel == :mass_point
|
||||
pathResistance = forceFromCoefficient(CSs[csId][:r_path], train.m_train_full)
|
||||
elseif massModel == :homogeneous_strip
|
||||
pathResistance = 0.0
|
||||
s_rear = s - train.length # position of the rear of the train
|
||||
while csId > 0 && s_rear < CSs[csId][:s_exit]
|
||||
pathResistance = pathResistance + (min(s, CSs[csId][:s_exit]) - max(s_rear, CSs[csId][:s_entry])) / train.length * forceFromCoefficient(CSs[csId][:r_path], train.m_train_full)
|
||||
csId = csId-1
|
||||
if csId == 0
|
||||
# TODO: currently for values < movingSection[:s_entry] the values of movingSection[:s_entry] will be used
|
||||
return pathResistance + (CSs[1][:s_entry] - s_rear) / train.length * forceFromCoefficient(CSs[1][:r_path], train.m_train_full)
|
||||
end #if
|
||||
end #while
|
||||
end #if
|
||||
|
||||
return pathResistance
|
||||
end #function calculatePathResistance
|
||||
|
||||
|
||||
"""
|
||||
calculate and return tractive and resisting forces for a data point
|
||||
"""
|
||||
function calculateForces!(dataPoint::Dict, CSs::Vector{Dict}, csId::Integer, bsType::String, train::Train, massModel)
|
||||
# calculate resisting forces
|
||||
dataPoint[:R_traction] = tractionUnitResistance(dataPoint[:v], train)
|
||||
if train.transportType == :freight
|
||||
dataPoint[:R_wagons] = freightWagonsResistance(dataPoint[:v], train)
|
||||
elseif train.transportType == :passenger
|
||||
dataPoint[:R_wagons] = passengerWagonsResistance(dataPoint[:v], train)
|
||||
end
|
||||
dataPoint[:R_train] = dataPoint[:R_traction] + dataPoint[:R_wagons]
|
||||
dataPoint[:R_path] = calculatePathResistance(CSs, csId, dataPoint[:s], massModel, train)
|
||||
dataPoint[:F_R] = dataPoint[:R_train] + dataPoint[:R_path]
|
||||
|
||||
# calculate tractive effort
|
||||
if bsType == "braking" || bsType == "coasting" || bsType == "halt"
|
||||
dataPoint[:F_T] = 0.0
|
||||
elseif bsType == "cruising"
|
||||
dataPoint[:F_T] = min(max(0.0, dataPoint[:F_R]), calculateTractiveEffort(dataPoint[:v], train.tractiveEffort))
|
||||
else # bsType == "accelerating" || bsType == "diminishing" || 'default'
|
||||
dataPoint[:F_T] = calculateTractiveEffort(dataPoint[:v], train.tractiveEffort)
|
||||
end
|
||||
|
||||
return dataPoint
|
||||
end #function calculateForces!
|
||||
|
||||
|
||||
"""
|
||||
TODO
|
||||
"""
|
||||
function moveAStep(previousPoint::Dict, stepVariable::Symbol, stepSize::Real, csId::Integer)
|
||||
# stepSize is the currentStepSize depending on the accessing function
|
||||
# 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. =#
|
||||
|
||||
# create the next data point
|
||||
newPoint = DataPoint()
|
||||
newPoint[:i] = previousPoint[:i]+1 # identifier
|
||||
|
||||
# calculate s, t, v, E
|
||||
if stepVariable == :distance # distance step method
|
||||
newPoint[:Δs] = stepSize # step size (in m)
|
||||
if previousPoint[:a] == 0.0
|
||||
if previousPoint[:v] == 0.0
|
||||
error("ERROR: The train tries to cruise at v=0.0 m/s at s=",previousPoint[:s]," in CS",csId,".")
|
||||
end
|
||||
newPoint[:Δt] = Δt_with_constant_v(newPoint[:Δs], previousPoint[:v]) # step size (in s)
|
||||
newPoint[:Δv] = 0.0 # step size (in m/s)
|
||||
else
|
||||
# check if the parts of the following square roots will be <0.0 in the functions Δt_with_Δs and Δv_with_Δs
|
||||
squareRootPartIsNegative = (previousPoint[:v]/previousPoint[:a])^2+2*newPoint[:Δs]/previousPoint[:a] < 0.0 || previousPoint[:v]^2+2*newPoint[:Δs]*previousPoint[:a] < 0.0
|
||||
if previousPoint[:a] < 0.0 && squareRootPartIsNegative
|
||||
error("ERROR: The train stops during the accelerating section in CS",csId," because the tractive effort is lower than the resistant forces.",
|
||||
" Before the stop the last point has the values s=",previousPoint[:s]," m, v=",previousPoint[:v]," m/s, a=",previousPoint[:a]," m/s^2,",
|
||||
" F_T=",previousPoint[:F_T]," N, R_traction=",previousPoint[:R_traction]," N, R_wagons=",previousPoint[:R_wagons]," N, R_path=",previousPoint[:R_path]," N.")
|
||||
end
|
||||
newPoint[:Δt] = Δt_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in s)
|
||||
newPoint[:Δv] = Δv_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in m/s)
|
||||
end
|
||||
|
||||
elseif stepVariable == :time # time step method
|
||||
newPoint[:Δt] = stepSize # step size (in s)
|
||||
newPoint[:Δs] = Δs_with_Δt(newPoint[:Δt], previousPoint[:a], previousPoint[:v]) # step size (in m)
|
||||
newPoint[:Δv] = Δv_with_Δt(newPoint[:Δt], previousPoint[:a]) # step size (in m/s)
|
||||
|
||||
elseif stepVariable == :velocity # velocity step method
|
||||
if previousPoint[:a] == 0.0
|
||||
if previousPoint[:v] == 0.0
|
||||
error("ERROR: The train tries to cruise at v=0.0 m/s at s=",previousPoint[:s]," in CS",csId,".")
|
||||
end
|
||||
newPoint[:Δs] = stepSize # step size (in m)
|
||||
# TODO what is the best default step size for constant v? define Δs or Δt?
|
||||
newPoint[:Δt] = Δt_with_constant_v(newPoint[:Δs], previousPoint[:v]) # step size (in s)
|
||||
newPoint[:Δv] = 0.0 # step size (in m/s)
|
||||
else
|
||||
newPoint[:Δv] = stepSize * sign(previousPoint[:a]) # step size (in m/s)
|
||||
newPoint[:Δs] = Δs_with_Δv(newPoint[:Δv], previousPoint[:a], previousPoint[:v]) # step size (in m)
|
||||
newPoint[:Δt] = Δt_with_Δv(newPoint[:Δv], previousPoint[:a]) # step size (in s)
|
||||
end
|
||||
end #if
|
||||
|
||||
newPoint[:s] = previousPoint[:s] + newPoint[:Δs] # position (in m)
|
||||
newPoint[:t] = previousPoint[:t] + newPoint[:Δt] # point in time (in s)
|
||||
newPoint[:v] = previousPoint[:v] + newPoint[:Δv] # velocity (in m/s)
|
||||
|
||||
return newPoint
|
||||
end #function moveAStep
|
||||
|
||||
|
||||
"""
|
||||
# if the rear of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept
|
||||
"""
|
||||
function getCurrentSpeedLimit(CSs::Vector{Dict}, csWithTrainHeadId::Integer, s::Real, trainLength::Real)
|
||||
v_limit = CSs[csWithTrainHeadId][:v_limit]
|
||||
s_exit = CSs[csWithTrainHeadId][:s_exit]
|
||||
if csWithTrainHeadId > 1 && s -trainLength < CSs[csWithTrainHeadId][:s_entry]
|
||||
formerCsId = csWithTrainHeadId-1
|
||||
while formerCsId > 0 && s -trainLength < CSs[formerCsId][:s_exit]
|
||||
if CSs[formerCsId][:v_limit] < v_limit # TODO: is the position of the train's rear < movingSection[:s_entry], v_limit of the first CS is used
|
||||
v_limit = CSs[formerCsId][:v_limit]
|
||||
s_exit = CSs[formerCsId][:s_exit]
|
||||
end
|
||||
formerCsId = formerCsId -1
|
||||
end
|
||||
end
|
||||
currentSpeedLimit = Dict(:v => v_limit, :s_end => s_exit + trainLength)
|
||||
return currentSpeedLimit
|
||||
end #function getCurrentSpeedLimit
|
||||
|
||||
|
||||
"""
|
||||
TODO
|
||||
"""
|
||||
function getNextPointOfInterest(pointsOfInterest::Vector{Tuple}, s::Real)
|
||||
for POI in pointsOfInterest
|
||||
if POI[1] > s
|
||||
return POI
|
||||
end
|
||||
end
|
||||
error("ERROR in getNextPointOfInterest: There is no POI higher than s=",s," m.")
|
||||
end #function getNextPointOfInterest
|
||||
|
||||
|
||||
## create a moving section and its containing characteristic sections with secured braking, accelerating and cruising behavior
|
||||
function determineCharacteristics(path::Path, train::Train, settings::Settings)
|
||||
movingSection = MovingSection(path, train.v_limit, train.length)
|
||||
movingSection = secureBrakingBehavior!(movingSection, train.a_braking, settings.approxLevel)
|
||||
movingSection = secureAcceleratingBehavior!(movingSection, settings, train)
|
||||
#movingSection = secureCruisingBehavior!(movingSection, settings, train)
|
||||
|
||||
return movingSection
|
||||
end #function determineCharacteristics
|
||||
|
|
|
@ -1,170 +0,0 @@
|
|||
#!/usr/bin/env julia
|
||||
# -*- coding: UTF-8 -*-
|
||||
# __julia-version__ = 1.7.2
|
||||
# __author__ = "Max Kannenberg"
|
||||
# __copyright__ = "2020-2022"
|
||||
# __license__ = "ISC"
|
||||
|
||||
## create a moving section and its containing characteristic sections with secured braking, accelerating and cruising behavior
|
||||
function determineCharacteristics(path::Path, train::Train, settings::Settings)
|
||||
movingSection = createMovingSection(path, train.v_limit, train.length)
|
||||
movingSection = secureBrakingBehavior!(movingSection, train.a_braking)
|
||||
movingSection = secureAcceleratingBehavior!(movingSection, settings, train)
|
||||
#movingSection = secureCruisingBehavior!(movingSection, settings, train)
|
||||
|
||||
return movingSection
|
||||
end #function determineCharacteristics
|
||||
|
||||
## define the intersection velocities between the characterisitc sections to secure braking behavior
|
||||
function secureBrakingBehavior!(movingSection::Dict, a_braking::Real)
|
||||
# this function limits the entry and exit velocity of the characteristic sections to secure that the train stops at the moving sections end
|
||||
CSs = movingSection[:characteristicSections]
|
||||
|
||||
csId = length(CSs)
|
||||
followingCSv_entry = 0.0 # the exit velocity of the last characteristic section is 0.0 m/s
|
||||
while csId >= 1
|
||||
CS = CSs[csId]
|
||||
|
||||
CS[:v_exit] = min(CS[:v_limit], followingCSv_entry)
|
||||
|
||||
v_entryMax = calcBrakingStartVelocity(CS[:v_exit], a_braking, CS[:length])
|
||||
|
||||
CS[:v_entry] = min(CS[:v_limit], v_entryMax)
|
||||
CS[:v_peak] = CS[:v_entry]
|
||||
|
||||
|
||||
# reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit
|
||||
CS[:behaviorSections] = Dict()
|
||||
CS[:E] = 0.0
|
||||
CS[:t] = 0.0
|
||||
|
||||
followingCSv_entry = CS[:v_entry]
|
||||
csId = csId - 1
|
||||
end #while
|
||||
return movingSection
|
||||
end #function secureBrakingBehavior!
|
||||
|
||||
## define the intersection velocities between the characterisitc sections to secure accelerating behavior
|
||||
function secureAcceleratingBehavior!(movingSection::Dict, settings::Settings, train::Train)
|
||||
# this function limits the entry and exit velocity of the characteristic sections in case that the train accelerates in every section and cruises aterwards
|
||||
CSs = movingSection[:characteristicSections]
|
||||
|
||||
CSs[1][:v_entry] = 0.0 # the entry velocity of the first characteristic section is 0.0 m/s
|
||||
startingPoint = createDataPoint()
|
||||
startingPoint[:i] = 1
|
||||
|
||||
previousCSv_exit = CSs[1][:v_entry]
|
||||
for CS in CSs
|
||||
CS[:v_entry] = min(CS[:v_entry], previousCSv_exit)
|
||||
startingPoint[:s] = CS[:s_entry]
|
||||
startingPoint[:v] = CS[:v_entry]
|
||||
calculateForces!(startingPoint, CSs, CS[:id], "accelerating", train, settings.massModel) # traction effort and resisting forces (in N)
|
||||
acceleratingCourse::Vector{Dict} = [startingPoint] # List of data points
|
||||
|
||||
if CS[:v_entry] < CS[:v_peak]
|
||||
# conditions for entering the accelerating phase
|
||||
stateFlags = Dict(:endOfCSReached => false,
|
||||
:brakingStartReached => false,
|
||||
:tractionDeficit => false,
|
||||
:resistingForceNegative => false,
|
||||
:previousSpeedLimitReached => false,
|
||||
:speedLimitReached => false,
|
||||
:error => false,
|
||||
:usedForDefiningCharacteristics => true) # because usedForDefiningCharacteristics == true the braking distance will be ignored during securing the accelerating phase
|
||||
v_peak = CS[:v_entry]
|
||||
(CS, acceleratingCourse, stateFlags) = addBreakFreeSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs)
|
||||
while !stateFlags[:speedLimitReached] && !stateFlags[:endOfCSReached]
|
||||
if !stateFlags[:tractionDeficit]
|
||||
if !stateFlags[:previousSpeedLimitReached]
|
||||
(CS, acceleratingCourse, stateFlags) = addAcceleratingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function changes the acceleratingCourse
|
||||
|
||||
elseif stateFlags[:previousSpeedLimitReached]
|
||||
(CS, acceleratingCourse, stateFlags) = addClearingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function is needed in case the train is not allowed to accelerate because of a previous speed limit
|
||||
end
|
||||
else
|
||||
if settings.massModel == :mass_point || acceleratingCourse[end][:s] > CS[:s_entry] + train.length
|
||||
break
|
||||
else
|
||||
(CS, acceleratingCourse, stateFlags) = addDiminishingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function is needed in case the resisitng forces are higher than the maximum possible tractive effort
|
||||
end
|
||||
end
|
||||
v_peak = max(v_peak, acceleratingCourse[end][:v])
|
||||
end
|
||||
|
||||
# CS[:v_peak] = max(CS[:v_entry], acceleratingCourse[end][:v])
|
||||
CS[:v_peak] = v_peak
|
||||
CS[:v_exit] = min(CS[:v_exit], CS[:v_peak], acceleratingCourse[end][:v])
|
||||
else #CS[:v_entry] == CS[:v_peak]
|
||||
# v_exit stays the same
|
||||
end #if
|
||||
|
||||
previousCSv_exit = CS[:v_exit]
|
||||
|
||||
# reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit
|
||||
CS[:behaviorSections] = Dict()
|
||||
CS[:E] = 0.0
|
||||
CS[:t] = 0.0
|
||||
end #for
|
||||
|
||||
return movingSection
|
||||
end #function secureAcceleratingBehavior!
|
||||
|
||||
|
||||
#=
|
||||
## define the intersection velocities between the characterisitc sections to secure cruising behavior
|
||||
function secureCruisingBehavior!(movingSection::Dict, settings::Settings, train::Train)
|
||||
# limit the exit velocity of the characteristic sections in case that the train cruises in every section at v_peak
|
||||
CSs = movingSection[:characteristicSections]
|
||||
|
||||
startingPoint = createDataPoint()
|
||||
startingPoint[:i] = 1
|
||||
|
||||
previousCSv_exit = CSs[1][:v_entry]
|
||||
|
||||
for CS in CSs
|
||||
# conditions for entering the cruising phase
|
||||
stateFlags = Dict(:endOfCSReached => false,
|
||||
:brakingStartReached => false,
|
||||
:tractionDeficit => false,
|
||||
:resistingForceNegative => false,
|
||||
:previousSpeedLimitReached => false,
|
||||
:speedLimitReached => false,
|
||||
:error => false,
|
||||
:usedForDefiningCharacteristics => true)
|
||||
|
||||
CS[:v_entry] = min(CS[:v_entry], previousCSv_exit)
|
||||
|
||||
startingPoint[:s] = CS[:s_entry]
|
||||
startingPoint[:v] = CS[:v_peak]
|
||||
cruisingCourse::Vector{Dict} = [startingPoint] # List of data points
|
||||
|
||||
while !stateFlags[:endOfCSReached] #&& s_cruising > 0.0
|
||||
if !stateFlags[:tractionDeficit]
|
||||
s_cruising = CS[:s_exit] - cruisingCourse[end][:s]
|
||||
if !stateFlags[:resistingForceNegative]# cruisingCourse[end][:F_R] >= 0
|
||||
(CS, cruisingCourse, stateFlags) = addCruisingSection!(CS, cruisingCourse, stateFlags, s_cruising, settings, train, CSs, "cruising") # this function changes the cruisingCourse
|
||||
else
|
||||
(CS, cruisingCourse, stateFlags) = addCruisingSection!(CS, cruisingCourse, stateFlags, s_cruising, settings, train, CSs, "downhillBraking")
|
||||
end
|
||||
else
|
||||
if settings.massModel == :mass_point || cruisingCourse[end][:s] > CS[:s_entry] + train.length
|
||||
break
|
||||
else
|
||||
(CS, cruisingCourse, stateFlags) = addDiminishingSection!(CS, cruisingCourse, stateFlags, settings, train, CSs) # this function is needed in case the resisitng forces are higher than the maximum possible tractive effort
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
CS[:v_exit] = min(CS[:v_exit], cruisingCourse[end][:v])
|
||||
|
||||
previousCSv_exit = CS[:v_exit]
|
||||
|
||||
# reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit
|
||||
CS[:behaviorSections] = Dict()
|
||||
CS[:E] = 0.0
|
||||
CS[:t] = 0.0
|
||||
end #for
|
||||
|
||||
return movingSection
|
||||
end #function secureCruisingBehavior!
|
||||
=#
|
|
@ -1,6 +1,5 @@
|
|||
#!/usr/bin/env julia
|
||||
# -*- coding: UTF-8 -*-
|
||||
# __julia-version__ = 1.7.2
|
||||
# __author__ = "Martin Scheidt, Max Kannenberg"
|
||||
# __copyright__ = "2022"
|
||||
# __license__ = "ISC"
|
||||
|
@ -52,18 +51,18 @@ function Settings(file="DEFAULT")
|
|||
"outputDetail": {
|
||||
"description": "Selecting the detail of the result",
|
||||
"type": "string",
|
||||
"enum": [ "running_time", "points_of_interest", "driving_course", "everything" ]
|
||||
"enum": [ "running_time", "points_of_interest", "driving_course" ]
|
||||
},
|
||||
"outputFormat": {
|
||||
"description": "Output format",
|
||||
"type": "string",
|
||||
"enum": [ "dataframe", "dict" ]
|
||||
"enum": [ "dataframe", "vector" ]
|
||||
}
|
||||
}
|
||||
}""")
|
||||
|
||||
settings = YAML.load(open(file))["settings"]
|
||||
|
||||
|
||||
## validate the loaded file
|
||||
try
|
||||
validate(schema, settings)
|
||||
|
@ -116,12 +115,12 @@ function Path(file, type = :YAML)
|
|||
data = YAML.load(open(file))
|
||||
if data["schema"] != "https://railtoolkit.org/schema/running-path.json"
|
||||
error("Could not load path file '$file'.\n
|
||||
YAML format is not recognized.
|
||||
YAML format is not recognized.
|
||||
Currently supported: railtoolkit/schema/running-path (2022.05)")
|
||||
end
|
||||
if data["schema_version"] != "2022.05"
|
||||
error("Could not load path file '$file'.\n
|
||||
YAML format is not recognized.
|
||||
YAML format is not recognized.
|
||||
Currently supported: railtoolkit/schema/running-path (2022.05)")
|
||||
end
|
||||
|
||||
|
@ -212,7 +211,7 @@ function Path(file, type = :YAML)
|
|||
validate(railtoolkit_schema, paths)
|
||||
catch err
|
||||
error("Could not load path file '$file'.\n
|
||||
YAML format is not recognized.
|
||||
YAML format is not recognized.
|
||||
Currently supported: railtoolkit/schema/running-path (2022.05)")
|
||||
end
|
||||
if length(paths) > 1
|
||||
|
@ -256,9 +255,9 @@ function Path(file, type = :YAML)
|
|||
sort!(tmp_points, by = x -> x[1])
|
||||
for elem in tmp_points
|
||||
station = elem[1] # first point of the section (in m)
|
||||
label = elem[2] # paths speed limt (in m/s)
|
||||
label = elem[2] # paths speed limt (in m/s)
|
||||
measure = elem[3] # specific path resistance of the section (in ‰)
|
||||
|
||||
|
||||
point = Dict(:station => station,
|
||||
:label => label,
|
||||
:measure => measure)
|
||||
|
@ -302,27 +301,27 @@ function Train(file, type = :YAML)
|
|||
ξ_cars = 1.06 # rotation mass factor
|
||||
transportType = :freight # "freight" or "passenger" for resistance calculation
|
||||
v_limit = 140 # in m/s (default 504 km/h)
|
||||
a_braking = 0 # in m/s^2, todo: implement as function
|
||||
f_Rtd0 = 0 # coefficient for basic resistance due to the traction units driving axles (in ‰)
|
||||
f_Rtc0 = 0 # coefficient for basic resistance due to the traction units carring axles (in ‰)
|
||||
F_Rt2 = 3000 # coefficient for air resistance of the traction units (in N)
|
||||
f_Rw0 = 0 # coefficient for the consists basic resistance (in ‰)
|
||||
f_Rw1 = 0 # coefficient for the consists resistance to rolling (in ‰)
|
||||
f_Rw2 = 0 # coefficient fo the consistsr air resistance (in ‰)
|
||||
a_braking = 0 # in m/s^2, TODO: implement as function
|
||||
f_Rtd0 = 0 # coefficient for basic resistance due to the traction unit's driving axles (in ‰)
|
||||
f_Rtc0 = 0 # coefficient for basic resistance due to the traction unit's carring axles (in ‰)
|
||||
f_Rt2 = 0 # coefficient for air resistance of the traction unit (in ‰)
|
||||
f_Rw0 = 0 # coefficient for the consist's basic resistance (in ‰)
|
||||
f_Rw1 = 0 # coefficient for the consist's resistance to rolling (in ‰)
|
||||
f_Rw2 = 0 # coefficient for the consist's air resistance (in ‰)
|
||||
F_v_pairs = [] # [v in m/s, F_T in N]
|
||||
|
||||
## load from file
|
||||
if type == :YAML
|
||||
|
||||
data = YAML.load(open(file))
|
||||
if data["schema"] != "https://railtoolkit.org/schema/rolling-stock.json"
|
||||
if data["schema"] != "https://railtoolkit.org/schema/rolling-stock.json"
|
||||
error("Could not load path file '$file'.\n
|
||||
YAML format is not recognized.
|
||||
YAML format is not recognized.
|
||||
Currently supported: railtoolkit/schema/rolling-stock (2022.05)")
|
||||
end
|
||||
if data["schema_version"] != "2022.05"
|
||||
error("Could not load path file '$file'.\n
|
||||
YAML format is not recognized.
|
||||
YAML format is not recognized.
|
||||
Currently supported: railtoolkit/schema/rolling-stock (2022.05)")
|
||||
end
|
||||
|
||||
|
@ -472,14 +471,14 @@ function Train(file, type = :YAML)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}""")
|
||||
|
||||
try
|
||||
validate(railtoolkit_schema, data)
|
||||
catch err
|
||||
error("Could not load path file '$file'.\n
|
||||
YAML format is not recognized.
|
||||
YAML format is not recognized.
|
||||
Currently supported: railtoolkit/schema/rolling-stock (2022.05)")
|
||||
end
|
||||
|
||||
|
@ -514,12 +513,13 @@ function Train(file, type = :YAML)
|
|||
push!(vehicles, (data=vehicle, n=n, propulsion=propulsion) )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
## set the variables in "train"
|
||||
name = train["name"]
|
||||
id = train["id"]
|
||||
haskey(train, "UUID") ? uuid = parse(UUID, train["UUID"] ) : nothing
|
||||
transportType == :freight ? a_braking = -0.225 : a_braking = -0.375 # set a default a_braking value depending on the train type
|
||||
#TODO: add source: Brünger, Dahlhaus, 2014 p. 74 (see formulary.jl)
|
||||
|
||||
## set the variables for all vehicles
|
||||
for vehicle in vehicles
|
||||
|
@ -529,8 +529,8 @@ function Train(file, type = :YAML)
|
|||
haskey(vehicle.data, "load_limit") ?
|
||||
m_train_full += vehicle.data["load_limit"] * vehicle.n * 1000 : # in kg
|
||||
nothing
|
||||
haskey(vehicle.data, "speed_limit") ?
|
||||
v_limit > vehicle.data["speed_limit"]/3.6 ? v_limit = vehicle.data["speed_limit"]/3.6 : nothing :
|
||||
haskey(vehicle.data, "speed_limit") ?
|
||||
v_limit > vehicle.data["speed_limit"]/3.6 ? v_limit = vehicle.data["speed_limit"]/3.6 : nothing :
|
||||
nothing
|
||||
end
|
||||
|
||||
|
@ -553,7 +553,7 @@ function Train(file, type = :YAML)
|
|||
haskey(loco, "a_braking") ? a_braking = loco["a_braking"] : nothing
|
||||
haskey(loco, "base_resistance") ? f_Rtd0 = loco["base_resistance"] : nothing
|
||||
haskey(loco, "rolling_resistance") ? f_Rtc0 = loco["rolling_resistance"] : nothing
|
||||
haskey(loco, "air_resistance") ? F_Rt2 = loco["air_resistance"] * g * m_loco : nothing
|
||||
haskey(loco, "air_resistance") ? f_Rt2 = loco["air_resistance"] : nothing
|
||||
haskey(loco, "mass_traction") ? m_td = loco["mass_traction"] * 1000 : m_td = m_t
|
||||
haskey(loco, "rotation_mass") ? ξ_loco = loco["rotation_mass"] : nothing
|
||||
m_tc = m_loco- m_td
|
||||
|
@ -569,17 +569,17 @@ function Train(file, type = :YAML)
|
|||
resis_air = []
|
||||
rotMassFac = []
|
||||
for car in cars
|
||||
haskey(car.data, "base_resistance") ?
|
||||
append!(resis_base,repeat([car.data["base_resistance"]],car.n)) :
|
||||
haskey(car.data, "base_resistance") ?
|
||||
append!(resis_base,repeat([car.data["base_resistance"]],car.n)) :
|
||||
append!(resis_base,repeat([f_Rw0],car.n))
|
||||
haskey(car.data, "rolling_resistance") ?
|
||||
append!(resis_roll,repeat([car.data["rolling_resistance"]],car.n)) :
|
||||
haskey(car.data, "rolling_resistance") ?
|
||||
append!(resis_roll,repeat([car.data["rolling_resistance"]],car.n)) :
|
||||
append!(resis_roll,repeat([f_Rw1],car.n))
|
||||
haskey(car.data, "air_resistance") ?
|
||||
append!(resis_air,repeat([car.data["air_resistance"]],car.n)) :
|
||||
haskey(car.data, "air_resistance") ?
|
||||
append!(resis_air,repeat([car.data["air_resistance"]],car.n)) :
|
||||
append!(resis_air, repeat([f_Rw2],car.n))
|
||||
haskey(car.data, "rotation_mass") ?
|
||||
append!(rotMassFac,repeat([(car.data["rotation_mass"],car.data["mass"])],car.n)) :
|
||||
append!(rotMassFac,repeat([(car.data["rotation_mass"],car.data["mass"])],car.n)) :
|
||||
append!(rotMassFac,repeat([(ξ_cars ,car.data["mass"])],car.n))
|
||||
m_car_empty += car.data["mass"] * car.n * 1000 # in kg
|
||||
m_car_full += car.data["mass"] * car.n * 1000 # in kg
|
||||
|
@ -607,20 +607,33 @@ function Train(file, type = :YAML)
|
|||
ξ_train, ξ_loco, ξ_cars,
|
||||
transportType, v_limit,
|
||||
a_braking,
|
||||
f_Rtd0, f_Rtc0, F_Rt2, f_Rw0, f_Rw1, f_Rw2,
|
||||
f_Rtd0, f_Rtc0, f_Rt2, f_Rw0, f_Rw1, f_Rw2,
|
||||
F_v_pairs
|
||||
)
|
||||
|
||||
end #function Train() # outer constructor
|
||||
|
||||
## create a moving section containing characteristic sections
|
||||
function createMovingSection(path::Path, v_trainLimit::Real, s_trainLength::Real)
|
||||
function MovingSection(path::Path, v_trainLimit::Real, s_trainLength::Real)
|
||||
# this function creates and returns a moving section dependent on the paths attributes
|
||||
|
||||
s_entry = path.sections[1][:s_start] # first position (in m)
|
||||
s_exit = path.sections[end][:s_end] # last position (in m)
|
||||
pathLength = s_exit - s_entry # total length (in m)
|
||||
|
||||
##TODO: use a tuple with naming
|
||||
pointsOfInterest = Tuple[]
|
||||
if !isempty(path.poi)
|
||||
for POI in path.poi
|
||||
s_poi = POI[:station]
|
||||
if POI[:measure] == "rear"
|
||||
s_poi += s_trainLength
|
||||
end
|
||||
push!(pointsOfInterest, (s_poi, POI[:label]) )
|
||||
end
|
||||
sort!(pointsOfInterest, by = x -> x[1])
|
||||
end
|
||||
|
||||
CSs=Vector{Dict}()
|
||||
s_csStart=s_entry
|
||||
csId=1
|
||||
|
@ -630,27 +643,26 @@ function createMovingSection(path::Path, v_trainLimit::Real, s_trainLength::Real
|
|||
speedLimitIsDifferent = min(previousSection[:v_limit], v_trainLimit) != min(currentSection[:v_limit], v_trainLimit)
|
||||
pathResistanceIsDifferent = previousSection[:f_Rp] != currentSection[:f_Rp]
|
||||
if speedLimitIsDifferent || pathResistanceIsDifferent
|
||||
# 03/09 old: if min(previousSection[:v_limit], v_trainLimit) != min(currentSection[:v_limit], v_trainLimit) || previousSection[:f_Rp] != currentSection[:f_Rp]
|
||||
push!(CSs, createCharacteristicSection(csId, s_csStart, previousSection, min(previousSection[:v_limit], v_trainLimit), s_trainLength, path))
|
||||
push!(CSs, CharacteristicSection(csId, s_csStart, previousSection, min(previousSection[:v_limit], v_trainLimit), s_trainLength, pointsOfInterest))
|
||||
s_csStart = currentSection[:s_start]
|
||||
csId = csId+1
|
||||
end #if
|
||||
end #for
|
||||
push!(CSs, createCharacteristicSection(csId, s_csStart, path.sections[end], min(path.sections[end][:v_limit], v_trainLimit), s_trainLength, path))
|
||||
push!(CSs, CharacteristicSection(csId, s_csStart, path.sections[end], min(path.sections[end][:v_limit], v_trainLimit), s_trainLength, pointsOfInterest))
|
||||
|
||||
movingSection= Dict(:id => 1, # identifier # if there is more than one moving section in a later version of this tool the id should not be constant anymore
|
||||
:length => pathLength, # total length (in m)
|
||||
:s_entry => s_entry, # first position (in m)
|
||||
:s_exit => s_exit, # last position (in m)
|
||||
:t => 0.0, # total running time (in s)
|
||||
:E => 0.0, # total energy consumption (in Ws)
|
||||
:characteristicSections => CSs) # list of containing characteristic sections
|
||||
:characteristicSections => CSs, # list of containing characteristic sections
|
||||
:pointsOfInterest => pointsOfInterest) # list of containing points of interest
|
||||
|
||||
return movingSection
|
||||
end #function createMovingSection
|
||||
end #function MovingSection
|
||||
|
||||
## create a characteristic section for a path section. A characteristic section is a part of the moving section. It contains behavior sections.
|
||||
function createCharacteristicSection(id::Integer, s_entry::Real, section::Dict, v_limit::Real, s_trainLength::Real, path::Path)
|
||||
function CharacteristicSection(id::Integer, s_entry::Real, section::Dict, v_limit::Real, s_trainLength::Real, MS_poi::Vector{Tuple})
|
||||
# Create and return a characteristic section dependent on the paths attributes
|
||||
characteristicSection= Dict(:id => id, # identifier
|
||||
:s_entry => s_entry, # first position (in m)
|
||||
|
@ -659,7 +671,6 @@ function createCharacteristicSection(id::Integer, s_entry::Real, section::Dict,
|
|||
:r_path => section[:f_Rp], # path resistance (in ‰)
|
||||
:behaviorSections => Dict(), # list of containing behavior sections
|
||||
:t => 0.0, # total running time (in s)
|
||||
:E => 0.0, # total energy consumption (in Ws)
|
||||
:v_limit => v_limit, # speed limit (in m/s)
|
||||
# initializing :v_entry, :v_peak and :v_exit with :v_limit
|
||||
:v_peak => v_limit, # maximum reachable speed (in m/s)
|
||||
|
@ -671,34 +682,47 @@ function createCharacteristicSection(id::Integer, s_entry::Real, section::Dict,
|
|||
|
||||
##TODO: use a tuple with naming
|
||||
pointsOfInterest = Tuple[]
|
||||
# pointsOfInterest = Real[]
|
||||
if !isempty(path.poi)
|
||||
for POI in path.poi
|
||||
s_poi = POI[:station]
|
||||
if POI[:measure] == "rear"
|
||||
s_poi -= s_trainLength
|
||||
end
|
||||
if s_entry < s_poi && s_poi < s_exit
|
||||
push!(pointsOfInterest, (s_poi, POI[:label]) )
|
||||
# push!(pointsOfInterest, s_poi )
|
||||
if !isempty(MS_poi)
|
||||
for POI in MS_poi
|
||||
s_poi = POI[1]
|
||||
if s_entry < s_poi && s_poi <= s_exit
|
||||
push!(pointsOfInterest, (POI))
|
||||
end
|
||||
end
|
||||
end
|
||||
push!(pointsOfInterest, (s_exit,"")) # s_exit has to be the last POI so that there will always be a POI to campare the current position with
|
||||
# push!(pointsOfInterest, s_exit) # s_exit has to be the last POI so that there will always be a POI to campare the current position with
|
||||
|
||||
if isempty(pointsOfInterest) || pointsOfInterest[end][1] < s_exit
|
||||
push!(pointsOfInterest, (s_exit,"")) # s_exit has to be the last POI so that there will always be a POI to campare the current position with
|
||||
end
|
||||
merge!(characteristicSection, Dict(:pointsOfInterest => pointsOfInterest))
|
||||
|
||||
return characteristicSection
|
||||
end #function createCharacteristicSection
|
||||
end #function CharacteristicSection
|
||||
|
||||
"""
|
||||
BehaviorSection() TODO!
|
||||
"""
|
||||
function BehaviorSection(type::String, s_entry::Real, v_entry::Real, startingPoint::Integer)
|
||||
BS= Dict(
|
||||
:type => type, # type of behavior section: "breakFree", "clearing", "accelerating", "cruising", "downhillBraking", "diminishing", "coasting", "braking" or "standstill"
|
||||
:length => 0.0, # total length (in m)
|
||||
:s_entry => s_entry, # first position (in m)
|
||||
:s_exit => 0.0, # last position (in m)
|
||||
:t => 0.0, # total running time (in s)
|
||||
:E => 0.0, # total energy consumption (in Ws)
|
||||
:v_entry => v_entry, # entry speed (in m/s)
|
||||
:v_exit => 0.0, # exit speed (in m/s)
|
||||
:dataPoints => [startingPoint] # list of identifiers of the containing data points starting with the initial point
|
||||
)
|
||||
return BS
|
||||
end #function BehaviorSection
|
||||
|
||||
"""
|
||||
a DataPoint is the smallest element of the driving course. One step of the step approach is between two data points
|
||||
"""
|
||||
function createDataPoint()
|
||||
function DataPoint()
|
||||
dataPoint = Dict(
|
||||
:i => 0, # identifier and counter variable of the driving course
|
||||
:behavior => "", # type of behavior section the data point is part of - see createBehaviorSection()
|
||||
:behavior => "", # type of behavior section the data point is part of - see BehaviorSection()
|
||||
# a data point which is the last point of one behavior section and the first point of the next behavior section will be attached to the latter
|
||||
:s => 0.0, # position (in m)
|
||||
:Δs => 0.0, # step size (in m)
|
||||
|
@ -717,25 +741,7 @@ function createDataPoint()
|
|||
:R_train => 0.0, # train resistance (in N)
|
||||
:R_traction => 0.0, # traction unit resistance (in N)
|
||||
:R_wagons => 0.0, # set of wagons resistance (in N)
|
||||
:label => "" # a label for importend points
|
||||
:label => "" # a label for important points
|
||||
)
|
||||
return dataPoint
|
||||
end #function createDataPoint
|
||||
|
||||
"""
|
||||
BehaviorSection() TODO!
|
||||
"""
|
||||
function createBehaviorSection(type::String, s_entry::Real, v_entry::Real, startingPoint::Integer)
|
||||
BS= Dict(
|
||||
:type => type, # type of behavior section: "breakFree", "clearing", "accelerating", "cruising", "downhillBraking", "diminishing", "coasting", "braking" or "standstill"
|
||||
:length => 0.0, # total length (in m)
|
||||
:s_entry => s_entry, # first position (in m)
|
||||
:s_exit => 0.0, # last position (in m)
|
||||
:t => 0.0, # total running time (in s)
|
||||
:E => 0.0, # total energy consumption (in Ws)
|
||||
:v_entry => v_entry, # entry speed (in m/s)
|
||||
:v_exit => 0.0, # exit speed (in m/s)
|
||||
:dataPoints => [startingPoint] # list of identifiers of the containing data points starting with the initial point
|
||||
)
|
||||
return BS
|
||||
end #function createBehaviorSection
|
||||
end #function DataPoint
|
||||
|
|
121
src/formulary.jl
121
src/formulary.jl
|
@ -1,6 +1,5 @@
|
|||
#!/usr/bin/env julia
|
||||
# -*- coding: UTF-8 -*-
|
||||
# __julia-version__ = 1.7.2
|
||||
# __author__ = "Max Kannenberg"
|
||||
# __copyright__ = "2022"
|
||||
# __license__ = "ISC"
|
||||
|
@ -28,14 +27,14 @@
|
|||
## }
|
||||
#########################
|
||||
|
||||
approxLevel = 6
|
||||
#approxLevel = 6
|
||||
v00 = 100/3.6 # velocity factor (in m/s)
|
||||
|
||||
## calculate forces
|
||||
|
||||
#TODO: replace the ? ? ?
|
||||
"""
|
||||
calcTractionUnitResistance(v, train)
|
||||
tractionUnitResistance(v, train)
|
||||
|
||||
Calculate the vehicle resistance for the traction unit of the `train` dependend on the velocity `v`.
|
||||
|
||||
|
@ -47,42 +46,59 @@ Calculate the vehicle resistance for the traction unit of the `train` dependend
|
|||
|
||||
# Examples
|
||||
```julia-repl
|
||||
julia> calcTractionUnitResistance(30.0, ? ? ?)
|
||||
julia> tractionUnitResistance(30.0, ? ? ?)
|
||||
? ? ?
|
||||
```
|
||||
"""
|
||||
function calcTractionUnitResistance(v::AbstractFloat, train::Train)
|
||||
function tractionUnitResistance(v::AbstractFloat, train::Train)
|
||||
# equation is based on [Wende:2003, page 151]
|
||||
f_Rtd0 = train.f_Rtd0 # coefficient for basic resistance due to the traction units driving axles (in ‰)
|
||||
f_Rtc0 = train.f_Rtc0 # coefficient for basic resistance due to the traction units carring axles (in ‰)
|
||||
F_Rt2 = train.F_Rt2 # coefficient for air resistance of the traction units (in N)
|
||||
f_Rt2 = train.f_Rt2 # coefficient for air resistance of the traction unit (in ‰)
|
||||
m_td = train.m_td # mass on the traction unit's driving axles (in kg)
|
||||
m_tc = train.m_tc # mass on the traction unit's carrying axles (in kg)
|
||||
|
||||
F_R_tractionUnit = f_Rtd0/1000 * m_td * g + f_Rtc0/1000 * m_tc * g + F_Rt2 * ((v + Δv_air) /v00)^2 # vehicle resistance of the traction unit (in N) # /1000 because of the unit ‰
|
||||
# TODO: use calcForceFromCoefficient? F_R_tractionUnit = calcForceFromCoefficient(f_Rtd0, m_td) + calcForceFromCoefficient(f_Rtc0, m_tc) + F_Rt2 * ((v + Δv_air) /v00)^2 # vehicle resistance of the traction unit (in N)
|
||||
|
||||
F_R_tractionUnit = f_Rtd0/1000 * m_td * g + f_Rtc0/1000 * m_tc * g + f_Rt2/1000 * (m_td+m_tc) * g * ((v + Δv_air) /v00)^2 # vehicle resistance of the traction unit (in N) # /1000 because of the unit ‰
|
||||
# TODO: use forceFromCoefficient? F_R_tractionUnit = forceFromCoefficient(f_Rtd0, m_td) + forceFromCoefficient(f_Rtc0, m_tc) + forceFromCoefficient(f_Rt2, m_td+m_tc) * ((v + Δv_air) /v00)^2 # vehicle resistance of the traction unit (in N)
|
||||
return F_R_tractionUnit
|
||||
#TODO: same variable name like in the rest of the tool? return R_traction
|
||||
#TODO: just one line? return train.f_Rtd0/1000*train.m_td*g+train.f_Rtc0/1000*train.m_tc*g+train.F_Rt2*((v+train.Δv_air)/v00)^2 # /1000 because of the unit ‰
|
||||
end #function calcTractionUnitResistance
|
||||
#TODO: same variable name like in the rest of TrainRuns? return R_traction
|
||||
end #function tractionUnitResistance
|
||||
|
||||
"""
|
||||
TODO
|
||||
calculate and return the wagons vehicle resistance dependend on the velocity
|
||||
calculate and return the freight wagons' vehicle resistance dependend on the velocity
|
||||
"""
|
||||
function calcWagonsResistance(v::AbstractFloat, train::Train)
|
||||
# equation is based on a combination of the equations of Strahl and Sauthoff [Wende:2003, page 153] with more detailled factors (Lehmann, page 135)
|
||||
function freightWagonsResistance(v::AbstractFloat, train::Train)
|
||||
# equation is based on a combination of the equations of Strahl and Sauthoff [Wende:2003, page 153]
|
||||
f_Rw0 = train.f_Rw0 # coefficient for basic resistance of the set of wagons (consist) (in ‰)
|
||||
f_Rw2 = train.f_Rw2 # coefficient fo the consistsr air resistance (in ‰)
|
||||
m_w = train.m_w # mass of the set of wagons (consist) (in kg)
|
||||
|
||||
F_R_wagons = m_w *g *(f_Rw0/1000 + f_Rw2/1000 * (v /v00)^2) # vehicle resistance of freight wagons (in N) with Strahl # /1000 because of the unit ‰
|
||||
|
||||
# TODO: use forceFromCoefficient? F_R_wagons = forceFromCoefficient(f_Rw0, m_w) + ...
|
||||
return F_R_wagons
|
||||
end #function calcWagonsResistance
|
||||
|
||||
"""
|
||||
TODO
|
||||
calculate and return the passenger wagons' vehicle resistance dependend on the velocity
|
||||
"""
|
||||
function passengerWagonsResistance(v::AbstractFloat, train::Train)
|
||||
# equation is based on the equations of Sauthoff [Wende:2003, page 153]
|
||||
f_Rw0 = train.f_Rw0 # coefficient for basic resistance of the set of wagons (consist) (in ‰)
|
||||
f_Rw1 = train.f_Rw1 # coefficient for the consists resistance to rolling (in ‰)
|
||||
f_Rw2 = train.f_Rw2 # coefficient fo the consistsr air resistance (in ‰)
|
||||
m_w = train.m_w # mass of the set of wagons (consist) (in kg)
|
||||
|
||||
F_R_wagons = m_w *g *(f_Rw0/1000 + f_Rw1/1000 *v /v00 + f_Rw2/1000 * ((v + Δv_air) /v00)^2) # vehicle resistance of the wagons (in N) # /1000 because of the unit ‰
|
||||
# TODO: use calcForceFromCoefficient? F_R_wagons = calcForceFromCoefficient(f_Rw0, m_w) + calcForceFromCoefficient(f_Rw1, m_w) *v /v00 + calcForceFromCoefficient(f_Rw2, m_w) * ((v + Δv_air) /v00)^2 # vehicle resistance of the wagons (in N)
|
||||
F_R_wagons = m_w *g *(f_Rw0/1000 + f_Rw1/1000 *v /v00 + f_Rw2/1000 * ((v + Δv_air) /v00)^2) # vehicle resistance of passenger wagons (in N) with Sauthoff # /1000 because of the unit ‰
|
||||
|
||||
# TODO: use forceFromCoefficient? F_R_wagons = forceFromCoefficient(f_Rw0, m_w) + ...
|
||||
return F_R_wagons
|
||||
end #function calcWagonsResistance
|
||||
|
||||
function calcForceFromCoefficient(f_R::Real, m::Real)
|
||||
function forceFromCoefficient(f_R::Real, m::Real)
|
||||
# equation is based on [Wende:2003, page 8]
|
||||
|
||||
# f_R: specific resistance (in ‰)
|
||||
|
@ -90,9 +106,9 @@ function calcForceFromCoefficient(f_R::Real, m::Real)
|
|||
|
||||
F_R = f_R /1000 *m *g # Resisting Force (in N) # /1000 because of the unit ‰
|
||||
return F_R
|
||||
end #function calcForceFromCoefficient
|
||||
end #function forceFromCoefficient
|
||||
|
||||
function calcAcceleration(F_T::Real, F_R::Real, m_train::Real, ξ_train::Real)
|
||||
function acceleration(F_T::Real, F_R::Real, m_train::Real, ξ_train::Real)
|
||||
# equation is based on [Bruenger:2014, page 72] with a=dv/dt
|
||||
|
||||
# F_T: tractive effort (in N)
|
||||
|
@ -102,9 +118,9 @@ function calcAcceleration(F_T::Real, F_R::Real, m_train::Real, ξ_train::Real)
|
|||
|
||||
a = (F_T - F_R) /m_train /ξ_train # acceleration (in m/s)
|
||||
return a
|
||||
end #function calcAcceleration
|
||||
end #function acceleration
|
||||
|
||||
function calc_Δs_with_Δt(Δt::Real, a_prev::Real, v_prev::Real)
|
||||
function Δs_with_Δt(Δt::Real, a_prev::Real, v_prev::Real)
|
||||
# equation is based on [Wende:2003, page 37]
|
||||
|
||||
# Δt: time step (in s)
|
||||
|
@ -112,9 +128,9 @@ function calc_Δs_with_Δt(Δt::Real, a_prev::Real, v_prev::Real)
|
|||
# v_prev: velocitiy from previous data point
|
||||
Δs = Δt * (2*v_prev + Δt*a_prev) /2 # step size (in m)
|
||||
return Δs
|
||||
end #function calc_Δs_with_Δt
|
||||
end #function Δs_with_Δt
|
||||
|
||||
function calc_Δs_with_Δv(Δv::Real, a_prev::Real, v_prev::Real)
|
||||
function Δs_with_Δv(Δv::Real, a_prev::Real, v_prev::Real)
|
||||
# equation is based on [Wende:2003, page 37]
|
||||
|
||||
# Δv: velocity step (in m/s)
|
||||
|
@ -122,9 +138,9 @@ function calc_Δs_with_Δv(Δv::Real, a_prev::Real, v_prev::Real)
|
|||
# v_prev: velocitiy from previous data point
|
||||
Δs = ((v_prev + Δv)^2 - v_prev^2)/2/a_prev # step size (in m)
|
||||
return Δs
|
||||
end #function calc_Δs_with_Δv
|
||||
end #function Δs_with_Δv
|
||||
|
||||
function calc_Δt_with_Δs(Δs::Real, a_prev::Real, v_prev::Real)
|
||||
function Δt_with_Δs(Δs::Real, a_prev::Real, v_prev::Real)
|
||||
# equation is based on [Wende:2003, page 37]
|
||||
|
||||
# Δs: distance step (in m)
|
||||
|
@ -133,27 +149,27 @@ function calc_Δt_with_Δs(Δs::Real, a_prev::Real, v_prev::Real)
|
|||
|
||||
Δt = sign(a_prev) *sqrt((v_prev /a_prev)^2 + 2 *Δs /a_prev) - v_prev /a_prev # step size (in m/s)
|
||||
return Δt
|
||||
end #function calc_Δt_with_Δs
|
||||
end #function Δt_with_Δs
|
||||
|
||||
function calc_Δt_with_Δv(Δv::Real, a_prev::Real)
|
||||
function Δt_with_Δv(Δv::Real, a_prev::Real)
|
||||
# equation is based on [Wende:2003, page 37]
|
||||
|
||||
# Δv: velocity step (in m/s)
|
||||
# a_prev: acceleration from previous data point
|
||||
Δt = Δv /a_prev # step size (in s)
|
||||
return Δt
|
||||
end #function calc_Δt_with_Δv
|
||||
end #function Δt_with_Δv
|
||||
|
||||
function calc_Δt_with_constant_v(Δs::Real, v::Real)
|
||||
function Δt_with_constant_v(Δs::Real, v::Real)
|
||||
# equation is based on [Wende:2003, page 37]
|
||||
|
||||
# Δs: distance step (in m)
|
||||
# v: constant velocity (in m/s)
|
||||
Δt = Δs /v # step size (in s)
|
||||
return Δt
|
||||
end #function calc_Δt_with_constant_v
|
||||
end #function Δt_with_constant_v
|
||||
|
||||
function calc_Δv_with_Δs(Δs::Real, a_prev::Real, v_prev::Real)
|
||||
function Δv_with_Δs(Δs::Real, a_prev::Real, v_prev::Real)
|
||||
# equation is based on [Wende:2003, page 37]
|
||||
|
||||
# Δs: distance step (in m)
|
||||
|
@ -161,58 +177,41 @@ function calc_Δv_with_Δs(Δs::Real, a_prev::Real, v_prev::Real)
|
|||
# v_prev: velocitiy from previous data point
|
||||
Δv = sqrt(v_prev^2 + 2*Δs*a_prev) - v_prev # step size (in m/s)
|
||||
return Δv
|
||||
end #function calc_Δv_with_Δs
|
||||
end #function Δv_with_Δs
|
||||
|
||||
function calc_Δv_with_Δt(Δt::Real, a_prev::Real)
|
||||
function Δv_with_Δt(Δt::Real, a_prev::Real)
|
||||
# equation is based on [Wende:2003, page 37]
|
||||
|
||||
# Δt: time step (in s)
|
||||
# a_prev: acceleration from previous data point
|
||||
Δv = Δt * a_prev # step size (in m/s)
|
||||
return Δv
|
||||
end #function calc_Δv_with_Δt
|
||||
end #function Δv_with_Δt
|
||||
|
||||
function calc_ΔW(F_T_prev::Real, Δs::Real)
|
||||
# equation is based on [Wende:2003, page 17]
|
||||
|
||||
# F_T_prev: tractive force from previous data point
|
||||
# Δs: distance step
|
||||
ΔW = F_T_prev * Δs # mechanical work in this step (in Ws)
|
||||
return ΔW
|
||||
end #function calc_ΔW
|
||||
|
||||
function calc_ΔE(ΔW::Real)
|
||||
# simplified equation
|
||||
# TODO!
|
||||
# ΔW: mechanical work in this step (in Ws)
|
||||
ΔE = ΔW # energy consumption in this step (in Ws)
|
||||
return ΔE
|
||||
end #function calc_ΔW
|
||||
|
||||
function calcBrakingDistance(v_start::Real, v_end::Real, a_braking::Real)
|
||||
function brakingDistance(v_start::Real, v_end::Real, a_braking::Real, approxLevel::Integer)
|
||||
# equation is based on [Wende:2003, page 37]
|
||||
|
||||
# v_start: velocity at the start of braking (in m/s)
|
||||
# v_end: target velocity at the end of braking (in m/s)
|
||||
# a_braking: constant braking acceleration (in m/s^2)
|
||||
s_braking = (v_end^2 - v_start^2) /2 /a_braking # braking distance (in m)
|
||||
# TODO: also possible: calc_Δs_with_Δv(v_end-v_start, a_braking, v_start)
|
||||
# TODO: also possible: Δs_with_Δv(v_end-v_start, a_braking, v_start)
|
||||
# return max(0.0, ceil(s_braking, digits=approxLevel)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors
|
||||
return max(0.0, ceil(s_braking, digits=approxLevel +1)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors
|
||||
end #function calcBrakingDistance
|
||||
return max(0.0, ceil(s_braking, digits= approxLevel +1)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors
|
||||
end #function brakingDistance
|
||||
|
||||
function calcBrakingStartVelocity(v_end::Real, a_braking::Real, s_braking::Real)
|
||||
function brakingStartVelocity(v_end::Real, a_braking::Real, s_braking::Real, approxLevel::Integer)
|
||||
# equation is based on [Wende:2003, page 37]
|
||||
|
||||
# v_end: target velocity at the end of braking (in m/s)
|
||||
# a_braking: constant braking acceleration (in m/s^2)
|
||||
# s_braking: braking distance (in Ws)
|
||||
v_start = sqrt(v_end^2 - 2*a_braking *s_braking) # braking start velocity (in m/s)
|
||||
# return floor(v_start, digits=approxLevel)
|
||||
return floor(v_start, digits=approxLevel +1)
|
||||
end #function calcBrakingStartVelocity
|
||||
# return floor(v_start, digits= approxLevel)
|
||||
return floor(v_start, digits= approxLevel +1)
|
||||
end #function brakingStartVelocity
|
||||
|
||||
function calcBrakingAcceleration(v_start::Real, v_end::Real, s_braking::Real)
|
||||
function brakingAcceleration(v_start::Real, v_end::Real, s_braking::Real)
|
||||
# equation is based on [Wende:2003, page 37]
|
||||
|
||||
# v_start: braking start velocity (in m/s)
|
||||
|
@ -220,4 +219,4 @@ function calcBrakingAcceleration(v_start::Real, v_end::Real, s_braking::Real)
|
|||
# s_braking: braking distance (in Ws)
|
||||
a_braking = (v_end^2 - v_start^2) /2 /s_braking # constant braking acceleration (in m/s^2)
|
||||
return a_braking
|
||||
end #function calcBrakingAcceleration
|
||||
end #function brakingAcceleration
|
||||
|
|
134
src/output.jl
134
src/output.jl
|
@ -1,110 +1,66 @@
|
|||
#!/usr/bin/env julia
|
||||
# -*- coding: UTF-8 -*-
|
||||
# __julia-version__ = 1.7.2
|
||||
# __author__ = "Max Kannenberg"
|
||||
# __copyright__ = "2020-2022"
|
||||
# __license__ = "ISC"
|
||||
|
||||
function createOutput(train::Train, settings::Settings, path::Path, movingSection::Dict, drivingCourse::Vector{Dict})
|
||||
function createOutput(settings::Settings, drivingCourse::Vector{Dict}, pointsOfInterest::Vector{Tuple})
|
||||
if settings.outputDetail == :running_time
|
||||
output = movingSection[:t] # TODO: or use drivingCourse[end][:t]
|
||||
output::Vector{Dict} = [Dict(:t => drivingCourse[end][:t])]
|
||||
|
||||
elseif settings.outputDetail == :points_of_interest
|
||||
# add points of interest
|
||||
if !isempty(path.poi)
|
||||
|
||||
# for elem in 1:length(driving_course)
|
||||
# end
|
||||
|
||||
output = Dict[]
|
||||
POI = 1
|
||||
i = 1
|
||||
while POI <= length(path.poi) && i <= drivingCourse[end][:i]
|
||||
if path.poi[POI][:station] == drivingCourse[i][:s]
|
||||
push!(output, drivingCourse[i])
|
||||
POI = POI+1
|
||||
elseif settings.outputDetail == :points_of_interest && !isempty(pointsOfInterest)
|
||||
# get only the driving course's data points with POI labels
|
||||
output = Dict[]
|
||||
dataPoint = 1
|
||||
for POI in 1:length(pointsOfInterest)
|
||||
while dataPoint <= length(drivingCourse)
|
||||
if pointsOfInterest[POI][1] == drivingCourse[dataPoint][:s]
|
||||
push!(output, drivingCourse[dataPoint])
|
||||
break
|
||||
end
|
||||
i = i+1
|
||||
dataPoint += 1
|
||||
end
|
||||
end
|
||||
|
||||
elseif settings.outputDetail == :driving_course
|
||||
output = drivingCourse
|
||||
|
||||
elseif settings.outputDetail == :everything
|
||||
output = Dict{Symbol,Any}()
|
||||
merge!(output, Dict(:train => train, :path => path, :settings => settings))
|
||||
|
||||
|
||||
# add moving section and driving courses
|
||||
if settings[:operationModeMinimumRunningTime] == true
|
||||
merge!(output, Dict(:movingSectionMinimumRunningTime => movingSection,
|
||||
:drivingCourseMinimumRunningTime => drivingCourse))
|
||||
elseif settings[:operationModeMinimumEnergyConsumption] == true
|
||||
merge!(output, Dict(:movingSectionMinimumEnergyConsumption => movingSection,
|
||||
:drivingCourseMinimumEnergyConsumption => drivingCourse))
|
||||
end
|
||||
|
||||
# add points of interest
|
||||
if !isempty(path.poi)
|
||||
pointsOfInterest = Vector{Dict}()
|
||||
POI = 1
|
||||
i = 1
|
||||
while POI <= length(path.poi) && i <= drivingCourse[end][:i]
|
||||
if path.poi[POI] == drivingCourse[i][:s]
|
||||
push!(pointsOfInterest, drivingCourse[i])
|
||||
POI = POI+1
|
||||
end
|
||||
i = i+1
|
||||
end
|
||||
|
||||
if settings[:operationModeMinimumRunningTime] == true
|
||||
merge!(output, Dict(:pointsOfInterestMinimumRunningTime => pointsOfInterest))
|
||||
elseif settings[:operationModeMinimumEnergyConsumption] == true
|
||||
merge!(output, Dict(:pointsOfInterestMinimumEnergyConsumption => pointsOfInterest))
|
||||
end
|
||||
end
|
||||
else
|
||||
output = nothing
|
||||
else #if settings.outputDetail == :driving_course || (settings.outputDetail == :points_of_interest && !isempty(path.poi))
|
||||
output = drivingCourse
|
||||
end
|
||||
|
||||
if settings.outputFormat == :dataframe
|
||||
return createDataFrame(output, settings.outputDetail)
|
||||
elseif settings.outputFormat == :vector
|
||||
return output
|
||||
end
|
||||
return output
|
||||
end
|
||||
|
||||
#=
|
||||
function createOutputDict(train::Train, settings::Settings, path::Path, movingSection::Dict, drivingCourse::Vector{Dict})
|
||||
outputDict = Dict{Symbol,Any}()
|
||||
merge!(outputDict, Dict(:train => train, :path => path, :settings => settings))
|
||||
|
||||
function createDataFrame(output_vector::Vector{Dict}, outputDetail)
|
||||
if outputDetail == :running_time
|
||||
# create a DataFrame with running time information
|
||||
dataFrame = DataFrame(t=[output_vector[end][:t]])
|
||||
else # :points_of_interest or :driving_course
|
||||
columnSymbols = [:label, :behavior, :s, :v, :t, :a, :F_T, :F_R, :R_path, :R_traction, :R_wagons]
|
||||
|
||||
# add moving section and driving courses
|
||||
if settings[:operationModeMinimumRunningTime] == true
|
||||
merge!(outputDict, Dict(:movingSectionMinimumRunningTime => movingSection,
|
||||
:drivingCourseMinimumRunningTime => drivingCourse))
|
||||
elseif settings[:operationModeMinimumEnergyConsumption] == true
|
||||
merge!(outputDict, Dict(:movingSectionMinimumEnergyConsumption => movingSection,
|
||||
:drivingCourseMinimumEnergyConsumption => drivingCourse))
|
||||
end
|
||||
|
||||
# add points of interest
|
||||
if !isempty(path.poi)
|
||||
pointsOfInterest = Vector{Dict}()
|
||||
POI = 1
|
||||
i = 1
|
||||
while POI <= length(path.poi) && i <= drivingCourse[end][:i]
|
||||
if path.poi[POI] == drivingCourse[i][:s]
|
||||
push!(pointsOfInterest, drivingCourse[i])
|
||||
POI = POI+1
|
||||
allColumns = []
|
||||
for column in 1:length(columnSymbols)
|
||||
if typeof(output_vector[1][columnSymbols[column]]) == String
|
||||
currentStringColumn::Vector{String} = []
|
||||
for point in output_vector
|
||||
push!(currentStringColumn, point[columnSymbols[column]])
|
||||
end
|
||||
push!(allColumns, currentStringColumn)
|
||||
elseif typeof(output_vector[1][columnSymbols[column]]) <: Real
|
||||
currentRealColumn::Vector{Real} = []
|
||||
for point in output_vector
|
||||
push!(currentRealColumn, point[columnSymbols[column]])
|
||||
end
|
||||
push!(allColumns, currentRealColumn)
|
||||
end
|
||||
i = i+1
|
||||
end
|
||||
end # for
|
||||
|
||||
if settings[:operationModeMinimumRunningTime] == true
|
||||
merge!(outputDict, Dict(:pointsOfInterestMinimumRunningTime => pointsOfInterest))
|
||||
elseif settings[:operationModeMinimumEnergyConsumption] == true
|
||||
merge!(outputDict, Dict(:pointsOfInterestMinimumEnergyConsumption => pointsOfInterest))
|
||||
end
|
||||
# combine the columns in a data frame
|
||||
dataFrame = DataFrame(label=allColumns[1], driving_mode=allColumns[2], s=allColumns[3], v=allColumns[4], t=allColumns[5], a=allColumns[6], F_T=allColumns[7], F_R=allColumns[8], R_path=allColumns[9], R_traction=allColumns[10], R_wagons=allColumns[11])
|
||||
end
|
||||
|
||||
return outputDict
|
||||
end # function createOutputDict
|
||||
=#
|
||||
return dataFrame
|
||||
end #createDataFrameForDrivingCourse
|
||||
|
|
13
src/types.jl
13
src/types.jl
|
@ -1,6 +1,5 @@
|
|||
#!/usr/bin/env julia
|
||||
# -*- coding: UTF-8 -*-
|
||||
# __julia-version__ = 1.7.2
|
||||
# __author__ = "Martin Scheidt, Max Kannenberg"
|
||||
# __copyright__ = "2022"
|
||||
# __license__ = "ISC"
|
||||
|
@ -10,10 +9,10 @@ struct Settings
|
|||
massModel::Symbol # model type of train mass ":mass_point" or ":homogeneous_strip".
|
||||
stepVariable::Symbol # variable of the linear multistep method: ":distance", ":time" or ":velocity".
|
||||
stepSize::Real # step size, unit depends on stepVariable - :distance in meter, time in seconds and velocity in meter/second.
|
||||
approxLevel::Int # value for approximation; used when rounding or interating.
|
||||
outputDetail::Symbol # single Float() ":running_time", Array() of ":points_of_interest",
|
||||
# complete Array() ":driving_course", or Dict() ":everything".
|
||||
outputFormat::Symbol # output as ":dataframe" or as ":dict".
|
||||
approxLevel::Int # value for approximation; used when rounding or iterating.
|
||||
outputDetail::Symbol # single Float() ":running_time", Vector() of ":points_of_interest",
|
||||
# or complete Vector() ":driving_course"
|
||||
outputFormat::Symbol # output as ":dataframe" or as ":vector".
|
||||
|
||||
end #struct Settings
|
||||
|
||||
|
@ -45,10 +44,10 @@ struct Train
|
|||
a_braking::Real # in m/s^2
|
||||
|
||||
# coefficients for the vehicle resistance
|
||||
# for the traction unit (F_Rt=f_Rtd0*m_td*g+f_Rtc0*m_tc*g+F_Rt2*((v+Δv_air)/v00)^2)
|
||||
# for the traction unit (F_Rt=f_Rtd0*m_td*g+f_Rtc0*m_tc*g+f_Rt2*m_loco*g*((v+Δv_air)/v00)^2)
|
||||
f_Rtd0::Real # coefficient for basic resistance due to the traction units driving axles (in ‰)
|
||||
f_Rtc0::Real # coefficient for basic resistance due to the traction units carring axles (in ‰)
|
||||
F_Rt2::Real # coefficient for air resistance of the traction units (in N)
|
||||
f_Rt2::Real # coefficient for air resistance of the traction units (in ‰)
|
||||
|
||||
# for the consist (set of wagons) (F_Rw=m_w*g*(f_Rw0+f_Rw1*v/v00+f_Rw2*((v+Δv_air)/v00)^2))
|
||||
f_Rw0::Real # coefficient for the consists basic resistance (in ‰)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
%YAML 1.2
|
||||
---
|
||||
settings:
|
||||
outputDetail: "driving_course" # single value "running_time", array of "points_of_interest",complete array "driving_course", or dict() "everything"
|
||||
outputDetail: "driving_course" # single value "running_time", list of "points_of_interest", complete "driving_course"
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
%YAML 1.2
|
||||
---
|
||||
settings:
|
||||
outputDetail: "everything" # single value "running_time", array of "points_of_interest",complete array "driving_course", or dict() "everything"
|
|
@ -1,4 +1,4 @@
|
|||
%YAML 1.2
|
||||
---
|
||||
settings:
|
||||
outputDetail: "points_of_interest" # single value "running_time", array of "points_of_interest",complete array "driving_course", or dict() "everything"
|
||||
outputDetail: "points_of_interest" # single value "running_time", list of "points_of_interest", complete "driving_course"
|
||||
|
|
|
@ -37,7 +37,7 @@ vehicles:
|
|||
|
||||
rotation_mass: 1.09 # source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit
|
||||
base_resistance: 2.2 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsige Diesellokomot." -> 2.2 ‰ to 3.5 ‰
|
||||
air_resistance: 0.01 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "MittelfUhrerstand" -> 5000 N to 10000 N; modified for the used formula
|
||||
air_resistance: 10 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "MittelfUhrerstand" -> 5000 N to 10000 N; modified for the used formula
|
||||
|
||||
tractive_effort:
|
||||
- [0.0, 186940]
|
||||
|
|
|
@ -9,12 +9,12 @@ trains:
|
|||
|
||||
vehicles:
|
||||
- name: Siemens Desiro Classic # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic
|
||||
id: DB_BR_642
|
||||
id: DB_BR_642
|
||||
UUID: c915c80d-c63d-490b-879f-c481e4b62b55
|
||||
picture: https://commons.wikimedia.org/wiki/File:Liesel_28-11-10_642_055-8_im_Bahnhof_Scharfenstein.JPG
|
||||
power_type: diesel # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic
|
||||
vehicle_type: multiple unit # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic
|
||||
|
||||
|
||||
length: 41.7 # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic
|
||||
mass: 68.0 # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic
|
||||
load_limit: 20.0 # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic
|
||||
|
@ -26,7 +26,7 @@ vehicles:
|
|||
rotation_mass: 1.08 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 13 for "Zug, überschlägliche Berechnung"
|
||||
base_resistance: 3.0 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "f_WL0" -> 2.5 ‰ to 3.5 ‰
|
||||
rolling_resistance: 1.4 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "f_WW0" -> 1.2 ‰ to 1.6 ‰
|
||||
air_resistance: 0.0039 # source: the closest parameters are used: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "Fzg. vierachsig, abgerundeter Kopf" plus "Sektion bei Mehrteiligkeit" -> 2200 N + 400 N
|
||||
air_resistance: 3.9 # source: the closest parameters are used: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "Fzg. vierachsig, abgerundeter Kopf" plus "Sektion bei Mehrteiligkeit" -> 2200 N + 400 N
|
||||
|
||||
# tractive effort as pairs of speed and tractive effort
|
||||
tractive_effort:
|
||||
|
|
|
@ -54,7 +54,7 @@ vehicles:
|
|||
|
||||
rotation_mass: 1.09 # source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit
|
||||
base_resistance: 2.5 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsige Diesellokomot." -> 2.2 ‰ to 3.5 ‰
|
||||
air_resistance: 0.006 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsig, eckige Kopfform" with "Stromabnehmer" -> 5000 N to 6000 N; modified for the used formula
|
||||
air_resistance: 6.0 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsig, eckige Kopfform" with "Stromabnehmer" -> 5000 N to 6000 N; modified for the used formula
|
||||
|
||||
tractive_effort:
|
||||
- [0.0, 300000]
|
||||
|
|
|
@ -28,7 +28,6 @@ settings = Dict()
|
|||
push!(settings, "default" => @time Settings())
|
||||
push!(settings, "poi" => @time Settings("data/settings/points_of_interest.yaml"))
|
||||
push!(settings, "drivingcourse" => @time Settings("data/settings/driving_course.yaml"))
|
||||
push!(settings, "everything" => @time Settings("data/settings/everything.yaml"))
|
||||
push!(settings, "strip" => @time Settings("data/settings/strip.yaml"))
|
||||
push!(settings, "time" => @time Settings("data/settings/time.yaml"))
|
||||
push!(settings, "timestrip" => @time Settings("data/settings/time_strip.yaml"))
|
||||
|
@ -53,18 +52,18 @@ tests = Base.Iterators.product(trains,paths)
|
|||
|
||||
anticipated = Dict(
|
||||
:default => Dict(
|
||||
:longdistance_speed => 499.96109564970516,
|
||||
:freight_slope => 831.4768274141168,
|
||||
:local_slope => 396.99313307033276,
|
||||
:longdistance_const => 328.83479381353095,
|
||||
:freight_realworld => 8971.50124080998,
|
||||
:longdistance_slope => 329.22915822053164,
|
||||
:freight_const => 727.7969403041934,
|
||||
:longdistance_realworld => 2900.1198723158523,
|
||||
:local_speed => 524.3948201513945,
|
||||
:local_realworld => 3443.917823618831,
|
||||
:freight_speed => 733.2610572579886,
|
||||
:local_const => 392.7234008268302
|
||||
:freight_const => 746.6594691660882,
|
||||
:freight_slope => 842.3797947097586,
|
||||
:freight_speed => 751.9727357301351,
|
||||
:freight_realworld => 8789.299477891092,
|
||||
:local_const => 392.6801497584646,
|
||||
:local_slope => 396.59291844946534,
|
||||
:local_speed => 524.3734475900396,
|
||||
:local_realworld => 3438.3543735577446,
|
||||
:longdistance_const => 330.8511578156266,
|
||||
:longdistance_slope => 331.7163794230447,
|
||||
:longdistance_speed => 501.13448446081713,
|
||||
:longdistance_realworld => 2913.3759609192407
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -75,7 +74,7 @@ anticipated = Dict(
|
|||
for test in tests
|
||||
test_name = String(test[1][1]) * "_" * String(test[2][1])
|
||||
println("testing $test_name")
|
||||
@time result = trainrun(test[1][2],test[2][2])
|
||||
@time result = trainrun(test[1][2], test[2][2])[end, :t]
|
||||
expected = anticipated[:default][Symbol(test_name)]
|
||||
# compare result to test data set
|
||||
@test isapprox(result, expected, rtol=0.01)
|
||||
|
|
Loading…
Reference in New Issue