1 La ciudad como grafo
Para la computadora, Puebla es un grafo dirigido \(G = (V, E)\). Los nodos \(V\) son los puntos donde la geometría de una calle cambia: esquinas, curvas, entronques. Las aristas \(E\) son los tramos de calle entre dos nodos, en un solo sentido. Una calle de doble sentido aporta dos aristas, \(u \to v\) y \(v \to u\); un bulevar con camellón se dibuja como dos calles paralelas de un solo sentido, una por cada arroyo.
| Elemento | Cantidad | Atributos |
|---|---|---|
| Nodos \(V\) | 67,216 | latitud, longitud |
| Aristas \(E\) | 160,332 | longitud \(\ell_e\) (m), velocidad límite \(v^{\max}_e\) (m/s), carriles \(n_e\), nombre, geometría |
| Vehículos | 900,000 | arista \(e_i\), posición \(x_i \in [0, \ell_{e_i}]\), velocidad \(v_i\), estacionado o circulando |
El estado completo de un vehículo son tres números: en qué arista está, cuántos metros lleva recorridos sobre ella y a qué velocidad va. Su posición geográfica se obtiene interpolando sobre la geometría de la calle. Los tres números se guardan en arreglos tipados paralelos (Int32Array, Float64Array, Float32Array), uno por atributo, en lugar de un objeto por vehículo: memoria contigua que el motor de JavaScript recorre rápido, porque la simulación completa corre en un solo hilo de Node.js.
El tiempo avanza en pasos fijos de
y en cada paso se actualizan todos los vehículos que circulan. Los estacionados, que son la mayoría, no ocupan lugar en la calle ni cuestan cálculo hasta que vuelven a salir (sección 6).
2 Seguimiento vehicular
Cada vehículo mira hacia adelante y encuentra su obstáculo: la posición máxima a la que puede llegar sin problema. Si el vehículo es el primero de su calle y el semáforo al final está en rojo, el obstáculo es la línea de alto, en \(x = \ell_e\). Si tiene un vehículo enfrente, el obstáculo es la defensa trasera de ese vehículo menos una separación mínima. Si no hay nada, el obstáculo está en el infinito. La distancia libre hasta el obstáculo es el hueco:
Con desaceleración máxima \(b\), la distancia que necesita un vehículo para detenerse es la de la cinemática elemental, más un metro de margen:
La regla de velocidad compara ambas cantidades. Si el hueco es menor que la distancia de frenado, el vehículo baja a la velocidad segura \(\sqrt{2 b g_i}\), la máxima con la que todavía puede detenerse en \(g_i\) metros. Si no, acelera hacia el límite de la calle:
| Constante | Símbolo | Valor |
|---|---|---|
| Aceleración | \(a\) | 2.0 m/s² |
| Desaceleración máxima | \(b\) | 4.0 m/s² |
| Longitud del vehículo | \(L\) | 4.5 m |
| Hueco mínimo | \(s_0\) | 2.0 m |
| Paso de tiempo | \(\Delta t\) | 0.25 s |
Los vehículos de cada arista se mantienen ordenados por posición y se procesan del primero al último. Así, cuando un vehículo calcula su hueco, el de enfrente ya tiene su posición nueva: la información de un frenazo se propaga hacia atrás de la fila dentro del mismo paso. Como los vehículos casi nunca cambian de orden, el reordenamiento se hace con inserción, que es lineal en listas casi ordenadas.
Carriles sin carriles
El simulador no representa carriles por separado: todos los vehículos de una arista forman una sola fila. Para que una avenida de varios carriles tenga más capacidad que una calle de colonia, la separación mínima se reparte entre los carriles reales de la calle:
La densidad máxima de la fila es entonces \(n_e / 6.5\) vehículos por metro: una avenida de tres carriles aguanta tres veces más vehículos antes de formar cola. Es una aproximación de capacidad, no una simulación de carriles: no hay rebases ni cambios de carril. La Fig. 1 aplica exactamente las ecuaciones (2)–(6) a una calle con un semáforo.
3 Paso de una calle a otra
Cuando un vehículo rebasa el final de su arista con el semáforo en verde, se registra como movimiento pendiente junto con los metros que le sobraron. Los movimientos se resuelven después de actualizar todas las aristas, en tres pasos.
// para cada vehículo i que llegó al final de su arista e elegir la siguiente arista e' // sección 4 agrupar las llegadas por arista destino e' // para cada arista destino, de la llegada más adelantada a la menos x_deseada = min(sobrante, ℓ_e' / 2) x_permitida = (vehículo más cercano adelante en e') − s_e' si x_permitida < 0: rechazar: i se queda en e, detenido en la línea de alto si no: i pasa a e' en x = max(0, min(x_deseada, x_permitida)) v_i ← v_i · φ(θ) // ec. (7) // los rechazados se apilan detrás de la línea de alto con separación s_e
El rechazo es lo que en ingeniería de tránsito se llama bloqueo por saturación (spillback): con el semáforo en verde, un vehículo no entra a un cruce si la cuadra de enfrente no tiene espacio. Sin esta regla los vehículos se encimarían en los tramos cortos; con ella, las colas se propagan hacia atrás de una calle a otra, como en la ciudad real.
Al cambiar de calle, el vehículo pierde velocidad según el ángulo \(\theta\) entre la dirección con la que llega y la dirección con la que sale:
4 Elección de ruta
Los vehículos no tienen origen ni destino: deciden esquina por esquina. Al llegar al nodo final de su arista, el vehículo elige una de las aristas de salida \(\mathcal{O}\), descartando la vuelta en U salvo que sea la única opción, con probabilidad
El factor cuadrático hace que las avenidas atraigan mucho más que las calles locales: una salida a 60 km/h pesa cuatro veces lo que una a 30 km/h. Con un peso lineal, los vehículos se dispersarían por las calles de colonia, que son la mayoría de la red, y las avenidas se verían vacías. El mismo peso \((v^{\max}_e)^2\) se usa para decidir dónde aparece cada vehículo nuevo.
El factor \(p_e \in \{0,\ 0.25,\ 1,\ 2,\ 4\}\) es una prioridad que se ajusta a mano por calle desde el editor; \(p_e = 0\) cierra la calle a la circulación. El factor \(z_e\) modela la hora pico. La ciudad tiene zonas dibujadas a mano, comerciales o residenciales, cada una con un nivel \(\lambda \in \{1, \dots, 5\}\) de importancia. Según la hora de Puebla, una de las dos clases se vuelve destino:
Una zona de nivel 1 multiplica el peso de sus calles por 25; una de nivel 5, por 5. Durante la hora pico, además, los vehículos nuevos aparecen en la clase de zona contraria al destino, para que tengan el viaje completo por delante. En fin de semana no hay ida y vuelta al trabajo: el horario de (9) se sustituye por una sola atracción a las zonas comerciales de 12:00 a 18:00, con un factor más suave (3 en lugar de 5).
5 Semáforos
Un semáforo controla una arista: una calle, en un sentido. Los vehículos de esa arista se detienen al final de ella cuando está en rojo; el resto de la red no se entera. Los semáforos de una misma esquina se agrupan en un cruce y reciben un turno \(k \in \{1, \dots, K\}\). Los semáforos con el mismo turno están en verde al mismo tiempo, y dos turnos distintos nunca lo están.
Cada semáforo tiene una prioridad con multiplicador \(m \in \{0.6,\ 1,\ 1.5\}\) (baja, media, alta). El verde del turno \(k\) lo fija el semáforo más prioritario del turno:
Entre un turno y el siguiente hay un intervalo de despeje de \(C = 3\) s con todo en rojo. El ciclo completo y el inicio de cada turno son
y un semáforo del turno \(k\) está en verde en el instante \(t\) si y solo si
donde \(\phi\) es el desfase del cruce, es decir, en qué punto de su ciclo se encontraba en \(t = 0\). Un semáforo suelto se trata como un cruce de un solo semáforo al que se agrega una fase vacía de \(G_0\) segundos, para que también tenga rojo. Cuando un turno se queda sin semáforos, los turnos superiores se recorren para que la numeración siga siendo \(1, 2, \dots, K\).
Al crear un cruce, los turnos se asignan por eje: se toma el rumbo \(\beta\) con el que cada calle llega a la esquina, se pliega a \([0^\circ, 180^\circ)\) para que ambos sentidos de una calle coincidan, y se compara con el del primer semáforo seleccionado:
Las calles paralelas a la primera quedan en el turno 1 y las perpendiculares en el 2. Desde el editor se puede cambiar cualquier turno y crear turnos adicionales.
De dónde salen los semáforos
Cualquier persona con cuenta puede proponer un semáforo desde el mapa: toca 🚦 Proponer semáforo y luego la calle donde hace falta. El punto se convierte en una arista con la misma regla que usa el editor: si el toque cae a menos de 40 m de una esquina, el semáforo va en la calle que llega a esa esquina y está más cerca del toque; si no, en la calle más cercana, y los vehículos se detienen en su siguiente esquina. No se aceptan puntos a más de 40 m de una calle de la red ni a menos de 25 m de otro semáforo o de otra propuesta.
Cada propuesta pasa por revisión antes de contar. Primero la meto a la simulación en vivo, a prueba, para ver cómo reaccionan los vehículos; si la cola que forma tiene sentido, se queda; si no, se quita. Una propuesta aprobada entra como semáforo suelto, con prioridad media y un desfase \(\phi\) al azar entre 0 y 45 s. Como un semáforo controla un solo sentido de una sola calle, una esquina completa se arma con varias propuestas que después agrupo en un cruce.
Ejemplo: Valsequillo y Municipio Libre
Si Bulevar Valsequillo (turno 1) tiene prioridad alta y Bulevar Municipio Libre (turno 2) media:
Con ambas en prioridad media, cada una tendría \(20/46 \approx 43\,\%\). Son diez segundos más de verde en cada ciclo para el bulevar que mueve más vehículos.
Coordinación entre cruces
Dos cruces consecutivos sobre la misma avenida forman una ola verde si su diferencia de fase se mantiene constante. Con ciclos \(T_1\) y \(T_2\), la diferencia de fase avanza \(|T_1 - T_2|\) segundos en cada ciclo:
Solo si \(T_1 = T_2\) la coordinación se conserva. Un cruce con prioridad alta en uno de sus turnos (\(T = 56\) s) junto a uno con todo en media (\(T = 46\) s) se desfasa diez segundos por ciclo: la ola verde se rompe en menos de cinco ciclos.
6 Cuántos circulan: estacionamiento y hora del día
En la ciudad real casi todos los autos están estacionados casi todo el tiempo. El simulador parte de una flota fija de \(N = 900{,}000\) vehículos. El registro da unos 750 mil para el área del mapa (Puebla, las Cholulas, Cuautlancingo, Amozoc…): alrededor de 2.4 millones de habitantes con una motorización de 318 vehículos por cada mil (Conapo, 2023). A eso se suma lo que el registro no ve: autos con placas de Tlaxcala u otros estados y los que entran a diario desde fuera del mapa.
De esa flota, la fracción que circula en el instante \(t\) mezcla dos poblaciones. Los autos particulares (\(1-\sigma\) de la flota) pasan el día estacionados y salen con los horarios de trabajo y escuela, con una curva \(p_d(h)\) que depende de la hora \(h\) y del tipo de día \(d\) (entre semana, sábado o domingo). El transporte de servicio (\(\sigma = 10\,\%\): combis, camiones, taxis, plataformas, reparto) casi no se estaciona de día y sigue una curva propia \(s(h)\):
Entre semana, a las 8:00 y a las 19:00, eso da \(M^{*} \approx 0.9 \cdot 0.15 + 0.1 \cdot 0.65 = 0.20\): una de cada cinco unidades de la flota está en la calle, unos 180 mil vehículos. De madrugada circula alrededor del 1 %. Las curvas se interpolan minuto a minuto, y a medianoche se enlazan con las del día siguiente, para que la madrugada del sábado refleje la salida del viernes.
Un regulador corre cada segundo. Cuenta los vehículos que circulan, \(M\), y corrige la diferencia con un tope, para que la ciudad se llene y se vacíe de forma gradual:
Si faltan vehículos, despierta autos estacionados elegidos al azar, que salen desde la calle donde estaban. Si sobran, guarda vehículos que van por calles de \(\le 50\) km/h, como quien llega a su casa o a su trabajo; nunca estaciona a nadie en un bulevar. Los autos guardados se reparten en las calles de colonia en proporción a su longitud.
Además del regulador, durante la hora pico un vehículo que entra a una calle lenta (\(v^{\max}_e \le 30\) km/h) dentro de la zona destino se estaciona con probabilidad \(0.015\), por un tiempo que depende del tipo de zona:
Esto concentra los autos estacionados donde la gente llega a esa hora; el regulador compensa para que el total siga la curva. Un vehículo estacionado sale de la fila de su calle y no estorba a nadie. Si un vehículo llega a un callejón sin salida fuera de su zona destino, se reubica en una calle de su zona de origen, para que vuelva a hacer el viaje.
7 Del servidor al navegador
Enviar los 900 mil vehículos como tres flotantes de 32 bits ocuparía \(900{,}000 \times 12 \approx 10.8\) MB por actualización, cuatro veces por segundo. En cambio, cada navegador pide solo el recuadro que tiene en pantalla, \([\text{lat}_s, \text{lat}_n] \times [\text{lon}_o, \text{lon}_e]\), y cada vehículo viaja en 5 bytes: posición cuantizada a 16 bits relativa al recuadro y velocidad a 8 bits.
Con toda el área metropolitana en pantalla (0.46° de latitud, unos 51 km), el error máximo es \(0.46^\circ \times 111{,}320\ \text{m} / 131{,}070 \approx 0.4\) m; al acercarse a una colonia, milímetros. Si en el recuadro hay más de 12,000 vehículos, se envía uno de cada \(\lceil N/12{,}000 \rceil\) según su índice global, de modo que entre una actualización y otra se ven siempre los mismos vehículos y la muestra no parpadea. La ciudad completa pesa unos 60 KB por actualización; una colonia, unos 25 KB. La posición de un auto estacionado se calcula una sola vez, cuando se estaciona.
8 Limitaciones
- No hay carriles físicos, cambios de carril ni rebases (sección 2).
- En cruces sin semáforo nadie cede el paso: todos los vehículos pasan sin detenerse.
- Las rutas son locales: cada vehículo decide esquina por esquina, sin un destino final.
- El frenado es ideal, sin tiempo de reacción.
- Todos los vehículos se mueven igual: una combi o un camión se comportan como un auto, y no hay paradas de transporte público.
- La flota y las curvas de la sección 6 son estimaciones a partir del registro vehicular y de encuestas de movilidad, no conteos de Puebla.
- Los semáforos los propone la gente desde el mapa y las zonas las dibujo a mano desde el editor; el modelo es tan bueno como esos datos.
La última limitación es la que más pesa y la única que no se resuelve con código. El mapa arrancó sin semáforos y se está completando a mano, cruce por cruce, con la ayuda de quien conoce su colonia: cada semáforo que alguien propone y que pasa la revisión hace que la simulación se parezca un poco más a la ciudad real.
- Gipps, P. G. (1981). A behavioural car-following model for computer simulation. Transportation Research Part B, 15(2), 105–111.
- Treiber, M., & Kesting, A. (2013). Traffic Flow Dynamics: Data, Models and Simulation. Springer.
- Webster, F. V. (1958). Traffic Signal Settings. Road Research Technical Paper No. 39. HMSO, Londres.
- Colaboradores de OpenStreetMap. Red vial de Puebla, México. openstreetmap.org, licencia ODbL.
- INEGI (2018). Encuesta Origen Destino en Hogares de la Zona Metropolitana del Valle de México 2017.
- Conapo (2023). Índice de motorización de la zona metropolitana Puebla-Tlaxcala, citado en La Jornada, 25 de agosto de 2025.
¿No carga? Ver el video en TikTok
Ayúdame a poner los semáforos de Puebla
¿Falta un semáforo en tu calle o en tu ruta diaria? Entra a la simulación, toca 📍 Mi zona para ir a tu colonia y luego 🚦 Proponer semáforo. Lo pruebo en la simulación y, si cuadra, se queda con tu nombre.
Proponer un semáforo →Implementación: Node.js · arreglos tipados · Flask · Leaflet · Canvas · datos OpenStreetMap
La serie donde documento los sistemas, los modelos y las herramientas que construyo. Aquí las matemáticas se ven por dentro.
→ Ver todo El Laboratorio