OpenRailAssociation / osrd-website

OSRD website (work in progress)
https://osrd.fr/
4 stars 12 forks source link

docs: design doc for the revamp of the running time calculation #168

Closed woshilapin closed 4 months ago

woshilapin commented 8 months ago
Réunion du 24/01/2024, notes de @clarani # Objectifs --- Quels sont les objectifs de la journée ? Design les nouvelles API du calcul de marche Quelles contraintes ? → pouvoir gérer des contraintes bornées dans le temps (temps système, réaction signalisation) → pouvoir rajouter des contraintes dynamiquement, ce qui permettra de faire de la simulation multitrains # Contexte --- Caractéristiques du modèle actuel → l’état du train se résume à un couple position/vitesse uniquement à un point de la courbe → le calcul de marche est calculé par morceaux, mais pas d’une manière non causale → recollage un peu bancal entre les morceaux → backtracking pour les marges Quels sont les problèmes du modèle actuel ? → impossible d’ajouter des paramètres supplémentaires comme l’état d’une batterie, un temps système… Marges: les marges de construction vont disparaître. La seule ambiguïtés encore sur le comportement avec les marges, c’est au niveau des transitions entre 2 sections qui ont des pourcentages de marge différentes: où se fait la transition ? # Propositions --- ## Nouvel algo des marges --- L’algo actuel des marges “pupet” le calcul de marche: autrement dit, il est à l’extérieur du CDM et le rappelle/itère. Cela complexifie grandement la gestion des marges et l’implémentation des marges marreco. Nouvel interface de Margin Strategy: le Margin Strategy prend en entrée une portion de chemin (avec ses propriétés), la marche tendue sur cette portion du chemin, le matériel roulant, un coefficient de ralentissement et la vitesse du train au début de la section (pour assurer la continuité de la courbe), et sortira des éléments de ralentissement (des nouvelles limites de vitesse, des contraintes en vitesse (qui remplacent des marches sur l’erre), des nouveaux coeffitients de freinage/accélération). Avec le résultat du Margin Strategy, on peut relancer un calcul de marche sur la portion concernée uniquement, comparer le nouveau temps de parcours et le temps de parcours de la marche tendue, puis si nécessaire, ajuster le coefficient de ralentissement et relancer Margin Strategy. Une fois que l’on a atteint un temps de parcours satisfaisant, on passe à la portion suivante du chemin. La transition de marge est donc entièrement prise en charge par le segment suivant (à droite). ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/12fd8d7b-f3fd-4f18-abca-888218495bb2/a71542df-faea-448f-89a3-cf21889e72d7/Untitled.png) Dans le nouvel algo, on passera les marges à l’intérieur du CDM et on utilisera le Margin Strategy, avec une boucle de rétroaction pour ajuster les éléments de marges (marches sur l’erre, abaissement du plateau de vitesse du MRSP et nouveaux coefficients d’accélération/de freinage). Nouveau fonctionnement des marges linéaires actuelles qui ne sont pas physiques: le calcul de marche prendrait un paramètre marges et pourrait lui-même abaisser au fur et à mesure les plateaux de vitesse du MRSP, rajouter des marches sur l’erre et enfin ajuster les coefficients d’accélération/de freinage. ⚠️ ce modèle permettra uniquement de gérer les transitions de marge à droite, et pas à gauche. Gérer les transitions de marges à gauche se répercuterait sur l’ensemble des portions du chemin (on ne pourra plus traiter les segments un par un, mais il faudra calculer les Margins Strategy pour tous les segments du chemin, lancer un CDM et comparer les nouveaux temps de parcours obtenu, puis ajuster tous les coefficients de ralentissement et recommencer). La compléxité algorithmique sera beaucoup plus importante. ## Calcul de marche --- Points à traiter pour les nouveaux APIs - simulation causale - contraintes liées à la signalisation statique (dynamique pour plus tard) → contraintes qui varient en fonction de la position du train ou du temps → sera utile pour les ralens 30, 60 et TIV mobiles, mais aussi les arrêts en gare - comportements conducteur - temps système du train - temps d’arrêt - intégration STDCM (calcul incrémental) Contraintes spécifiques pour STDCM → pouvoir reprendre un calcul de marche à un endroit donné → pouvoir spécifier des arrêts avec des temps ### Réflexions / Débats --- → Doit-on garder le MRSP à l’intérieur du CDM ou le sortir ? Si on le garde à l’intérieur, on doit l’avoir en output, mais on peut tout simplement le sortir. Autant le sortir finalement car ça réduirait la complexité dans le CDM. → Propriétés physiques du chemin et échantillonnage ? […] → Gestion des courbes de freinage Le CDM devra prendre en argument le MaxSpeedProfile (qui comprend les courbes de freinage), lui-même obtenu via un CDM. On devra faire du backtracking et refaire la simulation jusqu’à la fin (donc on reste causal, on ne “recolle” pas). Finalement, on ne prend pas le MaxSpeedProfile en argument, mais uniquement la vitesse finale. On calculerait le MaxSpeedProfile à l’intérieur du CDM. → Marges de régularité Il faudra recalculer tout le trajet. ### Résumé --- Le système actuel n’est plus valide car on peut avoir plusieurs MaxSpeeds sur tout le chemin (variation du MaxSpeed avec le temps). Quel que soit le point sur le chemin où on se trouve, on a au moins une contrainte MaxSpeed, voire plusieures. Toutes ces contraintes sont à minima bornées dans l’espace, et potentiellement dans le temps. On calcule les courbes de freinage les plus conservatrice associées à chaque contrainte, puis on les ordonne par le point de début de freinage. Dans la nouvelle implémentation, on propose d’intégrer jusqu’au point de la prochaine contrainte (=tracer le MaxEffort), vérifier si la contrainte est à prendre en compte ou non étant donné l’état du train (temps/position/vitesse). On passe ensuite à la contrainte suivante. Les types de contraintes sont: → un signal qui change → les extrémités de LTV → les extrémités de zones BP/CC → les changements de palier de MRSP → les arrêts ### Questions --- - Quelles sont les différentes conditions de fin de validité d’une instruction liée à un signal ? - Remettre en question le modèle défini - ⚠️ comment gérer si 2 contraintes sont très proches, mais avec superposition des contraintes
woshilapin commented 8 months ago
Réunion du 31/01/2024. # Que fait STDCM aujourd'hui ? 4 manières différentes d'interagir avec le CDM : 1. simulation incrémentale au plus vite - chemin + une vitesse de départ (marche tendue, pas réelle) : on va au plus vite - les sections du chemin sont simulées dans un ordre non-causal (mais tentative d'être optimal) 2. simulation à l'envers (freinage) - seulement utilisé lorsque la vitesse d'arrivée est plus faible que le résultat de la simulation incrémentale ci-dessus - chemin + vitesse de fin + courbe de vitesse existante : on calcule le freinage jusqu'à intersection à la courbe existante 3. marge de construction : on ajoute x secondes - seulement utilisé s'il y a un conflit avec d'autres trains - on cherche à déterminer si le train peut passer en adaptant la marge - chemin + courbe de vitesse existante + temps de marge : on ajoute le temps en tentant de conserver les vitesses de début et de fin - dans l'hypothèse d'une simulation causale, la vitesse de fin n'a pas plus besoin d'être une contrainte - si les contraintes de vitesse de début et de fin ne sont pas atteignables, le chemin est rejeté 4. marge de régularité : calcul final - on récupère tous les morceaux des différentes itérations des étapes 1, 2 et 3 - on ajoute la marge de régularité, avec une simulation de bout en bout - on vérifie que le trajet est toujours possible # Exemple déroulé d'un appel de calcul de marche ## Informations d'entrée au calcul de marche - chemins sous forme de cantons - états des signaux en fonction du temps - propriétés physique du chemin - dénivelé - courbure - vitesse maximum (MRSP) - vitesse maximum en fonction du temps (LTV) - arrêts - position - temps d'arrêt ou heure de départ - état initial - vitesse de départ - contrainte de temps - marges - points horairisés ![20240131_175255](https://github.com/osrd-project/osrd-website/assets/2520723/a6d5752c-d0df-4e91-bff5-d028294e34f4) ![20240131_175226](https://github.com/osrd-project/osrd-website/assets/2520723/e045f4ae-4cf0-48c6-996b-8adb2b902b8d) ![20240131_175210](https://github.com/osrd-project/osrd-website/assets/2520723/9206b2eb-42cf-43e6-a610-e4c10e7bf794)
woshilapin commented 8 months ago
Réunion du 07/02/2024 ![IMG_0004](https://github.com/osrd-project/osrd-website/assets/2520723/6b94bc12-5bd8-4070-9550-cbe159decded) ![IMG_0005](https://github.com/osrd-project/osrd-website/assets/2520723/1feb977b-765a-43f4-9430-d774611cb3de)
woshilapin commented 8 months ago
Réunion du 21/02/2024, pseudo-implémentation ```rust fn filter_by_range -> fastoche fn margin_driver -> mareco fn merge_sets -> fastoche fn find_most_restrictive_action(t, dt, pos, driving_instructions) -> pas fastoche mais bon courage au développeur // simulation de base (tendue) -> target_schedule vide (simplement une relaxed_time_section), margin_driver == noop // simulation finale (détendue/mareco) -> target_schedule avec contraintes (utilisant les résultats de marche tendue) fn cdm_simulation(target_schedule: &[(Horaire, Position)] + d'autres trucs, abstract_driving_instructions, path_physics_properties, rolling_stock, train_init_state, margin_driver) { concrete_driving_instructions = compiler(abstract_driving_instructions, path_physics_properties, rolling_stock); state_log = [train_init_state]; for (margin in target_schedule.margins) { filtered_concrete_driving_instructions = filter_by_range(margin.range, concrete_driving_instructions); for (v1 in search) { margin_concrete_driving_instructions = margin_driver(v1, filtered_concrete_driving_instructions, path_physics_properties); instructions = merge_sets(filtered_concrete_driving_instructions, margin_concrete_driving_instructions); new_state_log = simulation(margin.range, state_log[len(state_log) - 1], instructions, path_physics_properties, rolling_stock); } state_log.extend(new_state_log); } if let Some(range) = target_schedule.relaxed_time_section { new_state_log = simulation(range, state_log[len(state_log) - 1], concrete_driving_instructions, path_physics_properties, rolling_stock) state_log.extend(new_state_log); } state_log } fn compiler(abstract_driving_instruction, path_physics_properties, rolling_stock) -> ConcreteDrivingInstruction; struct AbstractDrivingInstruction { /* voir séance du 14/02/2024 */ } struct ConcreteDrivingInstruction { curve: EspaceTempsVitesse, abstract_driving_instruction: AbstractDrivingInstruction, } fn simulation(range, train_state, driving_instructions, path_physics_properties, rolling_stock) { simulation_output = [] for (t = start_time ; pos < range.max; t += dt) { train_state, driving_instructions = update_driving_instructions(train_state, driving_instructions); action = find_most_restrictive_action(t, dt, pos, train_state.active); simulation_output.extend(integration(action)); pos = simulation_output.positions[len(simulation_output.positions) - 1]; dt = cursed_whatever_function(); } simulation_output } // pending instructions -> driving_instructions // received instructions -> train_state.received_instructions // active instructions -> train_state.active_instructions // retired instructions -> garbage collected // train_state contient les instructions reçues et actives // driving_instructions contient les instructions pas encore reçues fn update_driving_instructions(train_state, driving_instructions) { for (instruction in driving_instructions) { if instruction.received { train_state.received(instruction); driving_instructions -= instruction; } } for (instruction in train_state.received_instructions) { if instruction is now active { // make obsolete (retired) some instructions // transfer from receive to active the 'instruction' train_state.activate(instruction); } } for (instruction in train_state.active_instructions) { if instruction.end_of_application is on { train_state.active_instructions -= instruction; } } train_state, driving_instructions } ```
multun commented 5 months ago

@woshilapin @Castavo can someone pick up the branch / the review?

leovalais commented 4 months ago

As discussed today, maybe we should consider moving the state reconciliation logic into the driver behavior module. The current process is:

// At simulation step T:

// Driving instructions
let instructions = [DI1, DI2, DI3]

// Driver behavior PER INSTRUCTION
let candidates = [db(DI1), db(DI2), db(DI3)]

// Reconciliation
let final_curve = speeding_curves_reconciliation(candidates)

The reconciliation part is tricky because it operates on a list of curves. We can defer the reconciliation step to the driver behavior which would operate on a list of driving instructions instead.

// At simulation step T:

// Driving instructions
let instructions = [DI1, DI2, DI3]

// Driver behavior application, which is now responsible of the reconciliation of the instructions
let final_curve = driver_behavior([DI1, DI2, DI3])

This way, if two instructions are conflicting, the driver behavior can reconciliate these by matching on these two instructions instead of operating on abstract curves. Symbolic decision making is probably easier and more maintainable rather than working with conflicting curves.

[!CAUTION] To be further discussed.

Castavo commented 4 months ago

When picking up this PR, we were tempted to change the model described. We then realized we did not have enough time so we simply settled for clarifying the description of the model.

We planned on adding examples of driving instructions generated from constraints, but none of us can afford the time, so we'll just add the photos we took from the workshop in this thread

Pictures
woshilapin commented 4 months ago

Looks good to me, thanks for the clarifications and the work on these last week. I can't approve (since I opened the PR).