1 package org.opentrafficsim.road.gtu.following;
2
3 import org.djunits.unit.AccelerationUnit;
4
5
6
7
8
9
10
11
12
13
14
15 public class IDM extends AbstractGTUFollowingModel
16 {
17
18 private final Length.Rel s0;
19
20
21 private final Acceleration.Abs a;
22
23
24 private final Acceleration.Abs b;
25
26
27 private final Time.Rel tSafe;
28
29
30
31
32
33 private final Time.Rel stepSize = new Time.Rel(0.5, SECOND);
34
35
36
37
38
39 private final double delta;
40
41
42
43
44 public IDM()
45 {
46 this.a = new Acceleration.Abs(1.56, METER_PER_SECOND_2);
47 this.b = new Acceleration.Abs(2.09, METER_PER_SECOND_2);
48 this.s0 = new Length.Rel(3, METER);
49 this.tSafe = new Time.Rel(1.2, SECOND);
50 this.delta = 1d;
51 }
52
53
54
55
56
57
58
59
60
61
62
63
64 public IDM(final Acceleration.Abs a, final Acceleration.Abs b, final Length.Rel s0, final Time.Rel tSafe, final double delta)
65 {
66 this.a = a;
67 this.b = b;
68 this.s0 = s0;
69 this.tSafe = tSafe;
70 this.delta = delta;
71 }
72
73
74
75
76
77
78
79 private Speed.Rel vDes(final Speed.Abs speedLimit, final Speed.Abs followerMaximumSpeed)
80 {
81 return new Speed.Rel(Math.min(this.delta * speedLimit.getSI(), followerMaximumSpeed.getSI()), METER_PER_SECOND);
82 }
83
84
85 public final Acceleration.Abs computeAcceleration(final Speed.Abs followerSpeed, final Speed.Abs followerMaximumSpeed,
86 final Speed.Abs leaderSpeed, final Length.Rel headway, final Speed.Abs speedLimit)
87 {
88
89
90 Speed.Rel dV = followerSpeed.minus(leaderSpeed);
91 Acceleration.Abs aFree =
92 new Acceleration.Abs(this.a.getSI()
93 * (1 - Math.pow(followerSpeed.getSI() / vDes(speedLimit, followerMaximumSpeed).getSI(), 4)),
94 METER_PER_SECOND_2);
95 if (Double.isNaN(aFree.getSI()))
96 {
97 aFree = new Acceleration.Abs(0, AccelerationUnit.SI);
98 }
99 Acceleration.Rel logWeightedAccelerationTimes2 =
100 new Acceleration.Rel(Math.sqrt(this.a.getSI() * this.b.getSI()), METER_PER_SECOND_2).multiplyBy(2);
101
102
103
104 Length.Rel right =
105 followerSpeed.toRel().multiplyBy(this.tSafe)
106 .plus(dV.multiplyBy(followerSpeed.toRel().divideBy(logWeightedAccelerationTimes2)));
107
108
109
110
111 if (right.getSI() < 0)
112 {
113
114 right = new Length.Rel(0, METER);
115 }
116 Length.Rel sStar = this.s0.plus(right);
117 if (sStar.getSI() < 0)
118 {
119 System.out.println("sStar is negative");
120 sStar = new Length.Rel(0, METER);
121 }
122
123 Acceleration.Rel aInteraction =
124 new Acceleration.Rel(-Math.pow(this.a.getSI() * sStar.getSI() / headway.getSI(), 2), METER_PER_SECOND_2);
125 Acceleration.Abs newAcceleration = aFree.plus(aInteraction);
126 if (newAcceleration.getSI() * this.stepSize.getSI() + followerSpeed.getSI() < 0)
127 {
128
129 newAcceleration = new Acceleration.Abs(-followerSpeed.getSI() / this.stepSize.getSI(), METER_PER_SECOND_2);
130 }
131
132 return newAcceleration;
133 }
134
135
136 @Override
137 public final Time.Rel getStepSize()
138 {
139 return new Time.Rel(this.stepSize);
140 }
141
142
143 @Override
144 public final Acceleration.Abs maximumSafeDeceleration()
145 {
146 return this.b;
147 }
148
149
150 @Override
151 public final String getName()
152 {
153 return "IDM";
154 }
155
156
157 @Override
158 public final String getLongName()
159 {
160 return String.format("%s (a=%.1fm/s\u00b2, b=%.1fm/s\u00b2, s0=%.1fm, tSafe=%.1fs, delta=%.2f)", getName(),
161 this.a.getSI(), this.b.getSI(), this.s0.getSI(), this.tSafe.getSI(), this.delta);
162 }
163
164 }