仿真ats重构-MA移动授权逻辑重构,ATS进路触发逻辑调整,进路正常开始解锁逻辑判断流程调整(现根据进路第一区段占用情况触发)
This commit is contained in:
parent
670ed1163a
commit
653a29eb65
@ -281,13 +281,13 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
|
||||
public void pause() {
|
||||
this.updateState(PAUSE);
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(BASE_RATE);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
if (this.mainLogicRunning.get() == false) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(5);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
log.debug(String.format("仿真[%s]暂停", this.id));
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import club.joylink.rtss.simulation.cbtc.CI.CiApiService;
|
||||
import club.joylink.rtss.simulation.cbtc.Simulation;
|
||||
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
|
||||
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Route;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Section;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Signal;
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
|
||||
@ -28,40 +27,6 @@ public class AtpSectionService {
|
||||
@Autowired
|
||||
private CiApiService ciApiService;
|
||||
|
||||
/**
|
||||
* 收集信号机跨压信息发送给CI
|
||||
*/
|
||||
public void collectAndSendSignalAcrossMessage2CI(Simulation simulation, List<VirtualRealityTrain> onlineTrainList,
|
||||
Map<String, List<Section>> trainAtpSectionMap) {
|
||||
Set<String> signalAcrossSet = new HashSet<>(); // 跨压信号机
|
||||
List<Signal> signalList = simulation.getRepository().getSignalList();
|
||||
signalList.forEach(signal -> {
|
||||
// if (!signal.isNormalOpen()) {
|
||||
// return;
|
||||
// }
|
||||
Route lockedRoute = signal.getLockedRoute();
|
||||
if (Objects.isNull(lockedRoute)) {
|
||||
return;
|
||||
}
|
||||
Section section = signal.getSection();
|
||||
Section nextSection = section.getNextRunningSectionOf(signal.isRight());
|
||||
boolean across = false;
|
||||
for (VirtualRealityTrain train : onlineTrainList) {
|
||||
List<Section> atpSectionList = trainAtpSectionMap.get(train.getGroupNumber());
|
||||
List<Section> physicalList = this.convert2PhysicalSectionList(atpSectionList);
|
||||
if (physicalList.contains(section) && physicalList.contains(nextSection)) {
|
||||
across = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
String signalCode = signal.getCode();
|
||||
if (across) {
|
||||
signalAcrossSet.add(signalCode);
|
||||
}
|
||||
});
|
||||
this.ciApiService.handleSignalAcrossMessage(simulation, signalAcrossSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集列车接近信号机消息并发送给CI
|
||||
*/
|
||||
|
@ -56,8 +56,7 @@ public class GroundAtpApiServiceImpl implements GroundAtpApiService {
|
||||
// 更新保存新的占用
|
||||
repository.addOrUpdateTrainOccupyAtpSectionList(train.getGroupNumber(), trainAtpSectionList);
|
||||
}
|
||||
// 信号机接近信息、停稳信息、跨压信息通知
|
||||
this.atpSectionService.collectAndSendSignalAcrossMessage2CI(simulation, onlineTrainList, trainAtpSectionMap);
|
||||
// 信号机接近信息、停稳信息通知
|
||||
Map<VirtualRealityTrain, Signal> nctApproachSignalMap =
|
||||
this.atpSectionService.collectAndSendSignalApproachMessage2CI(simulation, onlineTrainList, trainAtpSectionMap);
|
||||
|
||||
|
@ -0,0 +1,428 @@
|
||||
package club.joylink.rtss.simulation.cbtc.ATP.ground;
|
||||
|
||||
import club.joylink.rtss.simulation.cbtc.Simulation;
|
||||
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
|
||||
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.*;
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
|
||||
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
|
||||
import club.joylink.rtss.simulation.cbtc.onboard.ATO.SpeedCurve;
|
||||
import club.joylink.rtss.simulation.cbtc.onboard.ATP.OnboardAtpApiService;
|
||||
import lombok.Getter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 移动授权计算服务
|
||||
*/
|
||||
@Component
|
||||
public class MaService {
|
||||
|
||||
@Autowired
|
||||
private OnboardAtpApiService onboardAtpApiService;
|
||||
|
||||
@Getter
|
||||
public static class Ma {
|
||||
public static final int Safety_Margin = 10; // 安全余量,单位m
|
||||
public static final int EB_Trigger = 20; // 紧急制动触发点偏移量,单位m
|
||||
public static final int Safety_Distance = 30; // 安全距离, 单位m
|
||||
|
||||
VirtualRealityTrain train; // 列车
|
||||
MapNamedElement device; // 终端设备
|
||||
MaType type; // 类型
|
||||
SectionPosition eoaPosition; // 授权终端位置
|
||||
|
||||
float distanceToEoa; // 距离
|
||||
/**
|
||||
* 紧急制动触发曲线
|
||||
*/
|
||||
private SpeedCurve ebTriggerCurve;
|
||||
/**
|
||||
* ATO停车曲线
|
||||
*/
|
||||
private SpeedCurve atoStopCurve;
|
||||
/**
|
||||
* 移动的累计距离
|
||||
*/
|
||||
private float moveLen;
|
||||
|
||||
public Ma(VirtualRealityTrain train, MapNamedElement device, MaType type) {
|
||||
this.train = train;
|
||||
this.device = device;
|
||||
this.type = type;
|
||||
this.getEoaPosition();
|
||||
this.calculateDistanceToEoa();
|
||||
}
|
||||
|
||||
public void addMoveLen(float len) {
|
||||
this.moveLen += len;
|
||||
}
|
||||
|
||||
public void setEbTriggerCurve(SpeedCurve ebTriggerCurve) {
|
||||
this.ebTriggerCurve = ebTriggerCurve;
|
||||
}
|
||||
|
||||
public void setAtoStopCurve(SpeedCurve atoStopCurve) {
|
||||
this.atoStopCurve = atoStopCurve;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Ma ma = (Ma) o;
|
||||
return Objects.equals(eoaPosition, ma.eoaPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(eoaPosition);
|
||||
}
|
||||
|
||||
public String debugStr() {
|
||||
return String.format("列车[%s]位置:%s, 移动授权为:{类型: %s, 设备: %s, EOA: %s, distance: %s}",
|
||||
this.train.getGroupNumber(),
|
||||
this.train.getHeadPosition().toString(),
|
||||
this.type,
|
||||
this.device.debugStr(),
|
||||
this.eoaPosition.toString(),
|
||||
this.distanceToEoa);
|
||||
}
|
||||
|
||||
public float calculateDistanceToEoa() {
|
||||
SectionPosition headPosition = train.getHeadPosition();
|
||||
boolean right = train.isRight();
|
||||
Float distance = CalculateService.calculateDistance(headPosition, this.eoaPosition, right);
|
||||
if (distance == null) {
|
||||
distance = CalculateService.calculateDistance(headPosition, this.eoaPosition, !right);
|
||||
if (distance > 0) {
|
||||
distance = -distance;
|
||||
}
|
||||
}
|
||||
this.distanceToEoa = distance;
|
||||
return distanceToEoa;
|
||||
}
|
||||
|
||||
public float calculateDistanceOfEbTriggerEnd() {
|
||||
if (this.type.equals(MaType.Limit_Signal_Without_Overlap)) {
|
||||
Signal signal = (Signal) this.device;
|
||||
if (signal.getSection().isJustTurnBackTrack()) {
|
||||
return this.calculateDistanceToEoa();
|
||||
}
|
||||
}
|
||||
return this.calculateDistanceToEoa() - EB_Trigger;
|
||||
}
|
||||
|
||||
public float calculateDistanceOfAtoEnd() {
|
||||
if (this.type.equals(MaType.Limit_Signal_With_Overlap) ||
|
||||
this.type.equals(MaType.Limit_Signal_Without_Overlap)) {
|
||||
Signal signal = (Signal) this.device;
|
||||
SectionPosition sectionPosition = new SectionPosition(signal.getSection(), signal.getOffset());
|
||||
boolean right = this.train.isRight();
|
||||
SectionPosition end = CalculateService.calculateNextPositionByStartAndLen(sectionPosition, !right, 2);
|
||||
return CalculateService.calculateDistance(this.train.getHeadPosition(), end, right);
|
||||
} else {
|
||||
return this.calculateDistanceOfEbTriggerEnd() - Safety_Distance;
|
||||
}
|
||||
}
|
||||
|
||||
public SectionPosition getEoaPosition() {
|
||||
SectionPosition eoa;
|
||||
boolean right = this.train.isRight();
|
||||
switch (this.type) {
|
||||
case Front_Train: {
|
||||
VirtualRealityTrain frontTrain = (VirtualRealityTrain) this.device;
|
||||
if (frontTrain.isRight() == right) {
|
||||
eoa = frontTrain.getTailPosition();
|
||||
} else {
|
||||
eoa = frontTrain.getHeadPosition();
|
||||
}
|
||||
eoa = CalculateService.calculateNextPositionByStartAndLen(eoa, !right, 10 + frontTrain.getSpeed() * 2);
|
||||
break;
|
||||
}
|
||||
case Axle_Occupy_Section:{
|
||||
Section aoSection = (Section) this.device;
|
||||
eoa = this.buildEoaOfAxleOccupySection(aoSection, right);
|
||||
break;
|
||||
}
|
||||
case Limit_Signal_Without_Overlap:{
|
||||
Signal signal = (Signal) this.device;
|
||||
Section section = signal.getSection();
|
||||
eoa = new SectionPosition(section, right ? section.getLen() : 0);
|
||||
break;
|
||||
}
|
||||
case Limit_Signal_With_Overlap:{
|
||||
Signal signal = (Signal) this.device;
|
||||
eoa = this.buildEoaOfLimitSignalWithOverlap(signal, right);
|
||||
break;
|
||||
}
|
||||
case ZC_Boundary:{
|
||||
Section section = (Section) this.device;
|
||||
eoa = new SectionPosition(section, right ? section.getLen() : 0);
|
||||
break;
|
||||
}
|
||||
case Closed_Section:
|
||||
case Fault_Route:{
|
||||
Section section = (Section) this.device;
|
||||
eoa = new SectionPosition(section, right ? 0 : section.getLen());
|
||||
break;
|
||||
}
|
||||
case Stand:{
|
||||
Section section = (Section) this.device;
|
||||
float offset = section.getStopPointByDirection(right);
|
||||
offset = right ? offset - train.getLen() - 20 : offset + train.getLen() + 20;
|
||||
eoa = CalculateService.getAvailableSectionPositionOf(new SectionPosition(section, offset));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalStateException("未知的移动授权类型: " + this.type);
|
||||
}
|
||||
this.eoaPosition = eoa;
|
||||
return eoa;
|
||||
}
|
||||
|
||||
private SectionPosition buildEoaOfAxleOccupySection(Section aoSection, boolean right) {
|
||||
SectionPosition headPosition = this.train.getHeadPosition();
|
||||
if (aoSection.equals(headPosition.getSection())) { // 车头区段
|
||||
return new SectionPosition(aoSection, right ? 0 : aoSection.getLen());
|
||||
}
|
||||
// 非车头区段,取非通信车占用区段与列车运行方向反向区段
|
||||
// 如果此区段是道岔区段且不是车头区段,则从列车车头区段往前找,直到第一个和此道岔区段为同一道岔计轴的道岔区段
|
||||
Section front = aoSection.getSectionOf(!right);
|
||||
if (front.isSwitchTrack() && !front.equals(headPosition.getSection())) {
|
||||
Section section = headPosition.getSection();
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Section fs = section.getNextRunningSectionOf(right);
|
||||
if (fs.isSameAxle(front.getCode())) {
|
||||
front = fs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new SectionPosition(front, right ? 0 : front.getLen());
|
||||
}
|
||||
|
||||
private SectionPosition buildEoaOfLimitSignalWithOverlap(Signal signal, boolean right) {
|
||||
List<RouteOverlap> overlapList = signal.getOverlapList();
|
||||
Section section = this.queryOverlapLockedEndSection(overlapList);
|
||||
if (section == null) {
|
||||
section = signal.getSection();
|
||||
}
|
||||
return new SectionPosition(section, right ? section.getLen() : 0);
|
||||
}
|
||||
|
||||
private Section queryOverlapLockedEndSection(List<RouteOverlap> overlapList) {
|
||||
for (RouteOverlap routeOverlap : overlapList) {
|
||||
if (routeOverlap.isLock()) {
|
||||
List<SectionPath> pathList = routeOverlap.getPathList();
|
||||
for (SectionPath sectionPath : pathList) {
|
||||
List<Section> sectionList = sectionPath.getSectionList();
|
||||
if (sectionList.get(sectionList.size() - 1).isOverlapLock()) {
|
||||
return sectionList.get(sectionList.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动授权类型
|
||||
*/
|
||||
public enum MaType {
|
||||
/** 前方列车 */
|
||||
Front_Train,
|
||||
/** 计轴占用区段 */
|
||||
Axle_Occupy_Section,
|
||||
/** 没有延续保护的限制信号机 */
|
||||
Limit_Signal_Without_Overlap,
|
||||
/** 有延续保护的限制信号机 */
|
||||
Limit_Signal_With_Overlap,
|
||||
/** ZC边界 */
|
||||
ZC_Boundary,
|
||||
/** 关闭的区段 */
|
||||
Closed_Section,
|
||||
/** 进路联锁条件不再完备 */
|
||||
Fault_Route,
|
||||
/** 站台问题(屏蔽门或紧急停车) */
|
||||
Stand,
|
||||
}
|
||||
|
||||
public void calculateMaOfCtcTrains(Simulation simulation) {
|
||||
SimulationDataRepository repository = simulation.getRepository();
|
||||
Map<String, VirtualRealityTrain> usedTrainMap = repository.getUsedTrainMap();
|
||||
usedTrainMap.values().forEach(vrTrain -> vrTrain.calculateTailPosition());
|
||||
for (VirtualRealityTrain vrTrain : usedTrainMap.values()) {
|
||||
if (vrTrain.isRMMode() || vrTrain.isNRMMode()) {
|
||||
continue;
|
||||
}
|
||||
if (vrTrain.isCommunication()) {
|
||||
Ma ma = this.calculateCtcMa(simulation, vrTrain, usedTrainMap);
|
||||
if (ma.distanceToEoa <= 0) {
|
||||
System.out.println(ma.debugStr());
|
||||
}
|
||||
this.onboardAtpApiService.updateCtcMa(simulation, ma);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Ma calculateCtcMa(Simulation simulation, VirtualRealityTrain train, Map<String, VirtualRealityTrain> trainMap) {
|
||||
SectionPosition headPosition = train.getHeadPosition();
|
||||
SectionPosition tailPosition = train.getTailPosition();
|
||||
boolean right = train.isRight();
|
||||
Ma ma = null;
|
||||
boolean front = false;
|
||||
Section section = tailPosition.getSection();
|
||||
for (int i = 0; i < 20 && section != null; i++) {
|
||||
if (section.equals(headPosition.getSection())) {
|
||||
front = true;
|
||||
}
|
||||
Route route = section.getRoute();
|
||||
if (route != null) {
|
||||
if (this.isSwitchFaultRoute(route, section)) {
|
||||
// 道岔故障进路,直接构建返回
|
||||
ma = new Ma(train, section, MaType.Fault_Route);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (section.isClosed()) {
|
||||
// 关闭的区段
|
||||
ma = this.checkAndUpdateMa(ma, new Ma(train, section, MaType.Closed_Section));
|
||||
}
|
||||
if (this.isFaultStand(section)) {
|
||||
// 故障/紧急停车站台
|
||||
ma = this.checkAndUpdateMa(ma, new Ma(train, section, MaType.Stand));
|
||||
}
|
||||
Section next = section.getNextRunningSectionOf(right);
|
||||
if (front) { // 车头前方
|
||||
Signal signal = section.getSignalOf(right);
|
||||
if (signal != null && !signal.isNormalOpen()) {
|
||||
// 限制信号机
|
||||
if (signal.isOverlapLock()) {
|
||||
ma = this.checkAndUpdateMa(ma, new Ma(train, signal, MaType.Limit_Signal_With_Overlap));
|
||||
} else {
|
||||
ma = this.checkAndUpdateMa(ma, new Ma(train, signal, MaType.Limit_Signal_Without_Overlap));
|
||||
}
|
||||
}
|
||||
if (section.hasNctOccupy()) {
|
||||
// 计轴占用区段
|
||||
ma = this.checkAndUpdateMa(ma, new Ma(train, section, MaType.Axle_Occupy_Section));
|
||||
} else if (section.isOnlyCtcOccupy()) {
|
||||
// 前方列车
|
||||
Ma ma2 = this.queryFrontTrain(train, section, trainMap);
|
||||
ma = this.checkAndUpdateMa(ma, ma2);
|
||||
}
|
||||
// ZC(尽头区段)边界
|
||||
if (!section.anyZcWorking() &&
|
||||
(headPosition.getSection().equals(section) ||
|
||||
!headPosition.isAheadOf(new SectionPosition(section, right ? section.getLen() : 0), right))) {
|
||||
ma = this.checkAndUpdateMa(ma, new Ma(train, section, MaType.ZC_Boundary));
|
||||
}
|
||||
if (next == null || (!next.anyZcWorking())) {
|
||||
ma = this.checkAndUpdateMa(ma, new Ma(train, section, MaType.ZC_Boundary));
|
||||
}
|
||||
}
|
||||
section = next;
|
||||
if (ma != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ma;
|
||||
}
|
||||
|
||||
private boolean isFaultStand(Section section) {
|
||||
if (section.isNormalStandTrack()) {
|
||||
for (Stand stand : section.getStandList()) {
|
||||
if (stand.isEmergencyClosed()) {
|
||||
return true;
|
||||
}
|
||||
PSD psd = stand.getPsd();
|
||||
if (psd != null && (!psd.isCloseAndLock() && !psd.isInterlockRelease()) && !stand.isTrainParking()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isSwitchFaultRoute(Route route, Section section) {
|
||||
boolean switchFault = false;
|
||||
List<Section> sectionList = route.getSectionList();
|
||||
Set<String> handledSwitchSet = new HashSet<>();
|
||||
boolean flag = false;
|
||||
for (Section routeSection : sectionList) {
|
||||
if (routeSection.equals(section)) {
|
||||
flag = true;
|
||||
}
|
||||
if (flag) {
|
||||
if (routeSection.isSwitchTrack()) {
|
||||
if (handledSwitchSet.contains(routeSection.getRelSwitch().getCode())) {
|
||||
continue;
|
||||
}
|
||||
SwitchElement switchElement = route.getRouteSwitchElement(routeSection.getRelSwitch());
|
||||
Switch aSwitch = switchElement.getASwitch();
|
||||
handledSwitchSet.add(aSwitch.getCode());
|
||||
if (route.equals(aSwitch.getRoute())) {
|
||||
if (aSwitch.isLoss()) {
|
||||
switchFault = true;
|
||||
break;
|
||||
} else {
|
||||
RouteFls fls = route.getRouteFlsOfSwitch(aSwitch);
|
||||
if (fls != null) {
|
||||
List<RouteFls.FlsElement> level1List = fls.getLevel1List();
|
||||
for (RouteFls.FlsElement flsElement : level1List) {
|
||||
SwitchElement pSwitch = flsElement.getPSwitch();
|
||||
if (pSwitch != null && pSwitch.getASwitch().isLoss()) {
|
||||
switchFault = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (switchFault) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return switchFault;
|
||||
}
|
||||
|
||||
private Ma checkAndUpdateMa(Ma ma, Ma ma2) {
|
||||
if (ma == null) {
|
||||
return ma2;
|
||||
} else if(ma2 != null) {
|
||||
if (ma.distanceToEoa > ma2.distanceToEoa) {
|
||||
return ma2;
|
||||
}
|
||||
}
|
||||
return ma;
|
||||
}
|
||||
|
||||
private Ma queryFrontTrain(VirtualRealityTrain train, Section section,
|
||||
Map<String, VirtualRealityTrain> trainMap) {
|
||||
List<VirtualRealityTrain> trainList = trainMap.values().stream()
|
||||
.filter(vrTrain -> !vrTrain.equals(train) &&
|
||||
(vrTrain.getHeadPosition().getSection().equals(section) ||
|
||||
vrTrain.getTailPosition().getSection().equals(section)))
|
||||
.collect(Collectors.toList());
|
||||
Ma ma = null;
|
||||
if (trainList.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
for (VirtualRealityTrain vrTrain : trainList) {
|
||||
Ma ma1 = new Ma(train, vrTrain, MaType.Front_Train);
|
||||
if (ma1.getDistanceToEoa() > 0) {
|
||||
ma = this.checkAndUpdateMa(ma, ma1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ma;
|
||||
}
|
||||
|
||||
}
|
@ -5,8 +5,6 @@ import club.joylink.rtss.simulation.cbtc.ATS.AtsApiService;
|
||||
import club.joylink.rtss.simulation.cbtc.CI.service.RouteService;
|
||||
import club.joylink.rtss.simulation.cbtc.Simulation;
|
||||
import club.joylink.rtss.simulation.cbtc.constant.RunLevel;
|
||||
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
|
||||
import club.joylink.rtss.simulation.cbtc.constant.SimulationModule;
|
||||
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
|
||||
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.*;
|
||||
@ -39,6 +37,9 @@ public class ZCLogicLoop {
|
||||
@Autowired
|
||||
private AtsApiService atsApiService;
|
||||
|
||||
@Autowired
|
||||
private MaService maService;
|
||||
|
||||
@Autowired
|
||||
private RouteService routeService;
|
||||
|
||||
@ -680,6 +681,7 @@ public class ZCLogicLoop {
|
||||
}
|
||||
|
||||
public void addJobs(Simulation simulation) {
|
||||
simulation.addJob(SimulationModule.ZC.name(), () -> this.run(simulation), SimulationConstants.ZC_LOOP_RATE);
|
||||
// simulation.addJob(SimulationModule.ZC.name(), () -> this.run(simulation), SimulationConstants.ZC_LOOP_RATE);
|
||||
simulation.addJob("MaCal", () -> this.maService.calculateMaOfCtcTrains(simulation), 1000);
|
||||
}
|
||||
}
|
||||
|
@ -349,7 +349,7 @@ public class ATSMessageCollectAndDispatcher {
|
||||
}
|
||||
|
||||
public void addJobs(Simulation simulation) {
|
||||
simulation.addFixedRateJob(SimulationModule.SYNC_TIME.name(), () -> this.syncTime(simulation), SimulationConstants.SYNC_TIME_RATE);
|
||||
simulation.addJob(SimulationModule.SYNC_TIME.name(), () -> this.syncTime(simulation), SimulationConstants.SYNC_TIME_RATE);
|
||||
simulation.addFixedRateJob(SimulationModule.MESSAGE.name(), () -> this.run(simulation), SimulationConstants.SEND_CLIENT_RATE);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package club.joylink.rtss.simulation.cbtc.ATS.service;
|
||||
|
||||
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
|
||||
import club.joylink.rtss.simulation.cbtc.ATP.ground.GroundAtpApiService;
|
||||
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
|
||||
import club.joylink.rtss.simulation.cbtc.ATP.ground.ZCLogicLoop;
|
||||
import club.joylink.rtss.simulation.cbtc.CI.CILogicLoop;
|
||||
import club.joylink.rtss.simulation.cbtc.CI.service.RouteService;
|
||||
@ -65,6 +66,8 @@ public class AtsTrainLoadService {
|
||||
|
||||
@Autowired
|
||||
private ZCLogicLoop zcLogicLoop;
|
||||
@Autowired
|
||||
private MaService maService;
|
||||
|
||||
@Autowired
|
||||
private VRTrainRunningService vrTrainRunningService;
|
||||
@ -405,6 +408,7 @@ public class AtsTrainLoadService {
|
||||
// 列车上线并构建ATS监控列车信息
|
||||
this.trainOnlineAndBuildSupervise(simulation, loadedList);
|
||||
// 计算移动授权
|
||||
// this.maService.calculateMaOfCtcTrains(simulation);
|
||||
this.zcLogicLoop.run(simulation);
|
||||
// // 更新列车速度
|
||||
// this.updateTrainSpeed(simulation);
|
||||
|
@ -109,9 +109,7 @@ public class AtsTrainMonitorService {
|
||||
if (dlen < SimulationConstants.PARK_POINT_MAX_OFFSET) {
|
||||
// 停车点停车
|
||||
this.trainParking(simulation, trainInfo, headSection.getStation(), headSection);
|
||||
if (headSection.isNormalStandTrack()) {
|
||||
this.onboardAtpApiService.parkingInPlace(simulation, vrTrain);
|
||||
}
|
||||
this.onboardAtpApiService.parkingInPlace(simulation, vrTrain, headSection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,6 +147,10 @@ public class AtsTriggerRouteService {
|
||||
if (!trainInfo.isPlanTrain()) {
|
||||
return false;
|
||||
}
|
||||
// 计划车没有下一个计划,可能是加载折返情况
|
||||
if (trainInfo.getPlanStandTrack() == null) {
|
||||
return true;
|
||||
}
|
||||
SimulationDataRepository repository = simulation.getRepository();
|
||||
TripPlan tripPlan = repository.getTripPlan(trainInfo.getServiceNumber(), trainInfo.getTripNumber());
|
||||
List<StationPlan> planList = tripPlan.getPlanList();
|
||||
@ -155,12 +159,6 @@ public class AtsTriggerRouteService {
|
||||
StationPlan stationPlan = planList.get(i - 1);
|
||||
StationPlan next = planList.get(i);
|
||||
List<RoutePath> currentPaths = repository.getRoutePaths(stationPlan.getSection(), next.getSection());
|
||||
if (i == 1 && stationPlan.getSection().getCode().equals(trainInfo.getPlanStandTrack())) {
|
||||
if (currentPaths.get(0).isRight() != route.isRight()) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
boolean opposite = false;
|
||||
if (next.getSection().getCode().equals(trainInfo.getPlanStandTrack())) {
|
||||
if (i + 1 < size) {
|
||||
|
@ -9,7 +9,6 @@ import club.joylink.rtss.simulation.cbtc.data.support.SignalApproachMessage;
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.TrainStopMessage;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* CI子系统接口
|
||||
@ -275,13 +274,6 @@ public interface CiApiService {
|
||||
*/
|
||||
void handleSignalApproachMessage(Simulation simulation, List<SignalApproachMessage> approachMessageList);
|
||||
|
||||
/**
|
||||
* 接收处理信号机跨压信息
|
||||
* @param simulation
|
||||
* @param acrossMessageList
|
||||
*/
|
||||
void handleSignalAcrossMessage(Simulation simulation, Set<String> acrossMessageList);
|
||||
|
||||
/**
|
||||
* 接收处理列车停稳信息
|
||||
* @param simulation
|
||||
|
@ -7,7 +7,6 @@ import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.*;
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.SignalApproachMessage;
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.TrainStopMessage;
|
||||
import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo;
|
||||
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySectionAxleCounter;
|
||||
import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
|
||||
import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType;
|
||||
@ -21,7 +20,6 @@ import java.time.LocalTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -394,20 +392,6 @@ public class CiApiServiceImpl implements CiApiService {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSignalAcrossMessage(Simulation simulation,
|
||||
Set<String> acrossMessageList) {
|
||||
acrossMessageList.forEach(signalCode -> {
|
||||
Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class);
|
||||
// if (signal.isNormalOpen()) {
|
||||
Route lockedRoute = signal.getLockedRoute();
|
||||
if (Objects.nonNull(lockedRoute)) {
|
||||
this.routeService.normalUnlockStart(simulation, lockedRoute);
|
||||
}
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTrainStopMessage(Simulation simulation, TrainStopMessage stopMessage) {
|
||||
this.routeService.handleTrainStopMessage(simulation, stopMessage);
|
||||
|
@ -1336,6 +1336,12 @@ public class RouteService {
|
||||
}
|
||||
}
|
||||
if (route.isOpen()) {
|
||||
// 判断是否列车进入正常解锁
|
||||
Section firstLogicSection = route.getFirstLogicSection();
|
||||
if (firstLogicSection.isCtOccupied() || firstLogicSection.isNctOccupied()) {
|
||||
this.normalUnlockStart(simulation, route);
|
||||
return;
|
||||
}
|
||||
boolean interlocked = this.isInterlocked(route);
|
||||
if (!interlocked) {
|
||||
// 进路信号开放,联锁逻辑不满足,需关闭信号
|
||||
|
@ -52,8 +52,10 @@ public class InterlockBuilder2 {
|
||||
Signal signal = unlockSection.getSignalOf(mapOverlapVO.isRight());
|
||||
if (Objects.isNull(signal)) {
|
||||
errMsgList.add(String.format("延续保护[%s(%s)]数据异常,无法找到防护起始信号机", routeOverlap.getName(), routeOverlap.getCode()));
|
||||
} else {
|
||||
routeOverlap.setSignal(signal);
|
||||
signal.getOverlapList().add(routeOverlap);
|
||||
}
|
||||
routeOverlap.setSignal(signal);
|
||||
}
|
||||
if (Objects.isNull(mapOverlapVO.getUnlockTime()) || mapOverlapVO.getUnlockTime() <= 0) {
|
||||
errMsgList.add(String.format("延续保护[%s(%s)]的解锁时间未设置或小于0", routeOverlap.getName(), routeOverlap.getCode()));
|
||||
|
@ -522,16 +522,35 @@ public class Section extends MayOutOfOrderDevice {
|
||||
}
|
||||
|
||||
/**
|
||||
* 有非通信车占用
|
||||
* 是否有非通信车占用
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasNctOccupy() {
|
||||
boolean nct = this.nctOccupied && !this.ctOccupied;
|
||||
if (!CollectionUtils.isEmpty(this.logicList)) {
|
||||
return this.logicList.stream().anyMatch(section -> !section.isCtOccupied() && section.isNctOccupied());
|
||||
} else {
|
||||
return !this.isCtOccupied() && this.isNctOccupied();
|
||||
nct = false;
|
||||
for (Section logic : this.logicList) {
|
||||
if (!logic.isCtOccupied() && logic.isNctOccupied()) {
|
||||
nct = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nct;
|
||||
}
|
||||
|
||||
public boolean isOnlyCtcOccupy() {
|
||||
boolean ctOccupied = this.ctOccupied;
|
||||
if (!CollectionUtils.isEmpty(this.logicList)) {
|
||||
for (Section logic : this.logicList) {
|
||||
if (logic.isCtOccupied()) {
|
||||
ctOccupied = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ctOccupied;
|
||||
}
|
||||
|
||||
public List<Section> getAtpSectionListBy(float offset1, float offset2) {
|
||||
|
@ -24,6 +24,7 @@ public class Signal extends MayOutOfOrderDevice {
|
||||
super(code, name, DeviceType.SIGNAL);
|
||||
this.redOpen = true;
|
||||
this.routeList = new ArrayList<>();
|
||||
this.overlapList = new ArrayList<>();
|
||||
}
|
||||
|
||||
// ------------------固有属性/关联关系---------------------
|
||||
@ -119,6 +120,10 @@ public class Signal extends MayOutOfOrderDevice {
|
||||
* 进路列表
|
||||
*/
|
||||
private List<Route> routeList;
|
||||
/**
|
||||
* 延续保护列表
|
||||
*/
|
||||
private List<RouteOverlap> overlapList;
|
||||
|
||||
/**
|
||||
* 接近锁闭解锁时间
|
||||
|
@ -50,8 +50,8 @@ public class SectionPosition {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" +
|
||||
String.format("section:[%s(%s)]", section.getName(), section.getCode()) +
|
||||
String.format(", offset:[%s]", offset) +
|
||||
String.format("%s(%s)", section.getName(), section.getCode()) +
|
||||
String.format(", %s", offset) +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package club.joylink.rtss.simulation.cbtc.data.vr;
|
||||
|
||||
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
|
||||
import club.joylink.rtss.simulation.cbtc.constant.*;
|
||||
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.*;
|
||||
@ -31,6 +32,11 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
|
||||
*/
|
||||
public static final float Emergency_Acceleration = -1.5f;
|
||||
|
||||
/**
|
||||
* 紧急制动触发曲线计算加速度(矢量)
|
||||
*/
|
||||
public static final float Emergency_Trigger_Acceleration = -1.1f;
|
||||
|
||||
/**
|
||||
* 非紧急制动状态下最大制动加速度(标量)
|
||||
*/
|
||||
@ -176,6 +182,10 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
|
||||
* 车头位置
|
||||
*/
|
||||
private SectionPosition headPosition;
|
||||
/**
|
||||
* 车尾位置
|
||||
*/
|
||||
private SectionPosition tailPosition;
|
||||
|
||||
/**
|
||||
* 是否向右行驶
|
||||
@ -191,6 +201,10 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
|
||||
* 移动授权
|
||||
*/
|
||||
private MovementAuthority ma;
|
||||
/**
|
||||
* 移动授权
|
||||
*/
|
||||
private MaService.Ma ma2;
|
||||
|
||||
/**
|
||||
* 未收到CBTC级别ma的时长,单位毫秒
|
||||
@ -461,6 +475,7 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
|
||||
super(code, groupNumber, DeviceType.TRAIN);
|
||||
this.groupNumber = groupNumber;
|
||||
this.gear = ControlGear.Drive;
|
||||
this.communication = true;
|
||||
this.atpOn = true;
|
||||
this.door1 = new Door("1");
|
||||
this.door2 = new Door("2");
|
||||
@ -489,6 +504,7 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
|
||||
this.terminalStation = null;
|
||||
this.headPosition = null;
|
||||
this.robotTargetPosition = null;
|
||||
this.ma2 = null;
|
||||
this.ma = null;
|
||||
this.cbtcMaMissDuration = 0;
|
||||
this.itcMaMissDuration = 0;
|
||||
@ -613,9 +629,16 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
|
||||
this.autoOpenATO = this.atoOn;
|
||||
}
|
||||
|
||||
public void setTarget(Section target) {
|
||||
this.target = target;
|
||||
// if (this.ma2 != null) {
|
||||
// SpeedCurve.calculateAtoStopCurveAndUpdate(this, this.ma2);
|
||||
// }
|
||||
}
|
||||
|
||||
public synchronized void updateNextStationPlan(Station nextStation, Section targetSection, boolean nextParking) {
|
||||
this.nextStation = nextStation;
|
||||
this.target = targetSection;
|
||||
this.setTarget(targetSection);
|
||||
this.nextParking = nextParking;
|
||||
|
||||
// log.info(String.format("列车[%s]更新下一站[%s] 轨道[%s], [%s]",
|
||||
@ -625,7 +648,7 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
|
||||
}
|
||||
|
||||
public void startTurnBack(Section tbSection) {
|
||||
this.target = tbSection;
|
||||
this.setTarget(tbSection);
|
||||
this.dtro = true;
|
||||
this.nextStation = null;
|
||||
this.terminalStation = null;
|
||||
@ -688,6 +711,7 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
|
||||
|
||||
public void clearMa() {
|
||||
this.ma = null;
|
||||
this.ma2 = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -715,7 +739,8 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
|
||||
}
|
||||
|
||||
public SectionPosition calculateTailPosition() {
|
||||
return CalculateService.calculateNextPositionByStartAndLen(this.headPosition, !right, this.getLen());
|
||||
this.tailPosition = CalculateService.calculateNextPositionByStartAndLen(this.headPosition, !right, this.getLen());
|
||||
return this.tailPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -986,9 +1011,12 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void parkingAt() {
|
||||
// this.parkRemainTime = 30 * 1000;
|
||||
this.standParkedTrainActivity = StandParkedTrainActivity.PARK;
|
||||
public synchronized void parkingAt(Section headSection) {
|
||||
if (headSection.isNormalStandTrack()) {
|
||||
this.standParkedTrainActivity = StandParkedTrainActivity.PARK;
|
||||
} else {
|
||||
this.standParkedTrainActivity = StandParkedTrainActivity.START;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isParkingAt() {
|
||||
|
@ -1,5 +1,7 @@
|
||||
package club.joylink.rtss.simulation.cbtc.onboard.ATO;
|
||||
|
||||
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
|
||||
import club.joylink.rtss.simulation.cbtc.Simulation;
|
||||
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Section;
|
||||
import club.joylink.rtss.simulation.cbtc.data.storage.ato.StorageSpeedCalculator;
|
||||
@ -14,6 +16,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@ -44,6 +47,51 @@ public class SpeedCurve {
|
||||
this.speedCalculators = speedCalculators;
|
||||
}
|
||||
|
||||
public static void calculateAndUpdate(Simulation simulation, VirtualRealityTrain train, MaService.Ma ma) {
|
||||
if (ma.equals(train.getMa2())) {
|
||||
return;
|
||||
}
|
||||
// log.debug(String.format("系统时间:[%s],更新——%s",
|
||||
// simulation.getSystemTime(),
|
||||
// ma.debugStr()));
|
||||
train.setMa2(ma);
|
||||
SpeedCurve.calculateEbTriggerCurveAndUpdate(train, ma);
|
||||
SpeedCurve.calculateAtoStopCurveAndUpdate(train, ma);
|
||||
}
|
||||
|
||||
public static void calculateEbTriggerCurveAndUpdate(VirtualRealityTrain train, MaService.Ma ma) {
|
||||
float distance = ma.calculateDistanceOfEbTriggerEnd();
|
||||
SpeedCurve ebTriggerCurve = SpeedCurve.generateProtectSpeedCurve(distance, train.getAtpSpeedMax());
|
||||
ma.setEbTriggerCurve(ebTriggerCurve);
|
||||
}
|
||||
|
||||
public static SpeedCurve calculateAtoStopCurveAndUpdate(VirtualRealityTrain train, MaService.Ma ma) {
|
||||
SectionPosition headPosition = train.getHeadPosition();
|
||||
SectionPosition tailPosition = train.getTailPosition();
|
||||
boolean right = train.isRight();
|
||||
float stopDistance = ma.calculateDistanceOfAtoEnd();
|
||||
float speedMax = Math.min(train.getAtoSpeedMax(), train.getSpeedLimit() * 0.9f);
|
||||
SpeedCurve atoStopCurve;
|
||||
if (train.isNextParking() || train.isHold()) { // 列车下一站停车
|
||||
Section target = train.getTarget();
|
||||
if (target != null) {
|
||||
float stopPoint = target.getStopPointByDirection(right);
|
||||
SectionPosition stopPosition = new SectionPosition(target, stopPoint);
|
||||
Float stopPointDistance = CalculateService.calculateDistance(headPosition, stopPosition, right);
|
||||
float ebTriggerDistance = ma.calculateDistanceOfEbTriggerEnd();
|
||||
if (stopPointDistance != null && stopPointDistance.floatValue() <= ebTriggerDistance) {
|
||||
// 列车停车位置距离小于eb触发距离
|
||||
stopDistance = stopPointDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
atoStopCurve = SpeedCurve
|
||||
.buildTargetSpeedCurve(headPosition, tailPosition, right,
|
||||
stopDistance, train.getSpeed(), speedMax);
|
||||
// ma.setAtoStopCurve(atoStopCurve);
|
||||
return atoStopCurve;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SpeedCurve{" +
|
||||
@ -127,12 +175,12 @@ public class SpeedCurve {
|
||||
// 先不考虑区段临时限速
|
||||
// 减速段
|
||||
// 减速段总距离
|
||||
float dvDistance = (float) (Math.pow(speedMax, 2) / (2 * VirtualRealityTrain.Emergency_Acceleration));
|
||||
float dvDistance = (float) (Math.pow(speedMax, 2) / (2 * VirtualRealityTrain.Emergency_Trigger_Acceleration));
|
||||
if (dvDistance >= safeDistance) { // 只有减速段
|
||||
// 计算减速段开始位置防护初速度
|
||||
float v0 = (float) Math.sqrt(2 * VirtualRealityTrain.Emergency_Acceleration * safeDistance);
|
||||
float v0 = (float) Math.sqrt(2 * VirtualRealityTrain.Emergency_Trigger_Acceleration * safeDistance);
|
||||
speedCurve.addCalculator(new SpeedCalculator(0, safeDistance,
|
||||
v0, 0, VirtualRealityTrain.Emergency_Acceleration,
|
||||
v0, 0, VirtualRealityTrain.Emergency_Trigger_Acceleration,
|
||||
VSFormula.UNIFORM_DECELERATION));
|
||||
} else { // 有匀速,有减速
|
||||
// 匀速-减速分界位置
|
||||
@ -141,12 +189,58 @@ public class SpeedCurve {
|
||||
speedMax, speedMax, 0,
|
||||
VSFormula.UNIFORM));
|
||||
speedCurve.addCalculator(new SpeedCalculator(point, safeDistance,
|
||||
speedMax, 0, VirtualRealityTrain.Emergency_Acceleration,
|
||||
speedMax, 0, VirtualRealityTrain.Emergency_Trigger_Acceleration,
|
||||
VSFormula.UNIFORM_DECELERATION));
|
||||
}
|
||||
return speedCurve;
|
||||
}
|
||||
|
||||
public static SpeedCurve buildAtoCurve(SectionPosition headPosition, boolean right,
|
||||
float v0, float speedMax, float totalDistance) {
|
||||
if (totalDistance <= 0) {
|
||||
return SpeedCurve.ZERO;
|
||||
}
|
||||
SpeedCurve speedCurve = new SpeedCurve(totalDistance);
|
||||
List<SpeedCalculator> limitSpeedList = new ArrayList<>();
|
||||
float start = 0;
|
||||
float end = 0;
|
||||
float limitSpeed = speedMax;
|
||||
Section logicSection = headPosition.getLogicSection();
|
||||
Section base = headPosition.getSection();
|
||||
if (logicSection.equals(headPosition.getSection())) { // 非逻辑区段
|
||||
end += right ? logicSection.getLen() - headPosition.getOffset() : headPosition.getOffset();
|
||||
} else { // 逻辑区段
|
||||
end += right ? logicSection.getMaxOffset() - headPosition.getOffset() : headPosition.getOffset() - logicSection.getMinOffset();
|
||||
}
|
||||
if (base.getNeedLimitSpeed() != null && base.getNeedLimitSpeed().floatValue() < limitSpeed) {
|
||||
limitSpeed = base.getNeedLimitSpeed();
|
||||
}
|
||||
if (end >= totalDistance) {
|
||||
end = totalDistance;
|
||||
|
||||
}
|
||||
for (int i = 0; i < 15 && base != null; i++) {
|
||||
Float needLimitSpeed = base.getNeedLimitSpeed();
|
||||
if (needLimitSpeed != null) {
|
||||
end += base.getLen();
|
||||
} else if (!CollectionUtils.isEmpty(base.getLogicList())) {
|
||||
List<Section> logicList;
|
||||
if (!right) {
|
||||
logicList = new ArrayList<>(base.getLogicList());
|
||||
Collections.reverse(logicList);
|
||||
} else {
|
||||
logicList = base.getLogicList();
|
||||
}
|
||||
for (Section logic : logicList) {
|
||||
if (headPosition.getLogicSection().equals(logic)) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return speedCurve;
|
||||
}
|
||||
|
||||
public static SpeedCurve buildTargetSpeedCurve(SectionPosition headPosition,
|
||||
SectionPosition tailPosition, boolean right,
|
||||
float totalLen, float v0, float recommendedSpeedMax) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package club.joylink.rtss.simulation.cbtc.onboard.ATO.service;
|
||||
|
||||
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
|
||||
import club.joylink.rtss.simulation.cbtc.CI.CiApiService;
|
||||
import club.joylink.rtss.simulation.cbtc.Simulation;
|
||||
import club.joylink.rtss.simulation.cbtc.communication.vo.TrainDoorSwitch;
|
||||
@ -71,6 +72,37 @@ public class ATOService {
|
||||
}
|
||||
}
|
||||
|
||||
public void ato2(VirtualRealityTrain train) {
|
||||
if (!train.isPowerOn() || !train.isAtoOn()) {
|
||||
return;
|
||||
}
|
||||
//下令停车
|
||||
if (train.isOrderStop()) {
|
||||
this.doBreakMax(train);
|
||||
return;
|
||||
}
|
||||
// 是否EB
|
||||
if (train.isEB()) { // EB中,不控制
|
||||
return;
|
||||
}
|
||||
// 是否停车制动
|
||||
if (train.isBreaking()) { // 站台持续停车制动中,输出持续制动
|
||||
doBreakMax(train);
|
||||
return;
|
||||
}
|
||||
if (train.getTarget() == null)
|
||||
return;
|
||||
MaService.Ma ma = train.getMa2();
|
||||
if (ma == null) {
|
||||
return;
|
||||
}
|
||||
SpeedCurve speedCurve = SpeedCurve.calculateAtoStopCurveAndUpdate(train, ma);
|
||||
// 更新目标距离和建议速度
|
||||
train.setTargetDistance(speedCurve.getTotalDistance());
|
||||
train.setAtoSpeed(speedCurve.getSpeedOf(speedCurve.getTotalDistance()));
|
||||
this.doControlBySpeedCurve(train, speedCurve, speedCurve.getTotalDistance());
|
||||
}
|
||||
|
||||
/**
|
||||
* ATO运算逻辑
|
||||
*/
|
||||
|
@ -1,15 +1,15 @@
|
||||
package club.joylink.rtss.simulation.cbtc.onboard.ATP;
|
||||
|
||||
import club.joylink.rtss.simulation.cbtc.ATP.ground.GroundAtpApiService;
|
||||
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
|
||||
import club.joylink.rtss.simulation.cbtc.ATS.AtsApiService;
|
||||
import club.joylink.rtss.simulation.cbtc.Simulation;
|
||||
import club.joylink.rtss.simulation.cbtc.constant.*;
|
||||
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.MapConfig;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Section;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Signal;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Stand;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Station;
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.MovementAuthority;
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.TrainStopMessage;
|
||||
import club.joylink.rtss.simulation.cbtc.data.vr.StandParkedTrainActivity;
|
||||
@ -130,25 +130,10 @@ public class ATPLogicLoop {
|
||||
// 施加常规制动,防止倒溜
|
||||
this.atoService.openBreaking(train);
|
||||
}
|
||||
if (!train.isParkingAt()) {
|
||||
this.checkParkingAndSend2Ats(simulation, train);
|
||||
} else { // 列车站台停靠
|
||||
if (train.isParkingAt()) {// 列车站台停靠
|
||||
this.handleStandParkedTrain(simulation, train);
|
||||
}
|
||||
|
||||
// if (train.isEB()) { // 列车EB
|
||||
// if (train.isAtpOn()) { // 尝试自动缓解信号EB
|
||||
// if (train.getLeverPosition() == 0 && train.getMa() != null) {
|
||||
// Float distance = CalculateService.calculateDistance(headPosition, train.getMa().getEnd().getEndPosition(), right);
|
||||
// if (distance != null && distance > 100) {
|
||||
// atpService.cancelSignalEB(train);
|
||||
// applicationContext.publishEvent(new SimulationATPAutoCancelEBEvent(this, simulation, train));
|
||||
// log.info(String.format("列车[%s]移动授权距离超过100m,EB自动缓解", train.getGroupNumber()));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/* 缓解EB检查 */
|
||||
if (train.isEB()) {
|
||||
if (train.isRMMode() && train.getControlLeaver() <= 0) { //停车、RM模式、操纵杆非牵引位
|
||||
@ -183,65 +168,81 @@ public class ATPLogicLoop {
|
||||
}
|
||||
|
||||
// 列车ATO自动驾驶逻辑运行
|
||||
this.atoService.ATO(train);
|
||||
// this.atoService.ATO(train);
|
||||
this.atoService.ato2(train);
|
||||
}
|
||||
|
||||
private void calculateSpeedCurve(Simulation simulation, VirtualRealityTrain train) {
|
||||
if (!train.isAtpOn())
|
||||
return;
|
||||
DriveMode driveMode = train.getDriveMode();
|
||||
float atpSpeed = 0;
|
||||
float atoSpeed = 0;
|
||||
switch (driveMode) {
|
||||
case RM: {
|
||||
atpSpeed = simulation.getRepository().getConfig().getRmAtpSpeed();
|
||||
atoSpeed = train.getAtpSpeed() - 5 / 3.6f;
|
||||
float atpSpeed = simulation.getRepository().getConfig().getRmAtpSpeed();
|
||||
float atoSpeed = train.getAtpSpeed() - 5 / 3.6f;
|
||||
train.setAtpSpeed(atpSpeed);
|
||||
train.setAtoSpeed(atoSpeed);
|
||||
break;
|
||||
}
|
||||
case AM:
|
||||
case CM: {
|
||||
// 驾驶故障导致EB
|
||||
MovementAuthority ma = train.getMa();
|
||||
if (Objects.nonNull(ma)) { // 通信正常,移动授权可用
|
||||
// 获取移动授权剩余距离
|
||||
Float remainDistance = atpService.calculateProtectDistance(train, ma.getEnd());
|
||||
if (Objects.isNull(remainDistance) || remainDistance <= 0) {
|
||||
log.warn(String.format("列车[%s]无法计算出移动防护剩余距离或防护距离不为正", train.getGroupNumber()));
|
||||
atpSpeed = 0;
|
||||
atoSpeed = 0;
|
||||
} else {
|
||||
// // 获取防护速度
|
||||
// SpeedCurve protectSpeedCurve = ma.getProtectSpeedCurve();
|
||||
// float protectSpeed = protectSpeedCurve.getSpeedOf(remainDistance);
|
||||
// atpSpeed = protectSpeed;
|
||||
// 计算推荐速度曲线
|
||||
float targetDistance = ATOService.calculateTargetRemainDistance(train, ma);
|
||||
SectionPosition headPosition = train.getHeadPosition();
|
||||
SectionPosition tailPosition = train.calculateTailPosition();
|
||||
boolean right = train.isRight();
|
||||
float speedMax = Math.min(train.getAtoSpeedMax(), train.getSpeedLimit() * 0.9f);
|
||||
SpeedCurve speedCurve = SpeedCurve
|
||||
.buildTargetSpeedCurve(headPosition, tailPosition, right,
|
||||
targetDistance, train.getSpeed(), speedMax);
|
||||
// 更新目标距离和建议速度
|
||||
train.setTargetDistance(targetDistance);
|
||||
train.setSpeedCurve(speedCurve);
|
||||
atoSpeed = speedCurve.getSpeedOf(speedCurve.getTotalDistance());
|
||||
atpSpeed = atoSpeed + 5 / 3.6f;
|
||||
MaService.Ma ma = train.getMa2();
|
||||
if (ma != null) {
|
||||
// EB 触发速度计算
|
||||
SpeedCurve ebTriggerCurve = ma.getEbTriggerCurve();
|
||||
float ebTriggerRemain = ma.calculateDistanceOfEbTriggerEnd();
|
||||
float totalDistance = ebTriggerCurve.getTotalDistance();
|
||||
if (totalDistance < ebTriggerRemain) {
|
||||
ebTriggerRemain = totalDistance;
|
||||
}
|
||||
} else {
|
||||
atpSpeed = 0;
|
||||
atoSpeed = 0;
|
||||
log.warn(String.format("列车[%s-%s|%s|%s]速度[%s]没有移动授权,触发EB",
|
||||
train.getGroupNumber(), train.getServiceNumber(),
|
||||
train.getTripNumber(), train.getDestinationCode(),
|
||||
train.getSpeed()));
|
||||
float atpSpeed = ebTriggerCurve.getSpeedOf(ebTriggerRemain);
|
||||
// ATO推荐速度计算
|
||||
SpeedCurve speedCurve = SpeedCurve.calculateAtoStopCurveAndUpdate(train, ma);
|
||||
float atoSpeed = speedCurve.getSpeedOf(speedCurve.getTotalDistance());
|
||||
train.setAtpSpeed(atpSpeed);
|
||||
train.setAtoSpeed(atoSpeed);
|
||||
}
|
||||
break;
|
||||
// // 驾驶故障导致EB
|
||||
// MovementAuthority ma = train.getMa();
|
||||
// if (Objects.nonNull(ma)) { // 通信正常,移动授权可用
|
||||
// // 获取移动授权剩余距离
|
||||
// Float remainDistance = atpService.calculateProtectDistance(train, ma.getEnd());
|
||||
// if (Objects.isNull(remainDistance) || remainDistance <= 0) {
|
||||
// log.warn(String.format("列车[%s]无法计算出移动防护剩余距离或防护距离不为正", train.getGroupNumber()));
|
||||
// atpSpeed = 0;
|
||||
// atoSpeed = 0;
|
||||
// } else {
|
||||
//// // 获取防护速度
|
||||
//// SpeedCurve protectSpeedCurve = ma.getProtectSpeedCurve();
|
||||
//// float protectSpeed = protectSpeedCurve.getSpeedOf(remainDistance);
|
||||
//// atpSpeed = protectSpeed;
|
||||
// // 计算推荐速度曲线
|
||||
// float targetDistance = ATOService.calculateTargetRemainDistance(train, ma);
|
||||
// SectionPosition headPosition = train.getHeadPosition();
|
||||
// SectionPosition tailPosition = train.calculateTailPosition();
|
||||
// boolean right = train.isRight();
|
||||
// float speedMax = Math.min(train.getAtoSpeedMax(), train.getSpeedLimit() * 0.9f);
|
||||
// SpeedCurve speedCurve = SpeedCurve
|
||||
// .buildTargetSpeedCurve(headPosition, tailPosition, right,
|
||||
// targetDistance, train.getSpeed(), speedMax);
|
||||
// // 更新目标距离和建议速度
|
||||
// train.setTargetDistance(targetDistance);
|
||||
// train.setSpeedCurve(speedCurve);
|
||||
// atoSpeed = speedCurve.getSpeedOf(speedCurve.getTotalDistance());
|
||||
// atpSpeed = atoSpeed + 5 / 3.6f;
|
||||
// }
|
||||
// } else {
|
||||
// atpSpeed = 0;
|
||||
// atoSpeed = 0;
|
||||
// log.warn(String.format("列车[%s-%s|%s|%s]速度[%s]没有移动授权,触发EB",
|
||||
// train.getGroupNumber(), train.getServiceNumber(),
|
||||
// train.getTripNumber(), train.getDestinationCode(),
|
||||
// train.getSpeed()));
|
||||
// }
|
||||
// break;
|
||||
}
|
||||
}
|
||||
train.setAtpSpeed(atpSpeed);
|
||||
train.setAtoSpeed(atoSpeed);
|
||||
|
||||
}
|
||||
|
||||
private void driveModeControl(Simulation simulation, VirtualRealityTrain train) {
|
||||
@ -415,14 +416,21 @@ public class ATPLogicLoop {
|
||||
}
|
||||
|
||||
public boolean checkConditionToMove2(Simulation simulation, VirtualRealityTrain train) {
|
||||
if (train.isParkingAt() && !train.isStandReadyStart()) { // 站台停靠未完成
|
||||
return false;
|
||||
if (train.isParkingAt()) {
|
||||
if (!train.isStandReadyStart()) { // 站台停靠未完成
|
||||
return false;
|
||||
}
|
||||
SectionPosition headPosition = train.getHeadPosition();
|
||||
Signal signal = headPosition.getSection().getSignalOf(train.isRight());
|
||||
if (signal != null && !signal.isNormalOpen() && !(train.isRMMode() || train.isNRMMode())) {// 站台前方信号未开放
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (train.isHold()) {
|
||||
return false;
|
||||
}
|
||||
if (simulation.getRepository().getConfig().isAdjustOperationAutomatically()) {
|
||||
if (train.getDelayTime() == 0) {
|
||||
if (train.getDelayTime() <= 0) {
|
||||
train.setDelayTime(SimulationConstants.ATO_TRAIN_GET_SIGNAL_TO_START_DELAY);
|
||||
return false;
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ public class ATPService {
|
||||
* @param train
|
||||
*/
|
||||
public void speedProtect(Simulation simulation, VirtualRealityTrain train) {
|
||||
if (train.isEB() || !train.isAtpOn()) {
|
||||
if (train.isEB() || !train.isAtpOn() || (!train.isRMMode() && train.getMa2() == null)) {
|
||||
return;
|
||||
}
|
||||
DriveMode driveMode = train.getDriveMode();
|
||||
|
@ -1,5 +1,6 @@
|
||||
package club.joylink.rtss.simulation.cbtc.onboard.ATP;
|
||||
|
||||
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
|
||||
import club.joylink.rtss.simulation.cbtc.Simulation;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Section;
|
||||
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
|
||||
@ -11,6 +12,8 @@ import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
|
||||
*/
|
||||
public interface OnboardAtpApiService {
|
||||
|
||||
void updateCtcMa(Simulation simulation, MaService.Ma ma);
|
||||
|
||||
/**
|
||||
* 更新CBTC移动授权
|
||||
*/
|
||||
@ -116,5 +119,5 @@ public interface OnboardAtpApiService {
|
||||
void checkAndChangeDirection(Simulation simulation, VirtualRealityTrain train,
|
||||
Section targetSection);
|
||||
|
||||
void parkingInPlace(Simulation simulation, VirtualRealityTrain vrTrain);
|
||||
void parkingInPlace(Simulation simulation, VirtualRealityTrain vrTrain, Section headSection);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package club.joylink.rtss.simulation.cbtc.onboard.ATP;
|
||||
|
||||
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
|
||||
import club.joylink.rtss.simulation.cbtc.Simulation;
|
||||
import club.joylink.rtss.simulation.cbtc.constant.DriveMode;
|
||||
import club.joylink.rtss.simulation.cbtc.constant.RunLevel;
|
||||
@ -11,6 +12,7 @@ import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.MovementAuthority;
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.RoutePath;
|
||||
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
|
||||
import club.joylink.rtss.simulation.cbtc.onboard.ATO.SpeedCurve;
|
||||
import club.joylink.rtss.simulation.cbtc.onboard.ATO.service.ATOService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -30,6 +32,13 @@ public class OnboardAtpApiServiceImpl implements OnboardAtpApiService {
|
||||
@Autowired
|
||||
private ATOService ATOService;
|
||||
|
||||
@Override
|
||||
public void updateCtcMa(Simulation simulation, MaService.Ma ma) {
|
||||
VirtualRealityTrain train = ma.getTrain();
|
||||
SpeedCurve.calculateAndUpdate(simulation, train, ma);
|
||||
train.setCbtcMaMissDuration(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMA4CBTC(VirtualRealityTrain train, MovementAuthority ma) {
|
||||
if (ma == null)
|
||||
@ -275,7 +284,7 @@ public class OnboardAtpApiServiceImpl implements OnboardAtpApiService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parkingInPlace(Simulation simulation, VirtualRealityTrain vrTrain) {
|
||||
vrTrain.parkingAt();
|
||||
public void parkingInPlace(Simulation simulation, VirtualRealityTrain vrTrain, Section headSection) {
|
||||
vrTrain.parkingAt(headSection);
|
||||
}
|
||||
}
|
||||
|
@ -12,12 +12,6 @@ public class SimulationInfoVO {
|
||||
String name;
|
||||
Integer speed;
|
||||
LocalDateTime systemTime;
|
||||
// Integer year;
|
||||
// Integer month;
|
||||
// Integer day;
|
||||
// Integer hour;
|
||||
// Integer minute;
|
||||
// Integer second;
|
||||
Integer state;
|
||||
List<SimulationUserVO> userList;
|
||||
|
||||
@ -27,13 +21,6 @@ public class SimulationInfoVO {
|
||||
this.speed = simulation.getSpeed();
|
||||
this.state = simulation.getState();
|
||||
this.systemTime = simulation.getSystemTime();
|
||||
// LocalDateTime systemTime = simulation.getSystemTime();
|
||||
// this.year = systemTime.getYear();
|
||||
// this.month = systemTime.getMonthValue();
|
||||
// this.day = systemTime.getDayOfMonth();
|
||||
// this.hour = systemTime.getHour();
|
||||
// this.minute = systemTime.getMinute();
|
||||
// this.second = systemTime.getSecond();
|
||||
}
|
||||
|
||||
public void setUserList(List<SimulationUserVO> userList) {
|
||||
|
Loading…
Reference in New Issue
Block a user