버스 뭉침은 우연이 아니다 — 등간격이 스스로 무너지는 이유

버스 뭉침은 등간격으로 배차된 버스들이 승객 축적 되먹임 때문에 스스로 무너져 두세 대씩 붙어 오는 현상이다. 정류장에서만 국소적으로 결합하는 쿠라모토형 모델로 보면, 러시아워에도 버스 전체가 한 덩어리로 붙는 게 아니라 여러 개의 부분 클러스터가 형성된다는 사실이 드러난다.

정류장에 선 지 벌써 15분, 도착 안내판의 ‘곧 도착’은 아까부터 그대로다. 그러다 같은 번호 버스 두 대가 앞뒤로 바짝 붙어 들어오고, 그 뒤로는 또 한참 동안 아무 버스도 오지 않는다.

누구나 한 번쯤 겪는 이 장면을 흔히 기사 탓, 배차 탓, 그날의 교통 탓으로 돌린다. 그런데 이상한 사실이 하나 있다. 완벽하게 똑같은 버스를 완벽한 등간격으로 내보내도 뭉침은 똑같이 일어난다. 범인은 누군가의 실수가 아니라 ‘등간격’이라는 상태 그 자체다. 이 멀쩡해 보이는 상태가 왜 스스로 무너지는지는, 정류장 한 곳에서 벌어지는 일만 들여다보면 풀린다.

밝은 크림색 인포그래픽. 등간격으로 계획된 유령 버스 배차 위로, 실제로는 버스 두 대가 바짝 붙고 그 뒤에 긴 공백과 정류장에 쌓인 승객이 겹쳐 그려져 있다.

정류장이 만드는 되먹임 — 버스 뭉침은 왜 저절로 일어나는가

정류장에 버스가 도착하면 그동안 쌓여 있던 승객이 한꺼번에 올라탄다. 열쇠는 ‘그동안’이 얼마나 길었느냐에 있다. 앞차가 지나간 지 오래됐을수록 기다린 승객은 더 많고, 태우는 데 걸리는 시간도 그만큼 길어진다. 그러니까 버스가 정류장에서 문을 열고 있는 정차시간은, 바로 앞차와 벌어진 시간 간격에 거의 정비례한다.

이 관계는 한 줄로 적을 만큼 단순하다.

(1) $$ \tau_{ij} = k_j \, \Delta t_{ij}, \qquad k_j = \frac{s_j}{l} $$

식 1의 왼쪽은 정류장 j에서 버스 i의 정차시간, 오른쪽은 그 버스가 앞차와 벌어진 시간 간격이다. 둘은 곧게 비례한다. 비례계수 $k_j$는 정류장의 승객 도착률을 승차 처리율로 나눈 값일 뿐이다. 관계식 자체는 이렇게 곧은 직선이다. 그런데 이 선형 관계 하나가 버스들 사이에는 고약한 비선형 결합을 빚어낸다.

되먹임의 고리를 한 바퀴 따라가 보자. 어쩌다 조금 늦은 버스는 앞차와의 간격이 벌어진다. 간격이 벌어지면 태울 승객이 더 쌓이고, 더 많이 태우느라 더 늦어진다. 늦을수록 다음 정류장에서 간격은 더 벌어지고, 그래서 또 더 늦어진다.

반대로 어쩌다 조금 빠른 버스는 앞차를 바짝 뒤쫓아 태울 손님이 적으니 점점 더 빨라진다. 작은 어긋남이 스스로 몸집을 불리는 것이다. 등간격은 분명 평형이지만, 한 번 건드리면 제자리로 돌아오지 않고 무너지는 불안정한 평형이다.

되먹임 규칙 자체는 한 문장이면 적는다. 앞 간격이 넓은 버스일수록 다음 순간 더 뒤처진다 — 이것뿐이다. 완벽한 등간격에 1%짜리 잡음만 살짝 얹은 뒤 이 규칙 한 줄을 반복하면 무슨 일이 벌어질까.

import random, statistics

