VISSIM二次开发(Python)&大作业总结1
写在前面
本次作业也是我研一的时候看到师兄们以前选过这个课,就跟风也来选了,这节课的最后要交一个大作业,需要用到交通仿真软件,而且仿真需求很大。手动输入的话,相信看到这里的朋友都和我一样觉得很难受。所以肯定会有更方便的办法~那就是二次开发。
由于本人此前没有接触过VISSIM,所以也是花了很多的心思和力气在学习VISSIM的使用以及二次开发的一些方法。本文中也记录一下在这次二次开发中遇到的一些坑和一些技巧,和大家一起共同学习~
后面还会有一个和大作业有关的总结,因为内容和这个差异比较大就分开了。
参考
由于我本人不是做交通方向的,所以事先也阅读了很多网上写的很好的例子
VISSIM&COM——Python开发教程 - 知乎 (zhihu.com)
上文似乎也是和我同一节课的师兄,他展示的代码和过程和我之后的基本一样,不过我由于暑假基本在学校能用VISSIM7.0,当然我自己也尝试了VISSIM4.3,这两者的坑都有不少,但是由于版本不同,他们对于二次开发的接口的方式都不尽相同。不过,方法都是有共通性的~
所以上文给我了非常多的借鉴意义,这里也推荐大家去看这位大神的教程,下面是他的一个简单且完整的接入案例,我将围绕这这个案例展开我们的介绍,本文会涉及一点点VISSIM界面的东西,但不会太多。
import win32com.client as com
vissim_com = com.Dispatch("Vissim.Vissim")
Sim = vissim_com.Simulation
vissim_com.LoadNet('C:\\Users\\lenovo\\Desktop\\[HW]Traffic Flow\\VISSIM SIHUO - 1\\homework.inp')
vissim_com.LoadLayout('C:\\Users\\lenovo\\Desktop\\[HW]Traffic Flow\\VISSIM SIHUO - 1\\homework.ini')
vnet = vissim_com.net
Sim = vissim_com.simulation
eval = vissim_com.Evaluation
eval.SetAttValue('DATACOLLECTION', True) # 打开离线评价按钮
dceval = eval.DataCollectionEvaluation
dceval.SetAttValue('FILE', True)
dceval.SetAttValue('COMPILED', True)
# Sim.SetAttValue('PERIOD',100)
Sim.RandomSeed = 40
Sim.RunIndex = 0
Sim.RunContinuous()
Sim.stop()
可能很多人已经有体会了,VISSIM二次开发的代码主体就是设置一下仿真软件的一些基本参数,比如文件读写,选择仿真运行的时间种子,控制仿真的起止等等。由于软件的问题,在仿真中如果需要更改一些更加细节的设置,比如更改流量,驾驶行为参数等等,往往没那么快捷方便,下面就介绍本文的方法~
二次开发技巧
我其实更愿意说是粗暴的二次开发,vissim的文件一般都是以.inpx文件的形式存储,不同版本可能不太一致(比如4.3文件就是.inp),但都能找到类似的。
当我们用记事本打开会发现这样的形式
也即,我们在VISSIM构建的路网和交通相关的参数,全部存储在这个文件当中,那么是不是更改这个文件,会直接的引起文件的更改呢~ 答案是会,并且这个更改的速度很快~
先来点小菜,更改相对固定参数
如更改流量,时间段和分流比例这种量比较大,但是在一个仿真中相对比较固定的参数。找到inpx文件中以下有关的定义。
定义 | 字节 |
---|---|
时间段定义 | <timeInterval start="0.000000"/> |
输入流量定义 | <timeIntervalVehVolume cont=“false” timeInt=“1 0” vehComp=“2” volType=“EXACT” volume=“684.000000”/> |
分流区比例分配定义 | <timeIntervalVehVolume cont=“false” timeInt=“1 0” vehComp=“2” volType=“EXACT” volume=“684.000000”/> |
接下来按照他们原本的样式填充回去即可,这里建议注意备份好文件,以免自己的误操作,导致文件损坏而无法检查的尴尬局面
#开发环境
matplotlib 3.3.4
numpy 1.19.5
pandas 1.2.4
备注:部分代码前面的缩进不好把握,1,复制出来的时候直接带好格式,这样输入回去的时候格式基本不会错 2,无视,直接不缩进,VISSIM可以无视这个问题
#df的读取操作——需要先读取自己需要输入的数据
#%%分流匝道1分流比例参数更改
ratio=[]
for i in range(T):
ratio.append(int(df1.iloc[start+i,2]/df2.iloc[start+i,2]))#这里的int很重要,决定后面的小数点舒服报错
print('2 '+str(i*300000)+':'+str(ratio[i])+'.000000,',end='')#这里控制输出的时候在同一行,后续的都是分行输出
#%%时间段输入
for i in range(T):
print(' <timeInterval start="'+str(i*300)+'.000000"/>')
#%%主线流量输入
for i in range(T):
print(' <timeIntervalVehVolume cont="false" timeInt="1 '+str(str(i*300000))+'" vehComp="1" volType="EXACT" volume="'+str(12*df6.iloc[start+i-1,2])+'"/>')
#%%匝道流量输入
for i in range(T):
print(' <timeIntervalVehVolume cont="false" timeInt="1 '+str(str(i*300000))+'" vehComp="1" volType="EXACT" volume="'+str(12*df5.iloc[start+i-1,2])+'"/>')
我们的原则就是尽量简化调用的接口,提高速度
调用接口需要如何更改参数
这部分在前面的参考链接中也有更细致的介绍,这里简单贴一下方法,显然没有那么方便,但是对于需要动态调整的可能的确会方便一点,由于本次大作业不涉及,所以这里也不过多的涉及。
import win32com.client as com
vissim_com = com.Dispatch("Vissim.Vissim.700")#必要的引入
#%%
vissim_com.LoadNet('C:\\Users\\Administrator\\Desktop\\test\\test.inpx')#读取这两个文件
vissim_com.LoadLayout('C:\\Users\\Administrator\\Desktop\\test\\test.layx')
VI_number = 1 #车辆输入点
flowIN=[400,3000]#这里变成需要输入的流量,第一个时刻是400,第二个是3000。
for i in range(len(flowIN)):
vissim_com.Net.VehicleInputs.ItemByKey(1).SetAttValue('Volume('+str(i+1)+')', flowIN[i])
vissim_com.Net.VehicleInputs.ItemByKey(VI_number).SetAttValue('Cont('+str(i+2)+')', False)
Sim = vissim_com.simulation
Sim.RunContinuous()#启动仿真
Sim.stop()
更改.inpx快捷二次开发(完整代码)
需要更改.inpx就涉及到文件的查读写了,这里不是我们的重点,这里放一个比较成熟的修改文件内容方法大家可以参考。我们选用第一种方法。
python 修改文件内容3种方法 - wc_chan - 博客园 (cnblogs.com)
import win32com.client as com
vissim_com = com.Dispatch("Vissim.Vissim.700")#必要的引入
def alter(file,old_str,new_str):
file_data = ""
with open(file, "r", encoding="utf-8") as f:
for line in f:
if old_str in line:
line = line.replace(old_str,new_str)
file_data += line
with open(file,"w",encoding="utf-8") as f:
f.write(file_data)
def SIMRUN():
vissim_com.LoadNet('C:\\Users\\Administrator\\Desktop\\代码测试\\调试.inpx')#读取这两个文件
vissim_com.LoadLayout('C:\\Users\\Administrator\\Desktop\\代码测试\\调试.layx')
Sim = vissim_com.simulation
vissim_com.Graphics.SetAttValue('Quickmode',True)
Sim.SetAttValue('RandSeed',5)
Sim.SetAttValue('UseMaxSimSpeed',True)
Sim.RunContinuous()#启动仿真
Sim.stop()
print('第'+str(i+1)+'次仿真彻底结束')
#%%建议这里隔开,因为前面的调用VISSIM需要打开软件,效率不高
import pandas as pd
df=pd.read_csv('C:/Users/Administrator/Desktop/代码测试/8因子6水平处理后数据.csv',engine='python',sep=';',header=None)
a=df.shape[0]
b=df.shape[1]
Line0=['w99cc0="1.500000"','w99cc1="0.900000"','w99cc2="4.000000"','w99cc4="-0.350000"','w99cc5="0.350000"','accDecelTrail="-2.000000"','safDistFactLnChg="0.600000"','coopDecel="-6.000000"','coopLnChgSpeedDiff="10.800000"']
Line1=['w99cc0="','w99cc1="','w99cc2="','w99cc4="','w99cc5="','accDecelTrail="','safDistFactLnChg="','coopDecel="','coopLnChgSpeedDiff="']
for i in range(a):
if (i==0):
for j in range(b):
alter("C:\\Users\\Administrator\\Desktop\\代码测试\\调试.inpx", Line0[j], Line1[j]+'%.6f'%df.iloc[0,j]+'"')
SIMRUN()
if(i>0):
for j in range(b):
alter("C:\\Users\\Administrator\\Desktop\\代码测试\\调试.inpx", Line1[j]+'%.6f'%df.iloc[i-1,j]+'"', Line1[j]+'%.6f'%df.iloc[i,j]+'"')
SIMRUN()
可以注意到需要如果更改的参数如下,那么就找到原始的文件中的这些参数(完整字节),然后将需要更改的参数以文件读写的方式直接写入.inpx。至于这个更改成什么参数,大家可以去看看正交实验的东西或者其他的启发式算法之类的东西,具体这里不展开。
Line0=['w99cc0="1.500000"','w99cc1="0.900000"','w99cc2="4.000000"','w99cc4="-0.350000"','w99cc5="0.350000"','accDecelTrail="-2.000000"','safDistFactLnChg="0.600000"','coopDecel="-6.000000"','coopLnChgSpeedDiff="10.800000"']
结果输出
由于我们设置的采集器,最关注的是速度和流量所以只设置了比较常规的线圈检测器,在线圈数据显示界面勾选按钮可以使用.att格式的文件可以自动进行存储输出,本次大作业也涉及了很多相关的数据分析以及绘图的代码,将在第二部分进行介绍。
授人以渔部分
在二次开发过程中,遇到了不知道怎么样调用某一属性的方式,有这些方法可以解决,看个人喜好,没有先后关系。当然按照本文的去找到inpx文件中的对应字节然后直接更改文件也十分方便,但是一定要做好文件的备份,并且改动完之后及时运行inpx文件查看是否更改成功~
网上查看是否有可以参考的二次开发的技术文档
多数时候我们都希望能找到和我们需求相一致的代码参考,比如我本人。
vissim_com.Graphics.SetAttValue('Quickmode',True)
Sim.SetAttValue('RandSeed',5)
Sim.SetAttValue('UseMaxSimSpeed',True)
Sim.RunContinuous()#启动仿真
Sim.stop()
com自身提供的参考文档和参考代码
在安装了VISSIM软件的电脑上,在他的文件夹中都会有COM_example.py
这类型的文件,里面会有很多可以直接使用以及直观的代码。
在软件界面上的帮助下,可以找到这样的一个文件:
比如我们想设置Quickmode这个参数,发现他是在Graphics这个对象里面的,所以vissim_com.Graphics.SetAttValue('Quickmode',True)
我们用这种方法对其进行调用并设置为快速模式,这样软件界面的车辆运行就不会显示出来,从而就能更加快捷的运行了~
同样其它的属性需要修改的也可以按照这样的方法进行索引更改,例如前面例子中的'RandSeed'
就都在simulation
对象中。
本系列第二篇:VISSIM二次开发(Python)&大作业总结2~