├── .gitignore ├── model ├── model.h5 └── model_parameter.txt ├── run.py ├── LICENSE ├── README.md ├── plot.py ├── model.py ├── train.py └── preprosessing.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /model/model.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjpetersik/neural-network-car-following-model/HEAD/model/model.h5 -------------------------------------------------------------------------------- /model/model_parameter.txt: -------------------------------------------------------------------------------- 1 | 1.274997327044025042e+01 2 | 4.559743381169133691e+00 3 | 6.976576745663901846e+00 4 | 2.165888601637672828e+00 5 | 2.000000000000000000e+00 6 | 1.000000000000000000e+00 7 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Mon Apr 30 16:09:01 2018 5 | 6 | @author: paul 7 | """ 8 | 9 | from model import model 10 | 11 | 12 | import numpy as np 13 | import matplotlib.pyplot as plt 14 | import time 15 | 16 | print "Run ANN model #################" 17 | 18 | N = 22 19 | L = 150. 20 | dt = 1./3. 21 | tmax = 250 22 | xpert= np.zeros(N) 23 | xpert = 1.*np.sin(2*np.pi/float(N)*np.arange(N)) 24 | #xpert = np.random.uniform(0.,1.,N) 25 | 26 | # Model simulation 27 | start = time.time() 28 | 29 | m = model(N,L,tmax,dt,xpert) 30 | m.initCars() 31 | m.integrate() 32 | 33 | end = time.time() 34 | 35 | print "calculation time: "+str(end-start) 36 | 37 | #%% plot various variables 38 | plt.close("all") 39 | from plot import plots 40 | plots(m) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 paul1112 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Neural network car-following model 2 | 3 | In this code a feed-forward neural network or a recurrent neural network is trained on data 4 | from a traffic jam experiment conducted by Sugiyama et al. (2008) (http://iopscience.iop.org/article/10.1088/1367-2630/10/3/033001/meta). In this experiment cars drove in a circuit of 230m. Two experiments were done (case 1 and 2) with 22 or 23 cars, respectively. With the script "preprocessing.py" the headway, velocity and acceleration is calculated for each car. The neural network is given the task to predict the acceleration for a car of the subsequent data point based on the car's headway and the velocity (and if wanted from cars ahead). The training is done in the script "train.py". In the script "run.py" the trained neural network is used to simulate cars driving on a circuit. 5 | 6 | ## Requirements 7 | Keras 8 | 9 | Numpy 10 | 11 | matplotlib 12 | 13 | pandas 14 | 15 | ## Data 16 | The position data of the cars in the experiment can be downloaded here: 17 | http://iopscience.iop.org/article/10.1088/1367-2630/10/3/033001/meta 18 | 19 | ## Remark 20 | 21 | Up until now, the trained neural network often produces crashes. Mostly, because cars start to drive backwards. If just positive velocities are allowed (see model.integration_procedure), less crashes occur. 22 | -------------------------------------------------------------------------------- /plot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Wed Mar 14 18:25:54 2018 5 | 6 | @author: paul 7 | """ 8 | 9 | import numpy as np 10 | import matplotlib.pyplot as plt 11 | 12 | from scipy.interpolate import griddata 13 | 14 | fs = 14 15 | 16 | def plots(model): 17 | 18 | # ============================================================================= 19 | # hystersis loop 20 | # ============================================================================= 21 | fig, ax = plt.subplots() 22 | time = model.time 23 | x = model.x 24 | dot_x = model.dot_x 25 | Delta_x = model.Delta_x 26 | distance = model.distance 27 | 28 | car = 0 29 | start = 0 30 | end = model.iters 31 | iters = end - start 32 | jump = 1 # just plot every 3rd iteration to save time 33 | 34 | fs =14 35 | c = np.linspace(model.time[start],model.time[end-1],iters) 36 | 37 | #ax.set_title("velocity vs. headway, car=" + str(car)) 38 | ax_scatter = ax.scatter(Delta_x[car,start:end:jump],dot_x[car,start:end:jump],marker="x",s=10,c=c[::jump]) 39 | ax.set_xlabel('headway [m]', fontsize = fs) 40 | ax.set_ylabel('velocity [s]',fontsize = fs) 41 | #ax.set_ylim(0,10) 42 | #ax.set_xlim(0,15) 43 | ax.tick_params(direction="in") 44 | ax.set_title(r'ANN, $L=$'+str(model.L)) 45 | cb=fig.colorbar(ax_scatter, ax=ax) 46 | cb.set_label(label="time [s]",size=fs) 47 | # ============================================================================= 48 | # trajectories 49 | # ============================================================================= 50 | fig, ax = plt.subplots() 51 | for j in np.arange(0,model.N,jump): 52 | diffx = np.roll(x[j,:],-1)-x[j,:] 53 | masked_x = np.ma.array(x[j,:]) 54 | masked_x[diffx<-100] = np.ma.masked 55 | ax.plot(time,masked_x,lw=0.8,c="red") 56 | #ax.set_title("car positions", fontsize = fs) 57 | ax.set_ylabel("position [m]", fontsize = fs) 58 | ax.set_xlabel("time [s]", fontsize = fs) 59 | ax.tick_params(direction="in") 60 | # ============================================================================= 61 | # hovmöller velocites 62 | # ============================================================================= 63 | fig, ax = plt.subplots() 64 | jump = int(model.tmax/20) # just consider every 20 iteration for the interpolation to save time 65 | x_data = x[:,::jump] 66 | dot_x_data = dot_x[:,::jump] 67 | t_data = time[::jump] 68 | lent = len(t_data) 69 | 70 | grid_x, grid_t = np.meshgrid(distance,time) 71 | x_point = x_data.reshape(model.N*lent,1) 72 | t_point = np.tile(t_data,model.N) 73 | t_point = t_point.reshape(model.N*lent,1) 74 | points = np.concatenate((x_point,t_point),axis=1) 75 | dot_x_values = dot_x_data.reshape(model.N*lent) 76 | grid_dot_x = griddata(points, dot_x_values, (grid_x, grid_t), method='linear') 77 | 78 | cmap = "gist_ncar" 79 | contours = np.linspace(0.,9,21) 80 | cf = ax.contourf(time,distance,grid_dot_x.T,contours,cmap=cmap, extend="both") 81 | ax.set_xlabel("time [s]", fontsize = fs) 82 | ax.set_ylabel("position [m]", fontsize = fs) 83 | ax.tick_params(direction="in") 84 | #ax.set_title("velocity", fontsize = fs) 85 | cb=fig.colorbar(cf, ax=ax) 86 | cb.set_label(label="velocity [m/s]", size=14) 87 | # ============================================================================= 88 | # standard deviation headway 89 | # ============================================================================= 90 | fig, ax = plt.subplots() 91 | #ax.set_title("std($\Delta$x) vs. t") 92 | ax.plot(time,Delta_x.std(axis=0)) 93 | ax.set_xlabel("time [s]",fontsize = fs) 94 | ax.set_ylabel("std($\Delta$x) [m]",fontsize = fs) 95 | ax.tick_params(direction="in") 96 | #ax.set_xlim(0,250) 97 | #ax.set_ylim(0,6) 98 | 99 | # ============================================================================= 100 | # standard deviation velocity 101 | # ============================================================================= 102 | fig, ax = plt.subplots() 103 | #ax.set_title("std($\Delta$x) vs. t") 104 | ax.plot(time,dot_x.std(axis=0)) 105 | ax.set_xlabel("time [s]",fontsize = fs) 106 | ax.set_ylabel("std($\dot{x}$) [m/s]",fontsize = fs) 107 | ax.tick_params(direction="in") 108 | #ax.set_xlim(0,250) 109 | #ax.set_ylim(0,4) -------------------------------------------------------------------------------- /model.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Thu Feb 15 11:43:14 2018 5 | 6 | @author: paul 7 | """ 8 | import numpy as np 9 | from tensorflow import keras as kr 10 | 11 | class model(object): 12 | def __init__(self,N,L,tmax,dt,xpert): 13 | self.N = N 14 | self.L = L 15 | self.distance = np.arange(0,self.L,1) #array for distance 16 | self.xpert = xpert 17 | 18 | self.tmax = tmax 19 | self.dt = dt 20 | self.iters = abs(int(self.tmax/self.dt)) 21 | self.time = np.arange(0,self.tmax,self.dt) 22 | 23 | self.loaded_tf_model = kr.models.load_model('model/model.h5') 24 | self.meanDx,self.stdDx,self.meandotx,self.stddotx,self.n_leading_cars,self.rnn = np.loadtxt('model/model_parameter.txt') 25 | self.n_leading_cars = int(self.n_leading_cars) 26 | 27 | def initCars(self,**kwargs): 28 | """ 29 | initialise 0th time step 30 | """ 31 | 32 | self.x = np.zeros(shape=(self.N,self.iters)) # position 33 | self.dot_x = np.zeros(shape=(self.N,self.iters)) # velocity 34 | self.ddot_x = np.zeros(shape=(self.N,self.iters)) # acceleration 35 | self.Delta_x = np.zeros(shape=(self.N,self.iters)) # headway 36 | 37 | self.x[:,0] = np.linspace(0,self.L,self.N) 38 | self.dot_x[:,0] = self.meandotx 39 | self.ddot_x[:,0] = 0. 40 | 41 | self.x[:,0] = self.x[:,0] + self.xpert 42 | self.Delta_x[:,0] = self.headway(self.x[:,0],self.L) 43 | 44 | def integrate(self,**kwargs): 45 | """ 46 | Integrate the model using a fortran or a python kernel 47 | """ 48 | for i in range(0,self.iters-1): 49 | self.integration_procedure(i) 50 | 51 | def integration_procedure(self,i): 52 | """ 53 | RK4 integration scheme 54 | """ 55 | h = self.dt 56 | k1 = self.acceleration(self.Delta_x[:,i],self.dot_x[:,i],self.Delta_x[:,i-1],self.dot_x[:,i-1]) 57 | self.dot_x[:,i+1] = self.dot_x[:,i] + k1*h/2 58 | 59 | k2 = self.acceleration(self.Delta_x[:,i],self.dot_x[:,i+1],self.Delta_x[:,i-1],self.dot_x[:,i-1]) 60 | 61 | self.dot_x[:,i+1] = self.dot_x[:,i] + k2*h/2 62 | k3 = self.acceleration(self.Delta_x[:,i],self.dot_x[:,i+1],self.Delta_x[:,i-1],self.dot_x[:,i-1]) 63 | 64 | self.dot_x[:,i+1] = self.dot_x[:,i] + k3*h 65 | k4 = self.acceleration(self.Delta_x[:,i],self.dot_x[:,i+1],self.Delta_x[:,i-1],self.dot_x[:,i-1]) 66 | 67 | self.ddot_x[:,i+1] = k1 68 | 69 | self.dot_x[:,i+1] = self.dot_x[:,i] + h/6. * (k1 + 2*k2 + 2*k3 + k4) 70 | 71 | # just allow postive velocities 72 | self.dot_x[self.dot_x[:,i+1]<0.,i+1] = 0. 73 | 74 | self.x[:,i+1] = self.x[:,i] + self.dot_x[:,i+1] * h 75 | 76 | self.x[:,i+1] = self.x[:,i+1]%self.L 77 | 78 | # Diagnostics 79 | self.Delta_x[:,i+1] = self.headway(self.x[:,i+1],self.L) 80 | 81 | def acceleration(self,Delta_x,dot_x,prev_Delta_x,prev_dot_x): 82 | """ 83 | returns the acceleration of cars based on an ANN 84 | """ 85 | def shape(Delta_x,dot_x): 86 | Dx = Delta_x.reshape((len(Delta_x),1)) 87 | dotx = dot_x.reshape((len(Delta_x),1)) 88 | 89 | Dx = (Dx - self.meanDx)/self.stdDx 90 | dotx = (dotx - self.meandotx)/self.stddotx 91 | 92 | X = np.concatenate((Dx[0:self.n_leading_cars,:].T,dotx[0:self.n_leading_cars,:].T),axis=1) 93 | 94 | X_all = np.zeros((self.N,len(X[0]))) 95 | 96 | # for car number 0 97 | X_all[0,:] = X 98 | 99 | for i in range(self.N-1): 100 | Dx = np.roll(Dx,-1,axis=0) 101 | dotx = np.roll(dotx,-1,axis=0) 102 | X_all[i+1,:] = np.concatenate((Dx[0:self.n_leading_cars,:].T,dotx[0:self.n_leading_cars,:].T),axis=1) 103 | 104 | if self.rnn: 105 | X_all = X_all.reshape(X_all.shape[0],1,X_all.shape[1]) 106 | return X_all 107 | 108 | if self.rnn: 109 | X = shape(Delta_x,dot_x) 110 | # X_prev = shape(prev_Delta_x,prev_dot_x) 111 | # 112 | # X = np.concatenate((X,X_prev),axis=1) 113 | else: 114 | X = shape(Delta_x,dot_x) 115 | 116 | # predict acceleration 117 | ddotx = self.loaded_tf_model.predict(X) 118 | 119 | return ddotx[:,0] 120 | 121 | def headway(self,x,L): 122 | Dx = np.zeros(self.N) 123 | Dx[:-1] = ((x[1:] - x[:-1])+L)%L 124 | Dx[-1] = ((x[0] - x[-1])+L)%L 125 | return Dx 126 | 127 | -------------------------------------------------------------------------------- /train.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Thu Jul 12 08:42:16 2018 5 | 6 | @author: paul 7 | """ 8 | 9 | import numpy as np 10 | 11 | import matplotlib.pyplot as plt 12 | from tensorflow import keras as kr 13 | 14 | def normalize(x): 15 | x_mean = np.mean(x) 16 | x_std = np.std(x) 17 | x_norm = (x-x_mean)/x_std 18 | return x_norm,x_mean,x_std 19 | 20 | # ============================================================================= 21 | # Load trainings dataset 22 | # ============================================================================= 23 | data_dir = "processed/" 24 | 25 | #choose case 1 or 2 26 | case = 1 27 | 28 | # number of leading cars that are used for the labels 29 | car = 0 30 | n_leading_cars = 2 31 | 32 | RNN = True 33 | 34 | # load pre processed data 35 | Dx = np.loadtxt(data_dir+"case"+str(case)+"/headway.txt") 36 | dotx = np.loadtxt(data_dir+"case"+str(case)+"/velocity.txt") 37 | ddotx = np.loadtxt(data_dir+"case"+str(case)+"/acceleration.txt") 38 | D_dotx = np.loadtxt(data_dir+"case"+str(case)+"/velocity_difference.txt") 39 | 40 | # pre-arrays for features, filled with data to predict acceleration 41 | Dx_append = np.array(Dx[car:car+n_leading_cars,:]) 42 | dotx_append = np.array(dotx[car:car+n_leading_cars,:]) 43 | D_dotx_append = np.array(D_dotx[car:car+n_leading_cars,:]) 44 | # pre-array for labels, filled with acceleration 45 | ddotx_append = np.array(ddotx[car,:]) 46 | 47 | #for i in range(1,3): 48 | # Dx_append = np.concatenate((Dx_append,np.roll(Dx,i,axis=1)[0:n_leading_cars,:]),axis=0) 49 | # dotx_append = np.concatenate((dotx_append,np.roll(dotx,i,axis=1)[0:n_leading_cars,:]),axis=0) 50 | 51 | ### use all data 52 | #for i in range(1,5): 53 | # Dx_append = np.concatenate((Dx_append,np.roll(Dx,i,axis=0)[0:n_leading_cars,:]),axis=1) 54 | # dotx_append = np.concatenate((dotx_append,np.roll(dotx,i,axis=0)[0:n_leading_cars,:]),axis=1) 55 | # D_dotx_append = np.concatenate((D_dotx_append,np.roll(D_dotx,i,axis=0)[0:n_leading_cars,:]),axis=1) 56 | # ddotx_append = np.concatenate((ddotx_append,np.roll(ddotx,i,axis=0)[0,:]),axis=0) 57 | 58 | # transpose array because time need to the first array dimension 59 | Dx = Dx_append.T 60 | dotx = dotx_append.T 61 | D_dotx = D_dotx_append.T 62 | 63 | # normalize input data (for a better ANN prediction) 64 | Dx, meanDx, stdDx = normalize(Dx) 65 | dotx, meandotx, stddotx = normalize(dotx) 66 | D_dotx, meanD_dotx, stdD_dotx = normalize(D_dotx) 67 | 68 | # merge features into one big label array 69 | #X = np.concatenate((Dx,dotx,D_dotx),axis=1) 70 | X = np.concatenate((Dx,dotx),axis=1) 71 | 72 | if RNN: 73 | X = X.reshape(X.shape[0],1,X.shape[1]) 74 | #Xnew = np.concatenate((X,np.roll(X,1,axis=0)),axis=1) 75 | #X = Xnew 76 | 77 | # rename label for a clearer code 78 | y = ddotx_append.T 79 | 80 | #%% ============================================================================= 81 | # # build and train the model 82 | # ============================================================================= 83 | model = kr.Sequential() 84 | 85 | if RNN: 86 | model.add(kr.layers.LSTM(100, activation='relu', input_shape=(X.shape[1],X.shape[2]))) 87 | model.add(kr.layers.Dropout(0.2)) 88 | model.add(kr.layers.Dense(10, activation='relu')) 89 | 90 | else: 91 | model.add(kr.layers.Dense(100, input_dim=len(X[0]),activation='relu')) 92 | model.add(kr.layers.Dropout(0.2)) 93 | model.add(kr.layers.Dense(50, activation='relu')) 94 | model.add(kr.layers.Dropout(0.2)) 95 | model.add(kr.layers.Dense(10, activation='relu')) 96 | 97 | model.add(kr.layers.Dense(1, activation='linear')) 98 | 99 | optimizer = kr.optimizers.Adam(lr=0.0001, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0., amsgrad=False) 100 | 101 | model.compile(loss="mean_squared_error", optimizer=optimizer, metrics=['mse']) 102 | 103 | es = kr.callbacks.EarlyStopping(monitor='val_loss', 104 | min_delta=0.0, 105 | patience=500, 106 | verbose=0, mode='auto') 107 | 108 | history = model.fit(X, y, epochs=10000, batch_size=X.shape[0],verbose=2,shuffle=True,validation_split=0.1,callbacks=[es]) 109 | 110 | model.save('model/model.h5') 111 | 112 | np.savetxt("model/model_parameter.txt",[meanDx,stdDx,meandotx,stddotx,n_leading_cars,RNN]) 113 | 114 | #%% ============================================================================= 115 | # Plot history 116 | # ============================================================================= 117 | plt.close("all") 118 | 119 | # plot learning metric 120 | plt.figure(1) 121 | 122 | plt.plot(history.history['mean_squared_error'],label="MSE training") 123 | plt.plot(history.history['val_mean_squared_error'],label="MSE validation") 124 | plt.legend(frameon=False) 125 | 126 | #%% show predicition against data 127 | 128 | filename = 'model/model.h5' 129 | model = kr.models.load_model(filename) 130 | 131 | y_prediction = model.predict(X) 132 | plt.figure(2) 133 | 134 | plt.plot(y,label="data") 135 | plt.plot(y_prediction,label="prediction") 136 | plt.legend() 137 | 138 | # plot weights of first layer 139 | weights = model.layers[0].get_weights() 140 | cm=plt.cm.bwr 141 | C=plt.matshow(weights[0].T,cmap=cm,vmin=-1,vmax=1) 142 | plt.ylabel("to hidden layer neuron",fontsize=14) 143 | plt.xlabel("from input neuron",fontsize=14) 144 | plt.gca().xaxis.tick_bottom() 145 | plt.colorbar(C).set_label(label="weights",size=14) 146 | 147 | C2=plt.matshow(weights[1].T,cmap=cm,vmin=-1,vmax=1) 148 | plt.ylabel("to hidden layer neuron",fontsize=14) 149 | plt.xlabel("from input neuron",fontsize=14) 150 | plt.gca().xaxis.tick_bottom() 151 | plt.colorbar(C2).set_label(label="weights",size=14) -------------------------------------------------------------------------------- /preprosessing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Fri Jul 13 18:39:50 2018 5 | 6 | @author: paul 7 | """ 8 | 9 | import numpy as np 10 | 11 | import pandas as pd 12 | import matplotlib.pyplot as plt 13 | plt.close("all") 14 | from scipy.interpolate import griddata 15 | 16 | def moveAvg(x,option): 17 | if option==1: 18 | return x 19 | 20 | summed = np.zeros_like(x[:,0:-option+1]) 21 | for i in range(option): 22 | last = -option+i+1 23 | if last == 0: 24 | summed = summed + x[:,i:] 25 | else: 26 | summed = summed + x[:,i:last] 27 | 28 | return summed/float(option) 29 | mvavg = 3 30 | 31 | #%% ============================================================================= 32 | # Load trainings dataset 33 | # ============================================================================= 34 | 35 | # cirucuit length 36 | L = 230 37 | 38 | # data directiry 39 | input_directory = "raw/" 40 | output_directory = "processed/" 41 | 42 | # read data 43 | case = 1 44 | raw_data = pd.read_csv(input_directory+"case"+str(case)+".data",skiprows=14,sep='\s+', names=["position","time"],skip_blank_lines=False) 45 | 46 | raw_position = raw_data["position"] 47 | raw_time = raw_data["time"] 48 | 49 | # get array sizes 50 | n_cars = len(raw_time.index[raw_time.apply(np.isnan)]) # count NaNs (they devide measurements of different cars) 51 | time_steps = raw_time.index[raw_time.apply(np.isnan)][0] # index value first NaN is the number of time steps 52 | 53 | # drop the NaNs 54 | raw_position = raw_position.dropna() 55 | raw_time = raw_time.dropna() 56 | 57 | # reshape the array and take account that data have a NaN value is "missing" for case 1 58 | try: 59 | position = np.array(raw_position).reshape((n_cars,time_steps)) 60 | time = np.array(raw_time).reshape((n_cars,time_steps)) 61 | 62 | except: 63 | n_cars = n_cars+1 64 | position = np.array(raw_position).reshape((n_cars,time_steps)) 65 | time = np.array(raw_time).reshape((n_cars,time_steps)) 66 | 67 | 68 | #%% ============================================================================= 69 | # pre process data 70 | # ============================================================================= 71 | 72 | # arrays to store velocity, acceleration, headway and velocity difference 73 | velocity = np.zeros_like(position) 74 | acceleration = np.zeros_like(position) 75 | headway = np.zeros_like(position) 76 | D_velocity = np.zeros_like(position) 77 | 78 | # use central differences in space and time 79 | dx = (position[:,2:] - position[:,:-2]) 80 | dt = (time[:,2:] - time[:,:-2]) 81 | 82 | # use the modular function to account for the fact that position data was saved 83 | dx[dx<-200] = dx[dx<-200]%L 84 | 85 | # compute the variables 86 | velocity[:,1:-1] = dx/dt 87 | acceleration[:,2:-2] = (velocity[:,3:-1] - velocity[:,1:-3])/(time[:,3:-1] - time[:,1:-3]) 88 | headway[:,:] = (np.roll(position,-1,axis=0)-position[:,:])%L 89 | D_velocity[:,:] = (np.roll(velocity,-1,axis=0)-velocity[:,:])%L 90 | 91 | # drop values at the beginning and the end (they are 0 for acceleration) 92 | t = time[:,2:-2] 93 | x = position[:,2:-2] 94 | Dx = headway[:,2:-2] 95 | dotx = velocity[:,2:-2] 96 | D_dotx = D_velocity[:,2:-2] 97 | ddotx = acceleration[:,2:-2] 98 | 99 | # shift target (prediction of the acceleration of the next time step i+1) 100 | ddotx = np.roll(ddotx,-1,axis=1) 101 | 102 | t,x,Dx,dotx,D_dotx,ddotx = map(lambda x : moveAvg(x,mvavg),[t,x,Dx,dotx,D_dotx,ddotx]) 103 | 104 | #delete last array entry since it loses meaning due to shifting 105 | t= t[:,:-3] 106 | x = x[:,:-3] 107 | Dx = Dx[:,:-3] 108 | dotx = dotx[:,:-3] 109 | D_dotx = D_dotx[:,:-3] 110 | ddotx = ddotx[:,:-3] 111 | 112 | #save data 113 | np.savetxt(output_directory+"case"+str(case)+"/position.txt",x) 114 | np.savetxt(output_directory+"case"+str(case)+"/headway.txt",Dx) 115 | np.savetxt(output_directory+"case"+str(case)+"/velocity.txt",dotx) 116 | np.savetxt(output_directory+"case"+str(case)+"/acceleration.txt",ddotx) 117 | np.savetxt(output_directory+"case"+str(case)+"/velocity_difference.txt",D_dotx) 118 | np.savetxt(output_directory+"case"+str(case)+"/time.txt",t) 119 | 120 | #%% plot 121 | 122 | fig, ax = plt.subplots() 123 | 124 | 125 | car = 17 126 | start = 0 127 | end = len(Dx[0,:]) 128 | iters = end - start 129 | jump = 1 # just plot every 3rd iteration to save time 130 | 131 | fs =14 132 | c = np.linspace(0,np.max(time),end) 133 | 134 | #ax.set_title("velocity vs. headway, car=" + str(car)) 135 | ax_scatter = ax.scatter(Dx[car,:],dotx[car,:], marker="x",s=10,c=c) 136 | ax.set_xlabel(r'$\Delta x$', fontsize = fs) 137 | ax.set_ylabel(r'$\dot{x}$',fontsize = fs) 138 | #ax.set_ylim(0,10) 139 | ax.set_xlim(6,15) 140 | ax.tick_params(direction="in") 141 | cb=fig.colorbar(ax_scatter, ax=ax) 142 | cb.set_label(label="time [s]",size=fs) 143 | 144 | #%% ============================================================================= 145 | # headway velocities 146 | # ============================================================================= 147 | fig, ax = plt.subplots() 148 | 149 | for j in np.arange(0,n_cars): 150 | diffx = np.roll(x[j,:],-1)-x[j,:] 151 | masked_x = np.ma.array(x[j,:]) 152 | masked_x[diffx<-200] = np.ma.masked 153 | ax.plot(t[j,:],masked_x,lw=0.8,c="red") 154 | 155 | #ax.set_title("car positions", fontsize = fs) 156 | ax.set_ylabel("position [m]", fontsize = fs) 157 | ax.set_xlabel("time [s]", fontsize = fs) 158 | ax.set_ylim(0,230) 159 | ax.set_xlim(0,np.max(time)) 160 | ax.tick_params(direction="in") 161 | 162 | #%% ============================================================================= 163 | # velocities hovmöller 164 | # ============================================================================= 165 | fig, ax = plt.subplots() 166 | 167 | distance_arr=np.linspace(0,230,100) 168 | time_arr = np.linspace(0,np.max(time),100) 169 | 170 | grid_x, grid_t = np.meshgrid(distance_arr,time_arr) 171 | 172 | x_point = x.reshape(x.size,1) 173 | t_point = t.reshape(t.size,1) 174 | points = np.concatenate((x_point,t_point),axis=1) 175 | dot_x_values = dotx.reshape(dotx.size,1) 176 | 177 | grid_dot_x = griddata(points, dot_x_values[:,0], (grid_x, grid_t), method='linear') 178 | 179 | 180 | cmap = "inferno" 181 | contours = np.linspace(0,9,21) 182 | cf = ax.contourf(time_arr,distance_arr,grid_dot_x.T,contours,cmap=cmap, extend="max") 183 | ax.set_xlabel("time [s]", fontsize = fs) 184 | ax.set_ylabel("position [m]", fontsize = fs) 185 | ax.tick_params(direction="in") 186 | cb=fig.colorbar(cf, ax=ax) 187 | cb.set_label(label="velocity [m/s]", size=14) 188 | 189 | 190 | #%% ============================================================================= 191 | # standard deviation headway 192 | # ============================================================================= 193 | fig, ax = plt.subplots() 194 | #ax.set_title("std($\Delta$x) vs. t") 195 | ax.plot(t[0,:],Dx.std(axis=0)) 196 | ax.set_xlabel("time [s]",fontsize = fs) 197 | ax.set_ylabel("std($\Delta$x) [m]",fontsize = fs) 198 | ax.tick_params(direction="in") 199 | 200 | ax.set_xlim(0,250) 201 | ax.set_ylim(0,6) 202 | 203 | 204 | 205 | #%% ============================================================================= 206 | # standard deviation velocity differenc 207 | # ============================================================================= 208 | fig, ax = plt.subplots() 209 | #ax.set_title("std($\Delta$x) vs. t") 210 | ax.plot(t[0,:],dotx.std(axis=0)) 211 | ax.set_xlabel("time [s]",fontsize = fs) 212 | ax.set_ylabel("std($\dot{x}$) [m/s]",fontsize = fs) 213 | ax.tick_params(direction="in") 214 | 215 | ax.set_xlim(0,250) 216 | ax.set_ylim(0,4) 217 | --------------------------------------------------------------------------------