def simulate_headways(n_buses, k, steps, seed=1):
    rng = random.Random(seed)
    gap = 1.0 / n_buses
    # 완벽한 등간격에 ±1% 잡음만 준 초기 상태
    h = [gap * (1 + rng.uniform(-0.01, 0.01)) for _ in range(n_buses)]
    for _ in range(steps):
        # 앞 간격이 넓은 버스일수록 더 뒤처진다: h_i <- (1+k)*h_i - k*h_{i+1}
        h = [(1 + k) * h[i] - k * h[(i + 1) % n_buses] for i in range(n_buses)]
    return statistics.pstdev(h)

for t in (0, 5, 10, 15):
    std = simulate_headways(n_buses=6, k=0.1, steps=t)
    print(f"{t:2d}스텝  headway 표준편차 = {std:.4f}")
 0스텝  headway 표준편차 = 0.0008
 5스텝  headway 표준편차 = 0.0016
10스텝  headway 표준편차 = 0.0031
15스텝  headway 표준편차 = 0.0062

결과는 한 방향으로만 흐른다. 간격의 표준편차가 스텝을 거듭할수록 커진다. 처음엔 거의 고른 간격이었는데 열댓 스텝 만에 편차가 일곱 배 넘게 벌어진다. 모든 버스가 완전히 똑같은 규칙을 따르는데도 그렇다. 이 벌어짐을 노선 전체로 펼쳐 보면 그림 1처럼 나타난다.

가로축은 노선 위치, 세로축은 시간인 시공간도. 처음엔 고른 등간격 줄무늬가 시간이 갈수록 두 줄씩 수렴해 합쳐진다.
그림 1. 자연진동수가 완전히 같은 버스 6대를 등간격으로 출발시킨 시공간도. 처음의 고른 줄무늬가 시간이 지나며 두세 개씩 합쳐진다.

고르던 줄무늬가 시간이 갈수록 몇 가닥씩 겹쳐 붙는다. 되먹임 하나가 등간격을 이렇게 무너뜨린다. 다만 이 그림에는 짚고 넘어갈 전제가 하나 숨어 있다.

이 데모는 모든 버스의 자연진동수가 완전히 같은 극단적인 경우다. 이 극한에서는 완전 뭉침의 임계값이 공식상 0으로 떨어져, 결합이 조금이라도 있으면 뭉침이 일어난다. 실제 버스는 기사와 차량이 달라 자연속도가 조금씩 다른데, 그 차이가 이야기를 어떻게 바꾸는지는 뒤에서 실측으로 다시 만난다.

버스를 진동자로 놓고 보면 — 쿠라모토와 닮았지만 다른 결합

같은 현상을 시점만 바꿔 보면, 익숙한 물리 문제가 얼굴을 내민다. 순환노선을 도는 버스 한 대는 일정한 주기로 노선을 한 바퀴씩 도는 진동자다. 노선 위에는 이런 진동자가 여럿 올라앉아, 저마다 앞차와의 간격을 통해 서로의 리듬에 간섭한다. 버스가 두세 대씩 붙는 뭉침은, 진동자들의 위상이 하나로 맞물리는 위상 잠금(phase locking)인 셈이다.

원형 트랙 위에 놓인 버스들이 결합된 진동자처럼 서로의 위상을 밀고 당기는 모습.
그림 2. 순환노선을 도는 버스들을 원형 트랙 위 결합 진동자로 재해석한 그림.

그림 2처럼 진동자들이 서로의 위상을 끌어당기는 그림에는 물리학의 오래된 이름이 붙어 있다. 바로 쿠라모토(Kuramoto) 모델이다.

반딧불이가 한 박자로 깜빡이고 심장의 박동조율세포들이 한 리듬에 모이는, 그 동기화와 뿌리가 같다.

다만 버스의 결합은 표준 쿠라모토와 세 군데에서 결정적으로 갈라진다. 표준 모델의 진동자들은 노선 어디서나 서로 끌어당기고(전역), 모든 상대와 평균적으로 결합하며(평균장), 그 영향이 양방향으로 오간다. 버스는 어느 쪽도 아니다. 결합은 정류장에서만 일어나고(이산적), 오직 바로 앞차와의 간격에만 반응하며(국소적), 뒤차가 앞차를 당길 뿐 앞차는 뒤차에 무심하다(단방향). 정류장에서만, 바로 앞차와만, 한 방향으로만 — 이 세 제약이 버스 뭉침을 표준 동기화와 다른 문제로 만든다.

