如何解决AnyLogic中水上出租车模拟的初始速度问题?
AnyLogic威尼斯水上出租车速度仿真问题解决方案
问题描述
在AnyLogic中还原威尼斯水上出租车真实路径,通过自定义代码设置不同阶段的速度与加速度,使用状态机仿真,禁止使用Road、Pedestrian、Railway等库工具。当前运行时存在两个核心问题:
- 代理属性中指定的初始速度会干扰自定义位移计算,导致路径偏差
- 无法将代理初始速度设为0或留空,需要让代理完全遵循自定义代码的速度逻辑运行

现有自定义速度控制代码
//ACCELERATION 0-7 if(v_sum<1.94) {index_tratta=0; a=main.Yellow.get(index_tratta).a; latitude=getLatitude(); longitude=getLongitude(); v_part=a*t_iter; v_sum=v_part+v_sum; s_part=0.5*a*t_iter*t_iter; s_sum=s_part+s_sum;} //COSTANT_7 else if(v_sum>=1.94) {index_tratta=1; v_sum=1.94; a=main.Yellow.get(index_tratta).a; latitude=getLatitude(); longitude=getLongitude(); s_part=v_sum*t_iter; s_sum=s_part+s_sum;} //ACCELERATION 7-11 else if(latitude==45.445 && longitude==12.337) {index_tratta=2; a=main.Yellow.get(index_tratta).a; latitude=getLatitude(); longitude=getLongitude(); v_part=a*t_iter; v_sum=v_part+v_sum; s_part=0.5*a*t_iter*t_iter; s_sum=s_part+s_sum;} //COSTANT 11 else if(v_sum>=3.056) {index_tratta=3; v_sum=3.056; a=main.Yellow.get(index_tratta).a; latitude=getLatitude(); longitude=getLongitude(); s_part=v_sum*t_iter; s_sum=s_part+s_sum;} //ACCELERATION 11-20 else if(latitude==45.460 && longitude==12.343) {index_tratta=4; a=main.Yellow.get(index_tratta).a; latitude=getLatitude(); longitude=getLongitude(); v_part=a*t_iter; v_sum=v_part+v_sum; s_part=0.5*a*t_iter*t_iter; s_sum=s_sum+s_part;} //COSTANT 20 else if(v_sum>=5.56) {index_tratta=5; v_sum=5.56; a=main.Yellow.get(index_tratta).a; latitude=getLatitude(); longitude=getLongitude(); s_part=v_sum*t_iter; s_sum=s_sum+s_part;} //DECCELERATION 20-0 else if(latitude==45.490 && longitude==12.328) {index_tratta=6; a=main.Yellow.get(index_tratta).a; latitude=getLatitude(); longitude=getLongitude(); v_part=a*t_iter; v_sum=v_part+v_sum; s_part=0.5*a*t_iter*t_iter; s_sum=s_sum+s_part;} //ARRIVE else if(latitude==45.50083 && longitude==12.33685) {isRunning=false;} }
解决方案
1. 完全禁用代理内置运动逻辑
进入代理的属性设置面板,找到运动选项组,将运动模式设置为无(取消所有与内置运动相关的勾选)。这样代理不会自动使用初始速度计算位置,完全交由自定义代码控制。
2. 手动更新代理位置
不要依赖代理的speed属性,而是将计算得到的位移s_part(当前时间步的位移,而非累计s_sum)转换为经纬度偏移量,通过setLatitude()和setLongitude()直接更新代理位置。可以使用AnyLogic内置的地理计算函数辅助转换:
// 假设已确定当前运动方向的角度angle double newLat = moveLatitude(getLatitude(), angle, s_part); double newLon = moveLongitude(getLongitude(), getLatitude(), angle, s_part); setLatitude(newLat); setLongitude(newLon);
3. 初始化自定义速度变量
在代理的onStartup()方法或状态机的初始状态动作中,添加v_sum = 0;,确保自定义速度从0开始,不受代理初始速度属性影响。
4. 修正条件判断逻辑
当前代码的条件顺序会导致位置触发的阶段被速度条件覆盖,调整判断顺序,将位置触发的条件放在速度条件之前,确保到达指定点位后才切换到对应加速/减速阶段,同时用距离判断替代直接经纬度相等判断:
// 先判断位置触发的阶段 if(distance(getLatitude(), getLongitude(), 45.445, 12.337) < 0.0001) { // ACCELERATION 7-11逻辑 } else if(distance(getLatitude(), getLongitude(), 45.460, 12.343) < 0.0001) { // ACCELERATION 11-20逻辑 } else if(v_sum < 1.94) { // ACCELERATION 0-7逻辑 } else if(v_sum >=1.94 && v_sum <3.056) { // COSTANT_7逻辑 } // 后续条件依次调整
5. 规避浮点精度问题
直接判断经纬度是否等于固定值会因浮点计算误差失效,改用距离阈值判断,比如distance(getLatitude(), getLongitude(), 目标纬度, 目标经度) < 0.0001,阈值可根据仿真精度需求调整。
内容的提问来源于stack exchange,提问作者Riccardo Appennini
相关产品推荐
相关产品推荐

