mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#176 generator trip detection on supervisor
This commit is contained in:
parent
8b1e7cb933
commit
0f735d049e
@ -14,7 +14,7 @@ local svsessions = require("supervisor.session.svsessions")
|
|||||||
local config = require("supervisor.config")
|
local config = require("supervisor.config")
|
||||||
local supervisor = require("supervisor.supervisor")
|
local supervisor = require("supervisor.supervisor")
|
||||||
|
|
||||||
local SUPERVISOR_VERSION = "v0.14.0"
|
local SUPERVISOR_VERSION = "v0.14.1"
|
||||||
|
|
||||||
local print = util.print
|
local print = util.print
|
||||||
local println = util.println
|
local println = util.println
|
||||||
|
@ -154,7 +154,8 @@ function unit.new(reactor_id, num_boilers, num_turbines)
|
|||||||
ReactorHighWaste = { state = AISTATE.INACTIVE, trip_time = 0, hold_time = 2, id = ALARM.ReactorHighWaste, tier = PRIO.URGENT },
|
ReactorHighWaste = { state = AISTATE.INACTIVE, trip_time = 0, hold_time = 2, id = ALARM.ReactorHighWaste, tier = PRIO.URGENT },
|
||||||
-- RPS trip occured
|
-- RPS trip occured
|
||||||
RPSTransient = { state = AISTATE.INACTIVE, trip_time = 0, hold_time = 2, id = ALARM.RPSTransient, tier = PRIO.TIMELY },
|
RPSTransient = { state = AISTATE.INACTIVE, trip_time = 0, hold_time = 2, id = ALARM.RPSTransient, tier = PRIO.TIMELY },
|
||||||
-- BoilRateMismatch, CoolantFeedMismatch, SteamFeedMismatch, MaxWaterReturnFeed
|
-- CoolantLevelLow, WaterLevelLow, TurbineOverSpeed, MaxWaterReturnFeed, RCPTrip, RCSFlowLow, BoilRateMismatch, CoolantFeedMismatch,
|
||||||
|
-- SteamFeedMismatch, MaxWaterReturnFeed, RCS hardware fault
|
||||||
RCSTransient = { state = AISTATE.INACTIVE, trip_time = 0, hold_time = 5, id = ALARM.RCSTransient, tier = PRIO.TIMELY },
|
RCSTransient = { state = AISTATE.INACTIVE, trip_time = 0, hold_time = 5, id = ALARM.RCSTransient, tier = PRIO.TIMELY },
|
||||||
-- "It's just a routine turbin' trip!" -Bill Gibson, "The China Syndrome"
|
-- "It's just a routine turbin' trip!" -Bill Gibson, "The China Syndrome"
|
||||||
TurbineTrip = { state = AISTATE.INACTIVE, trip_time = 0, hold_time = 2, id = ALARM.TurbineTrip, tier = PRIO.URGENT }
|
TurbineTrip = { state = AISTATE.INACTIVE, trip_time = 0, hold_time = 2, id = ALARM.TurbineTrip, tier = PRIO.URGENT }
|
||||||
@ -195,6 +196,7 @@ function unit.new(reactor_id, num_boilers, num_turbines)
|
|||||||
TurbineOnline = {},
|
TurbineOnline = {},
|
||||||
SteamDumpOpen = {},
|
SteamDumpOpen = {},
|
||||||
TurbineOverSpeed = {},
|
TurbineOverSpeed = {},
|
||||||
|
GeneratorTrip = {},
|
||||||
TurbineTrip = {}
|
TurbineTrip = {}
|
||||||
},
|
},
|
||||||
---@class alarms
|
---@class alarms
|
||||||
@ -238,6 +240,7 @@ function unit.new(reactor_id, num_boilers, num_turbines)
|
|||||||
table.insert(self.db.annunciator.TurbineOnline, false)
|
table.insert(self.db.annunciator.TurbineOnline, false)
|
||||||
table.insert(self.db.annunciator.SteamDumpOpen, TRI_FAIL.OK)
|
table.insert(self.db.annunciator.SteamDumpOpen, TRI_FAIL.OK)
|
||||||
table.insert(self.db.annunciator.TurbineOverSpeed, false)
|
table.insert(self.db.annunciator.TurbineOverSpeed, false)
|
||||||
|
table.insert(self.db.annunciator.GeneratorTrip, false)
|
||||||
table.insert(self.db.annunciator.TurbineTrip, false)
|
table.insert(self.db.annunciator.TurbineTrip, false)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -312,7 +315,6 @@ function unit.new(reactor_id, num_boilers, num_turbines)
|
|||||||
local last_update_s = db.tanks.last_update / 1000.0
|
local last_update_s = db.tanks.last_update / 1000.0
|
||||||
|
|
||||||
_compute_dt(DT_KEYS.TurbineSteam .. turbine.get_device_idx(), db.tanks.steam.amount, last_update_s)
|
_compute_dt(DT_KEYS.TurbineSteam .. turbine.get_device_idx(), db.tanks.steam.amount, last_update_s)
|
||||||
---@todo unused currently?
|
|
||||||
_compute_dt(DT_KEYS.TurbinePower .. turbine.get_device_idx(), db.tanks.energy, last_update_s)
|
_compute_dt(DT_KEYS.TurbinePower .. turbine.get_device_idx(), db.tanks.energy, last_update_s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -316,12 +316,13 @@ function logic.update_annunciator(self)
|
|||||||
self.db.annunciator.SteamFeedMismatch = sfmismatch
|
self.db.annunciator.SteamFeedMismatch = sfmismatch
|
||||||
self.db.annunciator.MaxWaterReturnFeed = max_water_return_rate == total_flow_rate and total_flow_rate ~= 0
|
self.db.annunciator.MaxWaterReturnFeed = max_water_return_rate == total_flow_rate and total_flow_rate ~= 0
|
||||||
|
|
||||||
-- check if steam dumps are open
|
-- turbine safety checks
|
||||||
for i = 1, #self.turbines do
|
for i = 1, #self.turbines do
|
||||||
local turbine = self.turbines[i] ---@type unit_session
|
local turbine = self.turbines[i] ---@type unit_session
|
||||||
local db = turbine.get_db() ---@type turbinev_session_db
|
local db = turbine.get_db() ---@type turbinev_session_db
|
||||||
local idx = turbine.get_device_idx()
|
local idx = turbine.get_device_idx()
|
||||||
|
|
||||||
|
-- check if steam dumps are open
|
||||||
if db.state.dumping_mode == DUMPING_MODE.IDLE then
|
if db.state.dumping_mode == DUMPING_MODE.IDLE then
|
||||||
self.db.annunciator.SteamDumpOpen[idx] = TRI_FAIL.OK
|
self.db.annunciator.SteamDumpOpen[idx] = TRI_FAIL.OK
|
||||||
elseif db.state.dumping_mode == DUMPING_MODE.DUMPING_EXCESS then
|
elseif db.state.dumping_mode == DUMPING_MODE.DUMPING_EXCESS then
|
||||||
@ -329,16 +330,19 @@ function logic.update_annunciator(self)
|
|||||||
else
|
else
|
||||||
self.db.annunciator.SteamDumpOpen[idx] = TRI_FAIL.FULL
|
self.db.annunciator.SteamDumpOpen[idx] = TRI_FAIL.FULL
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
-- check if turbines are at max speed but not keeping up
|
-- check if turbines are at max speed but not keeping up
|
||||||
for i = 1, #self.turbines do
|
|
||||||
local turbine = self.turbines[i] ---@type unit_session
|
|
||||||
local db = turbine.get_db() ---@type turbinev_session_db
|
|
||||||
local idx = turbine.get_device_idx()
|
|
||||||
|
|
||||||
self.db.annunciator.TurbineOverSpeed[idx] = (db.state.flow_rate == db.build.max_flow_rate) and (_get_dt(DT_KEYS.TurbineSteam .. idx) > 0.0)
|
self.db.annunciator.TurbineOverSpeed[idx] = (db.state.flow_rate == db.build.max_flow_rate) and (_get_dt(DT_KEYS.TurbineSteam .. idx) > 0.0)
|
||||||
end
|
|
||||||
|
--[[
|
||||||
|
Generator Trip
|
||||||
|
a generator trip is when a generator suddenly and unexpectedly loses it's external load
|
||||||
|
oftentimes this is when a power plant is disconnected from the grid for one reason or another
|
||||||
|
in this case we just:
|
||||||
|
- check if internal power storage of turbine is increasing
|
||||||
|
that means there is no external load and there will be a turbine trip soon if this is not resolved
|
||||||
|
]]--
|
||||||
|
self.db.annunciator.GeneratorTrip[idx] = _get_dt(DT_KEYS.TurbinePower .. idx) > 0.0
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
Turbine Trip
|
Turbine Trip
|
||||||
@ -348,10 +352,6 @@ function logic.update_annunciator(self)
|
|||||||
- can initially catch this by detecting a 0 flow rate with a non-zero input rate, but eventually the steam will fill up
|
- can initially catch this by detecting a 0 flow rate with a non-zero input rate, but eventually the steam will fill up
|
||||||
- can later identified by presence of steam in tank with a 0 flow rate
|
- can later identified by presence of steam in tank with a 0 flow rate
|
||||||
]]--
|
]]--
|
||||||
for i = 1, #self.turbines do
|
|
||||||
local turbine = self.turbines[i] ---@type unit_session
|
|
||||||
local db = turbine.get_db() ---@type turbinev_session_db
|
|
||||||
|
|
||||||
local has_steam = db.state.steam_input_rate > 0 or db.tanks.steam_fill > 0.01
|
local has_steam = db.state.steam_input_rate > 0 or db.tanks.steam_fill > 0.01
|
||||||
self.db.annunciator.TurbineTrip[turbine.get_device_idx()] = has_steam and db.state.flow_rate == 0
|
self.db.annunciator.TurbineTrip[turbine.get_device_idx()] = has_steam and db.state.flow_rate == 0
|
||||||
end
|
end
|
||||||
@ -506,10 +506,12 @@ function logic.update_alarms(self)
|
|||||||
-- RCS Transient
|
-- RCS Transient
|
||||||
local any_low = annunc.CoolantLevelLow
|
local any_low = annunc.CoolantLevelLow
|
||||||
local any_over = false
|
local any_over = false
|
||||||
|
local gen_trip = false
|
||||||
for i = 1, #annunc.WaterLevelLow do any_low = any_low or annunc.WaterLevelLow[i] end
|
for i = 1, #annunc.WaterLevelLow do any_low = any_low or annunc.WaterLevelLow[i] end
|
||||||
for i = 1, #annunc.TurbineOverSpeed do any_over = any_over or annunc.TurbineOverSpeed[i] end
|
for i = 1, #annunc.TurbineOverSpeed do any_over = any_over or annunc.TurbineOverSpeed[i] end
|
||||||
|
for i = 1, #annunc.GeneratorTrip do gen_trip = gen_trip or annunc.GeneratorTrip[i] end
|
||||||
|
|
||||||
local rcs_trans = any_low or any_over or annunc.RCPTrip or annunc.MaxWaterReturnFeed
|
local rcs_trans = any_low or any_over or gen_trip or annunc.RCPTrip or annunc.MaxWaterReturnFeed
|
||||||
|
|
||||||
-- only care about RCS flow low early with boilers
|
-- only care about RCS flow low early with boilers
|
||||||
if self.num_boilers > 0 then rcs_trans = rcs_trans or annunc.RCSFlowLow end
|
if self.num_boilers > 0 then rcs_trans = rcs_trans or annunc.RCSFlowLow end
|
||||||
|
Loading…
Reference in New Issue
Block a user