결합이 세지면 전부 붙는다 — 그런데 임계값이 있다

그렇다면 이 국소적이고 단방향인 결합이 언제 뭉침으로 넘어가는지 따져 볼 차례다. 결합의 세기를 하나의 숫자 k로 재면, 이 문제엔 뚜렷한 문턱이 드러난다. k가 임계값 $k_c(N)$을 넘는 순간 N대 버스가 전부 한 덩어리로 맞물리는 완전 위상 잠금으로 상전이한다. 여기서 N은 노선 위를 도는 버스의 수다. 임계값은 이렇게 쓸 수 있다.

(2) $$ k_c(N) = \frac{1}{M} \sum_{i=1}^{N-1} \left( 1 – \frac{\omega_N}{\omega_i} \right) $$

식 2에서 M은 정류장 수이고, 각 버스의 자연진동수는 $\omega_i$로 쓴다. 번호는 빠른 버스부터 매겨 $\omega_1$이 가장 빠르고 $\omega_N$이 가장 느리다. 식의 생김새보다 눈여겨볼 건, 이 값이 N에 따라 어느 쪽으로 움직이느냐다. 버스가 많아질수록 합에 더해지는 항이 늘어, 완전 뭉침의 임계값은 오히려 높아진다.

숫자로 보면 더 분명하다. 버스가 2대일 때 임계값은 0.028이다. 3대면 0.045, 6대면 0.091, 7대면 0.108로 계속 커진다. 직관과는 정반대다. 버스가 많을수록 전부가 한 덩어리로 붙기는 더 어려워지는데, 다 함께 잠기려면 그만큼 더 센 결합이 필요하기 때문이다.

위상 잠금이 실제로 일어나는 모양

임계값을 넘는다는 게 상태 공간에서 어떤 모습인지는, 버스 두 대의 위상차 $\Delta\varphi$ 하나만 뒤쫓으면 눈에 들어온다. 그림 3는 이 위상차가 시간에 따라 어디로 흘러가는지를 그린 벡터장이다. 결합 k가 임계값보다 크면 위상차가 0으로 빨려드는 끌개가 생긴다. 두 버스가 끝내 한 위상으로 맞물린다는 뜻이다. k가 임계값에 못 미치면 그런 끌개는 없고, 위상차는 잠기지 않은 채 계속 돌며 진동한다.

버스 두 대의 위상차를 상태변수로 둔 벡터장. 결합이 크면 위상차 0으로 수렴하는 끌개가, 작으면 순환하는 궤적이 나타난다.
그림 3. 위상차의 벡터장. 결합 k가 임계값을 넘으면 위상차가 0으로 모이는 끌개가 생기고(완전 잠금), 넘지 못하면 위상차가 계속 순환한다.

이 지점에서 앞의 두 장면을 화해시켜야 한다. 섹션 1의 시공간도는 모든 버스의 자연진동수가 완전히 같은 극단이었다. 그 극한에서는 식 2의 각 항에 든 $\omega_N/\omega_i$가 전부 1이 되어 임계값이 0으로 주저앉는다. 문턱이 아예 없으니 결합이 조금만 있어도 곧장 뭉친다.

하지만 현실의 버스는 기사도 차량도 저마다 달라 자연속도가 조금씩 어긋나 있다.

바로 이 흩어짐이 임계값을 0에서 밀어 올려, 뭉침에도 넘어야 할 문턱을 세운다. 그러니 ‘등간격은 무조건 무너진다’는 시공간도의 이야기와 ‘러시아워에도 완전히 뭉치지는 않는다’는 다음 장의 이야기는, 서로 다른 진동수 전제 위에 나란히 서 있는 셈이다.

러시아워에도 완전 뭉침은 아니다 — 부분 위상 잠금 클러스터

이제 실측이 이 문턱의 어디쯤에 앉는지 볼 차례다. 한산한 시간대의 결합세기는 낮다. 버스 2대 시나리오에서 k는 0.024로, 완전 뭉침 임계값 0.028을 살짝 밑돈다. 3대 시나리오는 0.018로 임계값 0.045에 한참 못 미친다. 이 시간대에 이따금 보이는 뭉침은 기사별 속도 차가 만드는 일시적 잡음일 뿐, 지속되는 잠금이 아니다.

