diff --git a/component/iscs_pscada.go b/component/iscs_pscada.go index 1186f5e..1bec9cf 100644 --- a/component/iscs_pscada.go +++ b/component/iscs_pscada.go @@ -83,9 +83,18 @@ type VoltageTransformer struct { // PowerPipe 电力母线 type PowerPipe struct { - Voltage uint32 //母线当前电压 - Ac bool //true-交流电;false-直流电 - Sources map[string]ElePower //key-电源PowerSource实体id + Voltage uint32 //母线当前电压 + Ac bool //true-交流电;false-直流电 + Sources map[string]*ElePower //key-电源PowerSource实体id +} + +func (p *PowerPipe) TransPower(powerSourceId string, power *ElePower) { + ep, ok := p.Sources[powerSourceId] + if ok { + *ep = *power + } else { + p.Sources[powerSourceId] = power + } } // ElePower 传输中的电力 diff --git a/entity/iscs_load.go b/entity/iscs_load.go index 7d3504e..7c10c1e 100644 --- a/entity/iscs_load.go +++ b/entity/iscs_load.go @@ -46,8 +46,3 @@ func LoadIscs(w ecs.World) error { // return nil } - -/* - - PipeFittingMap map[string]*PipeFitting //ISCS 管件 -*/ diff --git a/entity/iscs_pscada.go b/entity/iscs_pscada.go index bd11e05..8e344b2 100644 --- a/entity/iscs_pscada.go +++ b/entity/iscs_pscada.go @@ -112,6 +112,7 @@ func NewPowerPipeEntity(w ecs.World, id string) *ecs.Entry { if !ok { e := w.Entry(w.Create(component.UidType, component.PowerPipeType)) component.UidType.SetValue(e, component.Uid{Id: id}) + component.PowerPipeType.Set(e, &component.PowerPipe{Sources: make(map[string]*component.ElePower)}) wd.EntityMap[id] = e } return e diff --git a/proto/src/model.proto b/proto/src/model.proto index a1b58fc..107a500 100644 --- a/proto/src/model.proto +++ b/proto/src/model.proto @@ -568,7 +568,7 @@ message HandcartSwitch{ } //整流器 -//PSCADA中整流器有两个交流输入端分别为A和B;直流输出端口有两个分别为直流正极端口C和直流负极端口D +//PSCADA中整流器有两个交流输入端分别为A(火线L)和B(零线N);直流输出端口有两个分别为直流正极端口C(+正极)和直流负极端口D(-负极) message Rectifier{ string id = 1; string code = 2; diff --git a/repository/iscs_pscada_yc.go b/repository/iscs_pscada_yc.go index d8d6e90..0b8ceb5 100644 --- a/repository/iscs_pscada_yc.go +++ b/repository/iscs_pscada_yc.go @@ -75,6 +75,16 @@ func (p *PipeFitting) Ports() []*PipePort { return ports } +// IsEle true-管件为电力管件 +func (p *PipeFitting) IsEle() bool { + for _, port := range p.Ports() { + if port.pipe.PipeType != proto.Pipe_ElectricPower { + return false + } + } + return true +} + // PipeFittingPort 管件端口 // // implement DevicePort @@ -201,14 +211,14 @@ func (p *HandcartSwitchPort) Device() PortedDevice { // Rectifier 整流器模型 // -// PSCADA中整流器有两个交流输入端分别为A和B;直流输出端口有两个分别为直流正极端口C和直流负极端口D +// PSCADA中整流器有两个交流输入端分别为A(火线L)和B(零线N);直流输出端口有两个分别为直流正极端口C(+正极)和直流负极端口D(-负极) type Rectifier struct { Identity Code string - PortA *PipePort //整流器A端口连接的管线 - PortB *PipePort //整流器B端口连接的管线 - PortC *PipePort //整流器C端口连接的管线 - PortD *PipePort //整流器D端口连接的管线 + PortA *PipePort //整流器A端口连接的管线,交流L(火线) + PortB *PipePort //整流器B端口连接的管线,交流N(零线) + PortC *PipePort //整流器C端口连接的管线,直流+ + PortD *PipePort //整流器D端口连接的管线,直流- } func NewRectifier(id string, code string) *Rectifier { diff --git a/sys/iscs_sys/iscs_pscada_power_pipe.go b/sys/iscs_sys/iscs_pscada_power_pipe.go deleted file mode 100644 index 2aab55f..0000000 --- a/sys/iscs_sys/iscs_pscada_power_pipe.go +++ /dev/null @@ -1,36 +0,0 @@ -package iscs_sys - -import ( - "joylink.club/ecs" - "joylink.club/ecs/filter" - "joylink.club/rtsssimulation/component" - "time" -) - -// PowerPipeSystem 电力母线,计算母线中的电压 -type PowerPipeSystem struct { - query *ecs.Query -} - -func NewPowerPipeSystem() *PowerPipeSystem { - return &PowerPipeSystem{query: ecs.NewQuery(filter.Contains(component.PowerPipeType))} -} -func (s *PowerPipeSystem) Update(w ecs.World) { - //计算电力母线中的电压 - s.query.Each(w, func(entry *ecs.Entry) { - pipe := component.PowerPipeType.Get(entry) - voltage := uint32(0) - ac := false - for _, power := range pipe.Sources { - if time.Now().UnixMilli()-power.Fresh <= int64(w.Tick()*2) { - if power.Voltage > voltage { - voltage = power.Voltage - ac = power.Ac - } - } - } - // - pipe.Voltage = voltage - pipe.Ac = ac - }) -} diff --git a/sys/iscs_sys/iscs_pscada_power_transmission.go b/sys/iscs_sys/iscs_pscada_power_transmission.go index e6d5ce4..050b245 100644 --- a/sys/iscs_sys/iscs_pscada_power_transmission.go +++ b/sys/iscs_sys/iscs_pscada_power_transmission.go @@ -1,11 +1,283 @@ package iscs_sys -import "joylink.club/ecs" +import ( + "joylink.club/ecs" + "joylink.club/ecs/filter" + "joylink.club/rtsssimulation/component" + "joylink.club/rtsssimulation/entity" + "joylink.club/rtsssimulation/repository" + "time" +) -// PowerTransmissionSystem 电力传递系统 +// PowerTransmissionSystem 电力传递系统(电压传递) type PowerTransmissionSystem struct { + queryPowerSource *ecs.Query //电力电源 + queryPowerPipe *ecs.Query //电力母线 + queryCircuitBreaker *ecs.Query //断路器 + queryHandcart *ecs.Query //手车 + queryDisconnector *ecs.Query //隔离开关 + query3PositionSwitch *ecs.Query //三工位隔离开关 + queryRectifier *ecs.Query //整流器 } +func NewPowerTransmissionSystem() *PowerTransmissionSystem { + return &PowerTransmissionSystem{ + queryPowerSource: ecs.NewQuery(filter.Contains(component.UidType, component.PowerSourceType)), + queryPowerPipe: ecs.NewQuery(filter.Contains(component.PowerPipeType)), + queryCircuitBreaker: ecs.NewQuery(filter.Contains(component.UidType, component.CircuitBreakerType)), + queryHandcart: ecs.NewQuery(filter.Contains(component.UidType, component.HandcartSwitchType)), + queryDisconnector: ecs.NewQuery(filter.Contains(component.UidType, component.DisconnectorType)), + query3PositionSwitch: ecs.NewQuery(filter.Contains(component.UidType, component.ThreePositionSwitchType)), + queryRectifier: ecs.NewQuery(filter.Contains(component.UidType, component.RectifierType)), + } +} func (s *PowerTransmissionSystem) Update(w ecs.World) { - + s.powerSourceTransPower(w) + s.circuitBreakerTransPower(w) + s.handcartTransPower(w) + s.disconnectorTransPower(w) + s.threePositionSwitchTransPower(w) + s.pipeFittingTransPower(w) + s.rectifierTransPower(w) + s.powerPipePower(w) +} + +// 整流器电能传递 +// 当线路接通时零线和负极电压规定值为1,当线路断开时零线和负极电压规定值为0 +func (s *PowerTransmissionSystem) rectifierTransPower(w ecs.World) { + wd := entity.GetWorldData(w) + s.queryRectifier.Each(w, func(entry *ecs.Entry) { + rectifierId := component.UidType.Get(entry).Id + rectifierModel := wd.Repo.FindById(rectifierId).(*repository.Rectifier) + // + portL := rectifierModel.PortA //交火 + //portN := rectifierModel.PortB //交零 + portZ := rectifierModel.PortC //直正 + portF := rectifierModel.PortD //直负 + // + portLPipeEntry := wd.EntityMap[portL.Device().Id()] + portLPipe := component.PowerPipeType.Get(portLPipeEntry) + // + portZPipeEntry := wd.EntityMap[portZ.Device().Id()] + portZPipe := component.PowerPipeType.Get(portZPipeEntry) + portFPipeEntry := wd.EntityMap[portF.Device().Id()] + portFPipe := component.PowerPipeType.Get(portFPipeEntry) + //L->Z、F + for lpsId, lps := range portLPipe.Sources { + if lps.Ac { + dcVoltage := uint32(float64(lps.Voltage) * 0.9) //交流电压转直流电压 + //L->Z + zps, zpsOk := portZPipe.Sources[lpsId] + if zpsOk { + zps.Voltage = dcVoltage + zps.Fresh = lps.Fresh - 1 + zps.Ac = false + } else { + portZPipe.Sources[lpsId] = &component.ElePower{Ac: false, Voltage: dcVoltage, Fresh: lps.Fresh - 1} + } + //L->F + fps, fpsOk := portFPipe.Sources[lpsId] + dcFVoltage := uint32(0) + if dcVoltage > 0 { + dcFVoltage = 1 + } + if fpsOk { + fps.Voltage = dcFVoltage + fps.Fresh = lps.Fresh - 1 + fps.Ac = false + } else { + portFPipe.Sources[lpsId] = &component.ElePower{Ac: false, Voltage: dcFVoltage, Fresh: lps.Fresh - 1} + } + } + } + + }) +} + +// 三工位隔离开关传递电能 +func (s *PowerTransmissionSystem) threePositionSwitchTransPower(w ecs.World) { + wd := entity.GetWorldData(w) + s.query3PositionSwitch.Each(w, func(entry *ecs.Entry) { + breakerId := component.UidType.Get(entry).Id + closed := component.ThreePositionSwitchType.Get(entry).Position == component.StpClosedWorking + breakerModel := (wd.Repo.FindById(breakerId)).(*repository.ThreePositionSwitch) + breakerPortA := breakerModel.PortA + breakerPortB := breakerModel.PortB + s.towPipePortsTransPower(wd, closed, breakerPortA, breakerPortB) + }) +} + +// 隔离开关传递电能 +func (s *PowerTransmissionSystem) disconnectorTransPower(w ecs.World) { + wd := entity.GetWorldData(w) + s.queryHandcart.Each(w, func(entry *ecs.Entry) { + breakerId := component.UidType.Get(entry).Id + closed := component.DisconnectorType.Get(entry).Closed + breakerModel := (wd.Repo.FindById(breakerId)).(*repository.Disconnector) + breakerPortA := breakerModel.PortA + breakerPortB := breakerModel.PortB + s.towPipePortsTransPower(wd, closed, breakerPortA, breakerPortB) + }) +} + +// 手车传递电能 +func (s *PowerTransmissionSystem) handcartTransPower(w ecs.World) { + wd := entity.GetWorldData(w) + s.queryHandcart.Each(w, func(entry *ecs.Entry) { + breakerId := component.UidType.Get(entry).Id + closed := component.HandcartSwitchType.Get(entry).Position == component.HpClosed + breakerModel := (wd.Repo.FindById(breakerId)).(*repository.HandcartSwitch) + breakerPortA := breakerModel.PortA + breakerPortB := breakerModel.PortB + s.towPipePortsTransPower(wd, closed, breakerPortA, breakerPortB) + }) +} + +// 断路器传递电能 +func (s *PowerTransmissionSystem) circuitBreakerTransPower(w ecs.World) { + wd := entity.GetWorldData(w) + s.queryCircuitBreaker.Each(w, func(entry *ecs.Entry) { + breakerId := component.UidType.Get(entry).Id + closed := component.CircuitBreakerType.Get(entry).Closed + breakerModel := (wd.Repo.FindById(breakerId)).(*repository.CircuitBreaker) + //断路器A端连接的管线 + breakerPortA := breakerModel.PortA + //断路器B端连接的管线 + breakerPortB := breakerModel.PortB + //传递电能 + s.towPipePortsTransPower(wd, closed, breakerPortA, breakerPortB) + }) +} + +// 电力母线中电力计算 +func (s *PowerTransmissionSystem) powerPipePower(w ecs.World) { + s.queryPowerPipe.Each(w, func(entry *ecs.Entry) { + pipe := component.PowerPipeType.Get(entry) + voltage := uint32(0) + ac := false + for _, power := range pipe.Sources { + if power.Voltage > voltage { + voltage = power.Voltage + ac = power.Ac + } + } + // + pipe.Voltage = voltage + pipe.Ac = ac + }) +} + +// 电源传递电能 +func (s *PowerTransmissionSystem) powerSourceTransPower(w ecs.World) { + wd := entity.GetWorldData(w) + s.queryPowerSource.Each(w, func(entry *ecs.Entry) { + psId := component.UidType.Get(entry).Id + ps := component.PowerSourceType.Get(entry) + // + psModel := (wd.Repo.FindById(psId)).(*repository.PowerSource) + pipeId := psModel.PortA.Device().Id() + //电源传递电力给母线 + pipeEntry := wd.EntityMap[pipeId] + powerPipe := component.PowerPipeType.Get(pipeEntry) + powerPipe.TransPower(psId, &component.ElePower{Ac: ps.Ac, Voltage: ps.Voltage, Fresh: time.Now().UnixMilli()}) + }) +} + +// 母线管件传递电能 +func (s *PowerTransmissionSystem) pipeFittingTransPower(w ecs.World) { + wd := entity.GetWorldData(w) + for _, pf := range wd.Repo.PipeFittingMap { + if pf.IsEle() { + //与管件连接的所有管线 + pipes := pf.Ports() + //筛选出相对电源 + pipePsMap := make(map[string]*component.ElePower) + for _, pipePort := range pipes { + pipeEntry := wd.EntityMap[pipePort.Device().Id()] + powerPipe := component.PowerPipeType.Get(pipeEntry) + for epId, ep := range powerPipe.Sources { + pipePs, ok := pipePsMap[epId] + if ok { + if ep.Fresh > pipePs.Fresh { + pipePsMap[epId] = ep + } + } else { + pipePsMap[epId] = ep + } + } + } + //管件连接的管线间电能传递 + for _, pipePort := range pipes { + for pipePsId, pipePs := range pipePsMap { //相对电源 + pipeEntry := wd.EntityMap[pipePort.Device().Id()] + powerPipe := component.PowerPipeType.Get(pipeEntry) + pipePortPs, ok := powerPipe.Sources[pipePsId] + if ok { + if pipePs.Fresh > pipePortPs.Fresh { + *powerPipe.Sources[pipePsId] = *pipePs + powerPipe.Sources[pipePsId].Fresh -= 1 //保证相对性 + } + } else { + powerPipe.Sources[pipePsId] = &component.ElePower{} + *powerPipe.Sources[pipePsId] = *pipePs + powerPipe.Sources[pipePsId].Fresh -= 1 //保证相对性 + } + } + } + } + } +} + +// 两位置开关传递电能(断路器、手车、隔离开关) +func (s *PowerTransmissionSystem) towPipePortsTransPower( + wd *component.WorldData, + closed bool, + breakerPortA *repository.PipePort, + breakerPortB *repository.PipePort) { + //断路器A端连接的管线 + breakerPortAPipeEntry := wd.EntityMap[breakerPortA.Device().Id()] + breakerPortAPipe := component.PowerPipeType.Get(breakerPortAPipeEntry) + //断路器B端连接的管线 + breakerPortBPipeEntry := wd.EntityMap[breakerPortB.Device().Id()] + breakerPortBPipe := component.PowerPipeType.Get(breakerPortBPipeEntry) + //A->B + for portAPipePsId, portAPipePs := range breakerPortAPipe.Sources { //A + portBPipePs, ok := breakerPortBPipe.Sources[portAPipePsId] //B + if ok { + if portAPipePs.Fresh > portBPipePs.Fresh { + *breakerPortBPipe.Sources[portAPipePsId] = *portAPipePs + breakerPortBPipe.Sources[portAPipePsId].Fresh -= 1 + if !closed { + breakerPortBPipe.Sources[portAPipePsId].Voltage = 0 + } + } + } else { + breakerPortBPipe.Sources[portAPipePsId] = &component.ElePower{} + *breakerPortBPipe.Sources[portAPipePsId] = *portAPipePs + breakerPortBPipe.Sources[portAPipePsId].Fresh -= 1 + if !closed { + breakerPortBPipe.Sources[portAPipePsId].Voltage = 0 + } + } + } + //B->A + for portBPipePsId, portBPipePs := range breakerPortBPipe.Sources { //B + portAPipePs, ok := breakerPortAPipe.Sources[portBPipePsId] //A + if ok { + if portBPipePs.Fresh > portAPipePs.Fresh { + *breakerPortAPipe.Sources[portBPipePsId] = *portBPipePs + breakerPortAPipe.Sources[portBPipePsId].Fresh -= 1 + if !closed { + breakerPortAPipe.Sources[portBPipePsId].Voltage = 0 + } + } + } else { + breakerPortAPipe.Sources[portBPipePsId] = &component.ElePower{} + *breakerPortAPipe.Sources[portBPipePsId] = *portBPipePs + breakerPortAPipe.Sources[portBPipePsId].Fresh -= 1 + if !closed { + breakerPortAPipe.Sources[portBPipePsId].Voltage = 0 + } + } + } }