年后来到北京找工作,也许是为了能活着,能做喜欢做的事儿,能看喜欢看的书,能玩好玩的软件,也许是为了追寻那并不清晰的梦想……
终于,再一次被北京地铁的运客量所震撼了!天通苑北——更是一个神奇的地铁站!!
经历过几次早高峰之后,发现一个比较有趣的现象:当排队的人非常多时,在长长的限流围栏中,出现了时走时停的状态。整个队列就像一个软体虫子在爬行,有些部分是停滞状态有些部分是移动状态,很有节奏和规律。故此,我打算称之为“队列蠕动”现象。嘻嘻,还算比较恰当吧,虽然还发现有什么应用价值,但却实挺有意思。实际上,在跟车队列,行军队列等密集队列中都会出现此现象。
到了地铁上,开始想为什么会出现这种现象。其实也挺简单,主要是由于两方面的原因:(1) 队列整体速度小于每个人的正常速度。主要原因就是,由于需要安检,队列中的第一个人被限速了,而其它人又不能超越;(2) 每个人从停止状态到走起来需要一个反应时间(或反应距离,即当前面的人走过一小段距离之后自己才开始起步)。
于是,回家后用Mathematica模拟了一下这一现象。期间,又发现队列蠕动现象还与每个人的最大速度,最小速度,人与人的最大间距,最小间距有一定的关系。另外,除队列中的第一个人之外,其它人的运动状态只与他和他前面的人之间的距离有关(实际中与他前面人的运动状态也有关,但这没有间距的影响大,为了简便忽略之)。
如果将每个人的速度看成一个变量,而且只有增加、减少和不变3种状态,那么整个队列就组成一个向量。而且此向量中的每一个状态都可以由上一个状态确定。在形式上,它与马尔可夫过程(Markov Process)非常相似,只不过这是一个确定过程,而且最后会达到一种稳态。
最后,给出一张演示图片和Mma代码以供大家玩耍。
下面是代码截图,可复制的代码在最后面。
Remove["Global`*"]
NN = 20;(*人数*)
nn = 1000;(*计算次数*)
udt = 0.5;(*更新时间间隔*)
aa = 3 Pi/2.;(*NN个点分布在aa弧度内*)
t = 0;(*初始时间*)
ps = 0.02;(*点的尺寸*)
rt = Pi/40;(*反应间距,大于此间距才起步*)
limitv = Pi/700.;(*领头的速度,角速度*)
minv = Pi/500.;(*起步速度,角速度*)
maxv = Pi/250.;(*最大速度,角速度*)
mins = Pi/60.;(*最小间距,小于此间距时,速度为0*)
maxs = Pi/6.;(*最大间距,大于,此间距时,速度为maxv*)
ss = Table[0, {Range[nn]}];
vv = ss;
ss[[1]] = Table[N[aa n/NN], {n, 1, NN}];(*位置列表,角度*)
vv[[1]] = Table[0, {Range[NN]}];(*速度列表,上一次速度*)
fv[s_] := a Log[s] + b;(*自定义起步速度函数模型*)
sv = NSolve[{fv[mins] == minv, fv[maxs] == maxv}, {a,
b}];(*求解起步速度函数中的参数,下面是两种其它的速度函数*)
(*fv[s_]:=a (s-b)^2;
sv=NSolve[{fv[mins]==minv,fv[maxs]==maxv,b>mins},{a,b}];*)
(*fv[s_]:=a s+b;
sv=NSolve[{fv[mins]==minv,fv[maxs]==maxv},{a,b}];*)
nv[s_, v_] :=
If[s > maxs, Return[maxv],
If[s > mins + rt, Return[(fv[s] /. sv)[[1]]],
If[s > mins && v > 0, Return[(fv[s] /. sv)[[1]]],
Return[0]]]];(*当前速度计算公式*)
nt[ls_, xx_] :=
Return[Table[
If[k == NN, {limitv udt + ls[[NN]],
limitv}, {nv[ls[[k + 1]] - ls[[k]], xx[[k]]] udt + ls[[k]],
nv[ls[[k + 1]] - ls[[k]], xx[[k]]]}], {k, 1,
NN}]];(*以列的形式,生成新的位置列表和速度列表,角度*)
Do[
ss[[k + 1]] = (nt[ss[[k]], vv[[k]]])[[;; , 1]];
vv[[k + 1]] = (nt[ss[[k]], vv[[k]]])[[;; , 2]];
, {k, 1, nn - 1}];
(*计算并存储数据*)
Do[k; Pause[0.005], {k, 1, nn}];
k = nn;
Dynamic[Show[{ListPlot[Transpose[{Cos[ss[[k]]], Sin[ss[[k]]]}],
Axes -> False, PlotRange -> {{-1.2, 1.2}, {-1.2, 1.2}},
AspectRatio -> Automatic, PlotStyle -> PointSize[ps]],
Graphics[{Circle[{0, 0}, 1 - 2 ps], Circle[{0, 0}, 1 + 2 ps]}]}]]
(*实时绘图*)