仿真结构抽象(仿真主线程逻辑调整)
虚拟真实设备逻辑开发
This commit is contained in:
parent
fb7f3fa70c
commit
6abd8254b6
@ -28,12 +28,12 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
|
||||
*/
|
||||
private LocalDateTime systemTime;
|
||||
|
||||
private static final int SYSTEM_TIME_RATE = 10;
|
||||
private static final int SYSTEM_TIME_RATE = 1;
|
||||
private final AtomicBoolean mainLogicRunning = new AtomicBoolean(false);
|
||||
/**
|
||||
* 实际运行间隔,单位ns
|
||||
*/
|
||||
long runPeriod;
|
||||
long timeAdd;
|
||||
/**
|
||||
* 用来取消仿真线程逻辑定时执行的任务
|
||||
*/
|
||||
@ -82,25 +82,40 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
|
||||
throw new IllegalArgumentException("仿真id不能为空");
|
||||
}
|
||||
this.id = id;
|
||||
this.speed = speed;
|
||||
this.systemTime = LocalDateTime.now();
|
||||
this.runAsSpeed(speed);
|
||||
}
|
||||
|
||||
private void runAsSpeed(int speed) {
|
||||
this.speed = speed;
|
||||
if (this.future != null) {
|
||||
if (!this.future.cancel(false)) {
|
||||
log.error(String.format("仿真旧主线程无法取消"));
|
||||
public static void main(String[] args) {
|
||||
Simulation simulation = new Simulation("1") {
|
||||
@Override
|
||||
public String debugStr() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
simulation.addJob("b", () -> {
|
||||
log.info("logic");
|
||||
}, 500);
|
||||
simulation.addFixedRateJob("c", () -> {
|
||||
log.warn("fixed");
|
||||
}, 1000);
|
||||
simulation.updateSpeed(5);
|
||||
simulation.start();
|
||||
}
|
||||
this.updateRunPeriod(speed);
|
||||
private void runAsSpeed() {
|
||||
if (this.future == null) {
|
||||
// if (!this.future.cancel(false)) {
|
||||
// log.error(String.format("仿真旧主线程无法取消"));
|
||||
// }
|
||||
ScheduledFuture<?> scheduledFuture = EXECUTOR.scheduleAtFixedRate(()->this.logic(),
|
||||
this.runPeriod, this.runPeriod, TimeUnit.NANOSECONDS);
|
||||
this.SYSTEM_TIME_RATE, this.SYSTEM_TIME_RATE, TimeUnit.MILLISECONDS);
|
||||
this.future = scheduledFuture;
|
||||
}
|
||||
this.updateTimeUpdateSpeed(this.speed);
|
||||
}
|
||||
|
||||
private void updateRunPeriod(int speed) {
|
||||
this.runPeriod = TimeUnit.MILLISECONDS.toNanos(SYSTEM_TIME_RATE) / speed;
|
||||
private void updateTimeUpdateSpeed(int speed) {
|
||||
this.timeAdd = TimeUnit.MILLISECONDS.toNanos(SYSTEM_TIME_RATE) * speed;
|
||||
}
|
||||
|
||||
private void logic() {
|
||||
@ -109,7 +124,7 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
|
||||
}
|
||||
try {
|
||||
this.mainLogicRunning.set(true);
|
||||
this.systemTime = this.systemTime.plusNanos(TimeUnit.MILLISECONDS.toNanos(SYSTEM_TIME_RATE));
|
||||
this.systemTime = this.systemTime.plusNanos(timeAdd);
|
||||
for (SimulationScheduledJob scheduledJob : this.scheduledJobMap.values()) {
|
||||
if (scheduledJob.isTimeToRun(this.systemTime)) {
|
||||
scheduledJob.run();
|
||||
@ -221,6 +236,7 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
|
||||
*/
|
||||
public void start() {
|
||||
this.state.set(RUNNING);
|
||||
this.runAsSpeed();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -260,9 +276,10 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
|
||||
throw new IllegalArgumentException(String.format("speed must small or equal than [%s]", MAX_SPEED));
|
||||
}
|
||||
if (this.speed != speed) { // 速度不同,重新更改并重新按新速度运行
|
||||
this.speed = speed;
|
||||
int state = this.state.get();
|
||||
this.pause();
|
||||
this.runAsSpeed(speed);
|
||||
this.runAsSpeed();
|
||||
for (SimulationScheduledJob job : this.scheduledJobMap.values()) {
|
||||
job.updateRunPeriod(speed);
|
||||
}
|
||||
|
@ -46,23 +46,23 @@ final class SimulationScheduledJob implements Runnable {
|
||||
this(simulation, name, job, rate, false);
|
||||
}
|
||||
|
||||
public static final int TIMEOUT = 10;
|
||||
public static final long TIMEOUT_NANO = TimeUnit.MILLISECONDS.toNanos(10);
|
||||
@Override
|
||||
public void run() {
|
||||
long start = System.nanoTime();
|
||||
this.job.run();
|
||||
long used = System.nanoTime() - start;
|
||||
if (used > TimeUnit.MILLISECONDS.toNanos(TIMEOUT)) {
|
||||
log.warn(String.format("仿真任务[%s]执行耗时[%sns]超过[%sms],请检查并调优",
|
||||
this.name, TimeUnit.NANOSECONDS.toMillis(used), TIMEOUT));
|
||||
if (used > TIMEOUT_NANO) {
|
||||
log.warn(String.format("仿真任务[%s]执行耗时[%sns]超过[%sns],请检查并调优",
|
||||
this.name, used, TIMEOUT_NANO));
|
||||
}
|
||||
}
|
||||
|
||||
public void updateRunPeriod(int speed) {
|
||||
if (this.fixed) {
|
||||
this.runPeriod = TimeUnit.MILLISECONDS.toNanos(this.rate);
|
||||
this.runPeriod = TimeUnit.MILLISECONDS.toNanos(this.rate) * speed;
|
||||
} else {
|
||||
this.runPeriod = TimeUnit.MILLISECONDS.toNanos(this.rate) / speed;
|
||||
this.runPeriod = TimeUnit.MILLISECONDS.toNanos(this.rate);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,32 +1,42 @@
|
||||
package club.joylink.rtss.simulation.rt;
|
||||
|
||||
import club.joylink.rtss.services.MapService;
|
||||
import club.joylink.rtss.simulation.SimulationManager;
|
||||
import club.joylink.rtss.simulation.rt.srd.SrdService;
|
||||
import club.joylink.rtss.vo.UserVO;
|
||||
import club.joylink.rtss.vo.client.map.MapVO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Component
|
||||
public class RtSimulationService {
|
||||
@Autowired
|
||||
private MapService mapService;
|
||||
|
||||
@Autowired
|
||||
private SimulationManager simulationManager;
|
||||
|
||||
@Autowired
|
||||
private SrdService srdService;
|
||||
|
||||
public RtSimulation create(UserVO userVO) {
|
||||
public RtSimulation create(UserVO userVO, Long mapId) {
|
||||
Objects.requireNonNull(mapId);
|
||||
MapVO mapVO = this.mapService.getMapDetail(mapId);
|
||||
RtSimulation rtSimulation = new RtSimulation(SimulationIdGenerator.buildId());
|
||||
this.simulationManager.save(rtSimulation);
|
||||
this.load(rtSimulation);
|
||||
this.loadData(rtSimulation, mapVO);
|
||||
this.srdService.addJobs(rtSimulation);
|
||||
this.simulationManager.save(rtSimulation);
|
||||
return rtSimulation;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载相关数据
|
||||
* @param rtSimulation
|
||||
* @param mapVO
|
||||
*/
|
||||
private void load(RtSimulation rtSimulation) {
|
||||
|
||||
private void loadData(RtSimulation rtSimulation, MapVO mapVO) {
|
||||
this.srdService.buildRepository(rtSimulation, mapVO);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
package club.joylink.rtss.simulation.rt.srd;
|
||||
|
||||
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
|
||||
import club.joylink.rtss.simulation.rt.RtSimulation;
|
||||
import club.joylink.rtss.simulation.rt.srd.bo.SrTrain;
|
||||
import club.joylink.rtss.simulation.rt.srd.bo.SrdRepository;
|
||||
import club.joylink.rtss.simulation.rt.srd.bo.SrdRepositoryBuilder;
|
||||
import club.joylink.rtss.simulation.rt.srd.bo.TrackPosition;
|
||||
import club.joylink.rtss.simulation.rt.srd.bo.*;
|
||||
import club.joylink.rtss.vo.client.map.MapVO;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@ -28,14 +26,76 @@ public class SrdService {
|
||||
public void srTrainRun(SrdRepository repository) {
|
||||
List<SrTrain> trainList = repository.getTrainList();
|
||||
for (SrTrain srTrain : trainList) {
|
||||
TrackPosition position = srTrain.getPosition();
|
||||
if (position == null) { // 列车没有位置
|
||||
if (!srTrain.isUsing()) {
|
||||
continue;
|
||||
}
|
||||
if (srTrain.isNeutralGear()) { // 空挡
|
||||
continue;
|
||||
TrackPosition position = srTrain.getPosition();
|
||||
long speed = srTrain.getSpeed();
|
||||
boolean right = srTrain.isRight();
|
||||
int cv = this.calculateSpeed(srTrain);
|
||||
int s = this.calculateLen(cv, TRAIN_RUN_RATE);
|
||||
TrackPosition np = calculatePosition(position, s, right);
|
||||
if (np.equals(position) && cv != 0) {
|
||||
cv = 0;
|
||||
}
|
||||
srTrain.updatePositionAndSpeed(np, cv);
|
||||
}
|
||||
}
|
||||
|
||||
private int calculateLen(int cv, int time) {
|
||||
return cv * time;
|
||||
}
|
||||
|
||||
private int calculateSpeed(SrTrain srTrain) {
|
||||
long speed = srTrain.getSpeed();
|
||||
int wa = (int) (10 + speed * 0.001 + speed * speed * 0.0000003); // 阻力所产生的反向加速度
|
||||
int pa = 0;
|
||||
if (srTrain.isEb()) {
|
||||
pa = SrTrain.ES_DEC;
|
||||
} else {
|
||||
pa = srTrain.getP() >= 0 ? srTrain.getP() * SrTrain.MAX_ACC : srTrain.getP() * SrTrain.MAX_DEC;
|
||||
}
|
||||
int a = pa - wa;
|
||||
int cv = (int) (speed + a * TRAIN_RUN_RATE); // 当前速度
|
||||
if (cv < 0) {
|
||||
cv = 0;
|
||||
}
|
||||
return cv;
|
||||
}
|
||||
|
||||
private TrackPosition calculatePosition(TrackPosition position, int s, boolean right) {
|
||||
if (s == 0) {
|
||||
return position;
|
||||
}
|
||||
SrTrack track = position.getTrack();
|
||||
int offset = position.getOffset();
|
||||
if (right) {
|
||||
offset += s;
|
||||
} else {
|
||||
offset -= s;
|
||||
}
|
||||
SrTrack base = track;
|
||||
while (offset < 0 || offset > base.getLen()) {
|
||||
SrTrack nextTrack = base.queryNextTrack(right);
|
||||
if (nextTrack == null) {
|
||||
if (offset < 0) {
|
||||
offset = 0;
|
||||
} else {
|
||||
offset = base.getLen();
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
if (right) {
|
||||
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotTrue(offset < 0);
|
||||
offset -= base.getLen();
|
||||
} else {
|
||||
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotTrue(offset > base.getLen());
|
||||
offset += nextTrack.getLen();
|
||||
}
|
||||
base = nextTrack;
|
||||
}
|
||||
}
|
||||
return new TrackPosition(base, offset);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,13 +25,21 @@ public class SrTrack extends SrDevice {
|
||||
*/
|
||||
SrAXC axc;
|
||||
/**
|
||||
* 左侧轨道(可能为null)
|
||||
* 左侧直向轨道(可能为null)
|
||||
*/
|
||||
SrTrack left;
|
||||
SrTrack leftTrack;
|
||||
/**
|
||||
* 左侧侧向轨道(非道岔的都为null)
|
||||
*/
|
||||
SrTrack leftFlankTrack;
|
||||
/**
|
||||
* 右侧轨道(可能为null)
|
||||
*/
|
||||
SrTrack right;
|
||||
SrTrack rightTrack;
|
||||
/**
|
||||
* 右侧侧向轨道(非道岔的都为null)
|
||||
*/
|
||||
SrTrack rightFlankTrack;
|
||||
/**
|
||||
* 关联的道岔(是道岔区段才会关联,否则为null)
|
||||
*/
|
||||
@ -45,17 +53,52 @@ public class SrTrack extends SrDevice {
|
||||
this.axc = axc;
|
||||
}
|
||||
|
||||
public void setLeft(SrTrack left) {
|
||||
this.left = left;
|
||||
left.setRight(this);
|
||||
public void setLeftTrack(SrTrack left) {
|
||||
this.leftTrack = left;
|
||||
left.setRightTrack(this);
|
||||
}
|
||||
|
||||
public void setRight(SrTrack right) {
|
||||
this.right = right;
|
||||
right.setLeft(this);
|
||||
public void setLeftFlankTrack(SrTrack leftFlank) {
|
||||
this.leftFlankTrack = leftFlank;
|
||||
leftFlank.setRightTrack(this);
|
||||
}
|
||||
|
||||
public void setRightTrack(SrTrack right) {
|
||||
this.rightTrack = right;
|
||||
right.setLeftTrack(this);
|
||||
}
|
||||
|
||||
public void setRightFlankTrack(SrTrack rightFlank) {
|
||||
this.rightFlankTrack = rightFlank;
|
||||
rightFlank.setLeftTrack(this);
|
||||
}
|
||||
|
||||
public void setTurnout(SrTurnout turnout) {
|
||||
this.turnout = turnout;
|
||||
}
|
||||
|
||||
public SrTrack queryNextTrack(boolean right) {
|
||||
if (this.turnout != null) {
|
||||
if (this.turnout.isNormalPosition()) {
|
||||
return right ? this.rightTrack : this.leftTrack;
|
||||
} else if (this.turnout.isReversePosition()) {
|
||||
if (right) {
|
||||
if (this.rightFlankTrack != null) {
|
||||
return this.rightFlankTrack;
|
||||
} else {
|
||||
return this.rightTrack;
|
||||
}
|
||||
} else {
|
||||
if (this.leftFlankTrack != null) {
|
||||
return this.leftFlankTrack;
|
||||
} else {
|
||||
return this.leftTrack;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return right ? this.rightTrack : this.leftTrack;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,10 @@ import lombok.Getter;
|
||||
*/
|
||||
@Getter
|
||||
public class SrTrain extends SrDevice {
|
||||
/**
|
||||
* 是否使用中
|
||||
*/
|
||||
boolean using;
|
||||
|
||||
/**
|
||||
* 列车长度,单位mm
|
||||
@ -15,13 +19,29 @@ public class SrTrain extends SrDevice {
|
||||
/**
|
||||
* 列车质量,单位:吨
|
||||
*/
|
||||
int mass = 230;
|
||||
int mass = 224;
|
||||
/**
|
||||
* 牵引力,<0为制动
|
||||
* 最大加速度, 单位mm/s2
|
||||
*/
|
||||
int f;
|
||||
public static final int MAX_ACC = 1600;
|
||||
/**
|
||||
* 列车速度
|
||||
* 最大常用制动加速度, 单位mm/s2
|
||||
*/
|
||||
public static final int MAX_DEC = -1200;
|
||||
/**
|
||||
* 紧急制动加速度, 单位mm/s2
|
||||
*/
|
||||
public static final int ES_DEC = -1500;
|
||||
/**
|
||||
* 功率-100 <= p <= 100
|
||||
*/
|
||||
int p;
|
||||
/**
|
||||
* 是否紧急制动
|
||||
*/
|
||||
boolean eb;
|
||||
/**
|
||||
* 列车速度,单位mm/s
|
||||
*/
|
||||
int speed;
|
||||
/**
|
||||
@ -48,4 +68,9 @@ public class SrTrain extends SrDevice {
|
||||
public boolean isNeutralGear() {
|
||||
return NEUTRAL == this.gear;
|
||||
}
|
||||
|
||||
public void updatePositionAndSpeed(TrackPosition position, int v) {
|
||||
this.position = position;
|
||||
this.speed = v;
|
||||
}
|
||||
}
|
||||
|
@ -30,18 +30,27 @@ public class SrTurnout extends SrDevice {
|
||||
super(id, DeviceType.TURNOUT);
|
||||
}
|
||||
|
||||
public void setA(SrTrack a) {
|
||||
public void setTracks(SrTrack a, SrTrack b, SrTrack c) {
|
||||
this.a = a;
|
||||
a.setTurnout(this);
|
||||
}
|
||||
|
||||
public void setB(SrTrack b) {
|
||||
this.b = b;
|
||||
b.setTurnout(this);
|
||||
this.c = c;
|
||||
if (this.a.leftTrack == null && this.a.rightTrack == null) {
|
||||
throw new IllegalStateException("道岔a区段两端都没有关联的区段");
|
||||
}
|
||||
if (this.a.leftTrack != null) { // a左侧存在
|
||||
this.a.setRightTrack(this.b);
|
||||
this.a.setRightFlankTrack(this.c);
|
||||
} else { // a右侧存在
|
||||
this.a.setLeftTrack(this.b);
|
||||
this.a.setLeftFlankTrack(this.c);
|
||||
}
|
||||
}
|
||||
|
||||
public void setC(SrTrack c) {
|
||||
this.c = c;
|
||||
c.setTurnout(this);
|
||||
public boolean isNormalPosition() {
|
||||
return NORMAL == this.state.get();
|
||||
}
|
||||
|
||||
public boolean isReversePosition() {
|
||||
return REVERSE == this.state.get();
|
||||
}
|
||||
}
|
||||
|
@ -43,13 +43,13 @@ public class SrdRepositoryBuilder {
|
||||
SrTrack left = trackMap.get(sectionVO.getLeftSectionCode());
|
||||
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(left,
|
||||
String.format("区段[%s]的左关联区段[%s]不存在", srTrack.getId(), sectionVO.getLeftSectionCode()));
|
||||
srTrack.setLeft(left);
|
||||
srTrack.setLeftTrack(left);
|
||||
}
|
||||
if (StringUtils.hasText(sectionVO.getRightSectionCode())) {
|
||||
SrTrack right = trackMap.get(sectionVO.getRightSectionCode());
|
||||
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(right,
|
||||
String.format("区段[%s]的右关联区段[%s]不存在", srTrack.getId(), sectionVO.getRightSectionCode()));
|
||||
srTrack.setRight(right);
|
||||
srTrack.setRightTrack(right);
|
||||
}
|
||||
// 构建轨道和计轴关系
|
||||
SrAXC axc;
|
||||
@ -91,9 +91,7 @@ public class SrdRepositoryBuilder {
|
||||
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(c,
|
||||
String.format("道岔[%s]关联区段C[%s]不存在", switchVO.getCode(), switchVO.getSectionCCode()));
|
||||
SrTurnout turnout = turnoutMap.get(switchVO.getCode());
|
||||
turnout.setA(a);
|
||||
turnout.setB(b);
|
||||
turnout.setC(c);
|
||||
turnout.setTracks(a, b, c);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,4 +3,17 @@ package club.joylink.rtss.simulation.rt.srd.bo;
|
||||
public class TrackPosition {
|
||||
SrTrack track;
|
||||
int offset;
|
||||
|
||||
public TrackPosition(SrTrack track, int offset) {
|
||||
this.track = track;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public SrTrack getTrack() {
|
||||
return track;
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user