러시아워는 이야기가 다르다. 버스가 6~7대로 늘고 승객이 몰리는 오전 시간대에는 결합세기가 0.065까지 오른다. 그림 4는 N에 따른 완전 뭉침 임계값 곡선 위에 바로 이 값을 얹은 그림이다. 러시아워의 0.065는 부분 위상 잠금 기준선 0.028을 훌쩍 넘지만, 6대·7대의 완전 뭉침 임계값 0.091과 0.108에는 닿지 못한다. 곡선 아래, 기준선 위 — 부분 위상 잠금 영역에 정확히 걸린다.

가로축 버스 대수 N, 세로축 완전 위상 잠금 임계값의 우상향 곡선. 부분 잠금 기준선 0.028을 수평 점선으로, 러시아워 실측 0.065를 곡선 아래·기준선 위의 점으로 표시.
그림 4. N이 커질수록 높아지는 완전 위상 잠금 임계값 곡선. 러시아워 실측치 0.065는 부분 잠금 기준선(0.028)과 완전 잠금 임계값 사이에 놓인다.

이 위치가 말해 주는 건 분명하다. 러시아워에도 버스 전부가 한 덩어리로 뭉치지는 않고, 대신 몇 대씩 무리 짓는 부분 클러스터가 여기저기 생긴다. 러시아워일수록 뭉침이 심해진다는 통념과 달리, 버스가 많아질수록 완전 뭉침의 문턱은 되레 높아지는 탓이다. 논문도 이 대목을 한 문장으로 못 박아 둔다.

…thankfully, otherwise this would be a ridiculously inefficient system.

출처: Saw et al., Scientific Reports 9, 6887 (2019)

완전한 동기화가 일어났다면 버스들이 한 덩어리로 몰려 노선을 돌았을 테고, 그건 교통 시스템으로선 말이 안 되는 비효율이었을 것이다. 다행히 실제 노선은 그 지경까지 가지 않는다.

배차를 아무리 정밀하게 짜도 뭉침이 남는 이유

그렇다면 배차를 더 촘촘하고 정확하게 짜면 뭉침이 사라질까. 여기에 함정이 있다.

배차 간격을 아무리 정밀하게 다시 짜도, 승객 축적 되먹임 자체가 그대로 남아 있으면 뭉침은 다시 자란다. 재조정은 등간격 상태를 잠깐 회복시킬 뿐이고, 그 등간격이 애초에 불안정한 평형이라 작은 어긋남부터 또 증폭된다.

결국 문제는 배차 값이 틀렸다는 게 아니라, 등간격을 무너뜨리는 되먹임 고리가 여전히 살아 있다는 데 있다. 그래서 실무의 개입도 배차표를 다시 그리는 쪽이 아니라 고리 자체를 끊는 쪽을 향한다.

현장에서 통하는 대표적 개입은 정류장 홀딩(holding)이다. 계획보다 앞서가는 버스를 정류장에 일부러 잠깐 붙잡아 뒤차와의 간격을 되돌리는 방법이다. 배차표를 새로 계산하는 게 아니라, ‘앞선 버스일수록 손님이 적어 더 빨라진다’는 되먹임의 한 축을 그 자리에서 눌러 끊는다는 점이 핵심이다.

그 개입이 어떻게 고리를 끊는지는 한 걸음씩 따라가면 보인다. 앞서가던 버스를 정류장에 잠깐 붙잡는다. 그러면 뒤차와 벌어졌던 간격이 도로 좁혀지고, 그 사이 쌓일 승객이 줄어든다. 태울 손님이 준 뒤차는 더 늦춰질 이유가 없다. ‘앞선 버스일수록 손님이 적어 더 빨라진다’던 되먹임의 한 축이, 그 짧은 붙잡음 하나로 제자리에서 끊긴다. 고리 하나가 등간격을 무너뜨렸듯, 그 고리를 한 지점에서 끊어 주는 것만으로 붙어 오던 두 대는 다시 제 간격을 찾아간다.

더 읽기