Project Log

Why LINK_ID and Five-Minute Traffic Data Matter

  • Traffic Data
  • LINK_ID
  • Digital Twin

Created and reviewed on July 13, 2026. This is a working note based on the current project structure.

A traffic screen can look simple. A road is green, yellow, or red. But the screen only works when the backend knows which traffic record belongs to which road.

In my Seoul traffic digital twin project, LINK_ID became the key that connected the data flow. It linked road reference data, live traffic data, model input, API responses, and the road objects shown in Unity/Cesium.

Start with a stable road key

A road name is useful for people, but it is not a safe data key. Names can be repeated. The same road can have different directions. A name can also be written in more than one way.

LINK_ID gave each road link a stable identity. I used it to connect:

  • road geometry and road information;
  • public and real-time traffic records;
  • rows in the machine-learning table;
  • Flask API responses;
  • road data loaded and displayed in Unity.

This made the flow easier to check. When a road did not receive a speed value, I could follow the same LINK_ID through the data table, backend response, and Unity road object.

One road and one time need one clear row

Historical traffic files were organized into a training table with this basic unit:

LINK_ID x observed_at (five-minute interval)

This means that one row represents one road link at one observed time. Speed is the value to learn from, and other available features can be joined around the same road and time.

The five-minute rule was important because time data can look regular while still containing gaps, duplicates, or values that do not match the expected boundary. The data pipeline checks the time alignment and keeps quality information about missing intervals. It does not pretend that missing records exist.

That choice matters for model work. A clean file is not always an honest file. I would rather keep a warning about missing time slots than silently create data that was never observed.

Reference data and changing data are different

The project has two broad kinds of road data.

Reference data changes slowly. It includes the road identity, name, direction, geometry, and other information needed to create the road on the map.

Traffic data changes often. It includes the current speed and congestion state for a road link.

Both use LINK_ID, but they have different jobs. The reference data answers, “What road is this?” The live data answers, “What is happening on this road now?”

Keeping those jobs separate made the backend and Unity flow clearer. Unity could load the road shape first, then apply new traffic values to the existing road object instead of rebuilding everything for every update.

Model data and screen data are also different

The machine-learning table needs consistent historical rows for training and validation. The screen needs a smaller response that can be read and shown quickly.

Unity does not need the full training table. It needs road data, current traffic values, and an on-demand prediction result in a clear response format. The Flask backend prepares those responses and keeps the heavier data work on the server side.

This boundary helped me understand an important point: data is not ready just because it exists. It must be shaped for the next user of that data. A model, an API, and a 3D screen need different forms of the same information.

What I learned

Before thinking about a more complex model or a more polished screen, I needed to make the identity and time rules clear.

The practical order was:

  1. define the road key;
  2. align traffic records to the time unit;
  3. check missing and duplicate data;
  4. build the training and validation flow;
  5. return screen-ready data through the API;
  6. use the same road key to update the Unity view.

This project is still a prototype, and model quality should be discussed only with validated results. The useful result of this work is the connected flow: public and real-time data can move through a Flask backend, a machine-learning process, and Unity/Cesium without losing the road identity that holds the system together.