mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#470 reworked flow stability logic
This commit is contained in:
parent
d0b50c834c
commit
a6a1a61954
@ -68,8 +68,8 @@ constants.ALARM_LIMITS = alarms
|
|||||||
|
|
||||||
--#region Supervisor Constants
|
--#region Supervisor Constants
|
||||||
|
|
||||||
-- milliseconds until turbine flow is assumed to be stable enough to enable coolant checks
|
-- milliseconds until coolant flow is assumed to be stable enough to enable certain coolant checks
|
||||||
constants.FLOW_STABILITY_DELAY_MS = 15000
|
constants.FLOW_STABILITY_DELAY_MS = 10000
|
||||||
|
|
||||||
-- Notes on Radiation
|
-- Notes on Radiation
|
||||||
-- - background radiation 0.0000001 Sv/h (99.99 nSv/h)
|
-- - background radiation 0.0000001 Sv/h (99.99 nSv/h)
|
||||||
|
@ -106,6 +106,8 @@ function unit.new(reactor_id, num_boilers, num_turbines)
|
|||||||
status_text = { "UNKNOWN", "awaiting connection..." },
|
status_text = { "UNKNOWN", "awaiting connection..." },
|
||||||
-- logic for alarms
|
-- logic for alarms
|
||||||
had_reactor = false,
|
had_reactor = false,
|
||||||
|
turbine_flow_stable = false,
|
||||||
|
turbine_stability_data = {},
|
||||||
last_rate_change_ms = 0,
|
last_rate_change_ms = 0,
|
||||||
---@type rps_status
|
---@type rps_status
|
||||||
last_rps_trips = {
|
last_rps_trips = {
|
||||||
@ -253,12 +255,14 @@ function unit.new(reactor_id, num_boilers, num_turbines)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- init turbine table fields
|
-- init turbine table fields
|
||||||
for _ = 1, num_turbines do
|
for t = 1, num_turbines do
|
||||||
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.GeneratorTrip, false)
|
||||||
table.insert(self.db.annunciator.TurbineTrip, false)
|
table.insert(self.db.annunciator.TurbineTrip, false)
|
||||||
|
|
||||||
|
self.turbine_stability_data[t] = { time_state = 0, time_tanks = 0, rotation = 1 }
|
||||||
end
|
end
|
||||||
|
|
||||||
-- PRIVATE FUNCTIONS --
|
-- PRIVATE FUNCTIONS --
|
||||||
|
@ -39,6 +39,21 @@ local ALARM_LIMS = const.ALARM_LIMITS
|
|||||||
---@class unit_logic_extension
|
---@class unit_logic_extension
|
||||||
local logic = {}
|
local logic = {}
|
||||||
|
|
||||||
|
-- compute Mekanism's rotation rate for a turbine
|
||||||
|
---@param turbine turbinev_session_db
|
||||||
|
local function turbine_rotation(turbine)
|
||||||
|
local build = turbine.build
|
||||||
|
|
||||||
|
local inner_vol = build.steam_cap / 64000
|
||||||
|
local disp_rate = (build.dispersers * 1280) * inner_vol
|
||||||
|
local vent_rate = build.vents * 32000
|
||||||
|
|
||||||
|
local max_rate = math.min(disp_rate, vent_rate)
|
||||||
|
local flow = math.min(max_rate, turbine.tanks.steam.amount)
|
||||||
|
|
||||||
|
return (flow * (turbine.tanks.steam.amount / build.steam_cap)) / max_rate
|
||||||
|
end
|
||||||
|
|
||||||
-- update the annunciator
|
-- update the annunciator
|
||||||
---@param self _unit_self
|
---@param self _unit_self
|
||||||
function logic.update_annunciator(self)
|
function logic.update_annunciator(self)
|
||||||
@ -81,6 +96,11 @@ function logic.update_annunciator(self)
|
|||||||
-- some alarms wait until the burn rate has stabilized, so keep track of that
|
-- some alarms wait until the burn rate has stabilized, so keep track of that
|
||||||
if math.abs(_get_dt(DT_KEYS.ReactorBurnR)) > 0 then
|
if math.abs(_get_dt(DT_KEYS.ReactorBurnR)) > 0 then
|
||||||
self.last_rate_change_ms = util.time_ms()
|
self.last_rate_change_ms = util.time_ms()
|
||||||
|
self.turbine_flow_stable = false
|
||||||
|
|
||||||
|
for t = 1, self.num_turbines do
|
||||||
|
self.turbine_stability_data[t] = { time_state = 0, time_tanks = 0, rotation = 1 }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- record reactor stats
|
-- record reactor stats
|
||||||
@ -274,6 +294,7 @@ function logic.update_annunciator(self)
|
|||||||
local total_flow_rate = 0
|
local total_flow_rate = 0
|
||||||
local total_input_rate = 0
|
local total_input_rate = 0
|
||||||
local max_water_return_rate = 0
|
local max_water_return_rate = 0
|
||||||
|
local turbines_stable = true
|
||||||
|
|
||||||
-- recompute blade count on the chance that it may have changed
|
-- recompute blade count on the chance that it may have changed
|
||||||
self.db.control.blade_count = 0
|
self.db.control.blade_count = 0
|
||||||
@ -282,12 +303,14 @@ function logic.update_annunciator(self)
|
|||||||
for i = 1, #self.turbines do
|
for i = 1, #self.turbines do
|
||||||
local session = self.turbines[i] ---@type unit_session
|
local session = self.turbines[i] ---@type unit_session
|
||||||
local turbine = session.get_db() ---@type turbinev_session_db
|
local turbine = session.get_db() ---@type turbinev_session_db
|
||||||
|
local idx = session.get_device_idx()
|
||||||
|
|
||||||
annunc.RCSFault = annunc.RCSFault or (not turbine.formed) or session.is_faulted()
|
annunc.RCSFault = annunc.RCSFault or (not turbine.formed) or session.is_faulted()
|
||||||
|
annunc.TurbineOnline[idx] = true
|
||||||
|
|
||||||
-- update ready state
|
-- update ready state
|
||||||
-- - must be formed
|
-- - must be formed
|
||||||
-- - must have received build, state, and tanks at least once
|
-- - must have received build, state, and tanks at least once
|
||||||
turbines_ready = turbines_ready and turbine.formed and
|
turbines_ready = turbines_ready and turbine.formed and
|
||||||
(turbine.build.last_update > 0) and
|
(turbine.build.last_update > 0) and
|
||||||
(turbine.state.last_update > 0) and
|
(turbine.state.last_update > 0) and
|
||||||
@ -296,11 +319,56 @@ function logic.update_annunciator(self)
|
|||||||
total_flow_rate = total_flow_rate + turbine.state.flow_rate
|
total_flow_rate = total_flow_rate + turbine.state.flow_rate
|
||||||
total_input_rate = total_input_rate + turbine.state.steam_input_rate
|
total_input_rate = total_input_rate + turbine.state.steam_input_rate
|
||||||
max_water_return_rate = max_water_return_rate + turbine.build.max_water_output
|
max_water_return_rate = max_water_return_rate + turbine.build.max_water_output
|
||||||
|
|
||||||
self.db.control.blade_count = self.db.control.blade_count + turbine.build.blades
|
self.db.control.blade_count = self.db.control.blade_count + turbine.build.blades
|
||||||
|
|
||||||
annunc.TurbineOnline[session.get_device_idx()] = true
|
local last = self.turbine_stability_data[i]
|
||||||
|
|
||||||
|
if (not self.turbine_flow_stable) and (turbine.state.steam_input_rate > 0) then
|
||||||
|
local rotation = turbine_rotation(turbine)
|
||||||
|
local rotation_stable = false
|
||||||
|
|
||||||
|
-- see if data updated, and if so, check rotation speed change
|
||||||
|
-- minimal change indicates the turbine is converging on a flow rate
|
||||||
|
if last.time_tanks < turbine.tanks.last_update then
|
||||||
|
if last.time_tanks > 0 then
|
||||||
|
rotation_stable = math.abs(rotation - last.rotation) < 0.00000004
|
||||||
|
end
|
||||||
|
|
||||||
|
last.time_tanks = turbine.tanks.last_update
|
||||||
|
last.rotation = rotation
|
||||||
|
end
|
||||||
|
|
||||||
|
-- flow is stable if the flow rate is at the input rate or at the max (±1 mB/t)
|
||||||
|
local flow_stable = false
|
||||||
|
if last.time_state < turbine.state.last_update then
|
||||||
|
if (last.time_state > 0) and (turbine.state.flow_rate > 0) then
|
||||||
|
flow_stable = math.abs(turbine.state.flow_rate - math.min(turbine.state.steam_input_rate, turbine.build.max_flow_rate)) < 2
|
||||||
|
end
|
||||||
|
|
||||||
|
last.time_state = turbine.state.last_update
|
||||||
|
end
|
||||||
|
|
||||||
|
if rotation_stable then
|
||||||
|
log.debug(util.c("UNIT ", self.r_id, ": turbine ", idx, " reached rotational stability (", rotation, ")"))
|
||||||
|
end
|
||||||
|
|
||||||
|
if flow_stable then
|
||||||
|
log.debug(util.c("UNIT ", self.r_id, ": turbine ", idx, " reached flow stability (", turbine.state.flow_rate, " mB/t)"))
|
||||||
|
end
|
||||||
|
|
||||||
|
turbines_stable = turbines_stable and (rotation_stable or flow_stable)
|
||||||
|
else
|
||||||
|
last.time_state = 0
|
||||||
|
last.time_tanks = 0
|
||||||
|
last.rotation = 1
|
||||||
|
|
||||||
|
turbines_stable = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self.turbine_flow_stable = self.turbine_flow_stable or turbines_stable
|
||||||
|
|
||||||
-- check for boil rate mismatch (> 4% error) either between reactor and turbine or boiler and turbine
|
-- check for boil rate mismatch (> 4% error) either between reactor and turbine or boiler and turbine
|
||||||
annunc.BoilRateMismatch = math.abs(total_boil_rate - total_input_rate) > (0.04 * total_boil_rate)
|
annunc.BoilRateMismatch = math.abs(total_boil_rate - total_input_rate) > (0.04 * total_boil_rate)
|
||||||
|
|
||||||
@ -508,11 +576,25 @@ function logic.update_alarms(self)
|
|||||||
|
|
||||||
local rcs_trans = any_low or any_over or gen_trip or annunc.RCPTrip or annunc.MaxWaterReturnFeed
|
local rcs_trans = any_low or any_over or gen_trip or annunc.RCPTrip or annunc.MaxWaterReturnFeed
|
||||||
|
|
||||||
-- annunciator indicators for these states may not indicate a real issue when:
|
if plc_cache.active then
|
||||||
-- > flow is ramping up right after reactor start
|
-- these conditions may not indicate an issue when flow is changing after a burn rate change
|
||||||
-- > flow is ramping down after reactor shutdown
|
if self.num_boilers == 0 then
|
||||||
if ((util.time_ms() - self.last_rate_change_ms) > FLOW_STABILITY_DELAY_MS) and plc_cache.active then
|
if (util.time_ms() - self.last_rate_change_ms) > FLOW_STABILITY_DELAY_MS then
|
||||||
rcs_trans = rcs_trans or annunc.RCSFlowLow or annunc.BoilRateMismatch or annunc.CoolantFeedMismatch or annunc.SteamFeedMismatch
|
rcs_trans = rcs_trans or annunc.BoilRateMismatch
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.turbine_flow_stable then
|
||||||
|
rcs_trans = rcs_trans or annunc.RCSFlowLow or annunc.CoolantFeedMismatch or annunc.SteamFeedMismatch
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if (util.time_ms() - self.last_rate_change_ms) > FLOW_STABILITY_DELAY_MS then
|
||||||
|
rcs_trans = rcs_trans or annunc.RCSFlowLow or annunc.BoilRateMismatch or annunc.CoolantFeedMismatch
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.turbine_flow_stable then
|
||||||
|
rcs_trans = rcs_trans or annunc.SteamFeedMismatch
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if _update_alarm_state(self, rcs_trans, self.alarms.RCSTransient) then
|
if _update_alarm_state(self, rcs_trans, self.alarms.RCSTransient) then
|
||||||
@ -666,7 +748,9 @@ function logic.update_status_text(self)
|
|||||||
elseif annunc.WasteLineOcclusion then
|
elseif annunc.WasteLineOcclusion then
|
||||||
self.status_text[2] = "insufficient waste output rate"
|
self.status_text[2] = "insufficient waste output rate"
|
||||||
elseif (util.time_ms() - self.last_rate_change_ms) <= FLOW_STABILITY_DELAY_MS then
|
elseif (util.time_ms() - self.last_rate_change_ms) <= FLOW_STABILITY_DELAY_MS then
|
||||||
self.status_text[2] = "awaiting flow stability"
|
self.status_text[2] = "awaiting coolant flow stability"
|
||||||
|
elseif not self.turbine_flow_stable then
|
||||||
|
self.status_text[2] = "awaiting turbine flow stability"
|
||||||
else
|
else
|
||||||
self.status_text[2] = "system nominal"
|
self.status_text[2] = "system nominal"
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user