.
This commit is contained in:
parent
7eec32ad38
commit
59cfe70407
118
de_react_auto
118
de_react_auto
@ -347,7 +347,18 @@ local function calculateFieldInput()
|
|||||||
-- Add 10% safety margin, but ensure minimum of 1M RF/t during warmup when drain is 0
|
-- Add 10% safety margin, but ensure minimum of 1M RF/t during warmup when drain is 0
|
||||||
local minimumInput = math.max(drainRate * 1.1, 1000000)
|
local minimumInput = math.max(drainRate * 1.1, 1000000)
|
||||||
|
|
||||||
return math.max(minimumInput, math.floor(totalInput))
|
local result = math.max(minimumInput, math.floor(totalInput))
|
||||||
|
|
||||||
|
-- Verbose output
|
||||||
|
local fieldPct = string.format("%.1f%%", currentStrength * 100)
|
||||||
|
local targetPct = string.format("%.1f%%", targetStrength * 100)
|
||||||
|
if currentStrength < targetStrength - 0.01 then
|
||||||
|
print("[FIELD] " .. fieldPct .. " < " .. targetPct .. " target -> increasing input to " .. formatNumber(result) .. " RF/t")
|
||||||
|
elseif currentStrength > targetStrength + 0.01 then
|
||||||
|
print("[FIELD] " .. fieldPct .. " > " .. targetPct .. " target -> reducing input to " .. formatNumber(result) .. " RF/t")
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Calculate safe output rate based on temperature and saturation
|
-- Calculate safe output rate based on temperature and saturation
|
||||||
@ -368,52 +379,66 @@ local function calculateOutputRate()
|
|||||||
local temp = reactorInfo.temperature or 0
|
local temp = reactorInfo.temperature or 0
|
||||||
local saturation = reactorInfo.energySaturation / reactorInfo.maxEnergySaturation
|
local saturation = reactorInfo.energySaturation / reactorInfo.maxEnergySaturation
|
||||||
local generationRate = reactorInfo.generationRate or 0
|
local generationRate = reactorInfo.generationRate or 0
|
||||||
|
local result = 0
|
||||||
|
local reason = ""
|
||||||
|
|
||||||
-- If we're in emergency or cooling, limit output
|
-- If we're in emergency or cooling, limit output
|
||||||
if state == STATES.EMERGENCY then
|
if state == STATES.EMERGENCY then
|
||||||
return 0
|
result = 0
|
||||||
|
reason = "EMERGENCY state"
|
||||||
|
elseif state == STATES.COOLING then
|
||||||
|
result = math.floor(generationRate * 0.5)
|
||||||
|
reason = "COOLING - 50% of generation"
|
||||||
|
elseif state == STATES.CHARGING or state == STATES.WARMING_UP then
|
||||||
|
result = math.floor(generationRate * 0.8)
|
||||||
|
reason = state .. " - 80% of generation"
|
||||||
|
else
|
||||||
|
-- Normal operation
|
||||||
|
local tempFactor = 1.0
|
||||||
|
if temp > CONFIG.critical_temperature then
|
||||||
|
local overTemp = temp - CONFIG.critical_temperature
|
||||||
|
local tempRange = CONFIG.max_temperature - CONFIG.critical_temperature
|
||||||
|
tempFactor = 1.0 - (overTemp / tempRange) * 0.5
|
||||||
|
reason = "temp " .. formatTemp(temp) .. " > critical, factor=" .. string.format("%.2f", tempFactor)
|
||||||
|
end
|
||||||
|
|
||||||
|
local outputRate = generationRate * tempFactor
|
||||||
|
|
||||||
|
if saturation > 0.8 then
|
||||||
|
outputRate = generationRate * 1.1 * tempFactor
|
||||||
|
if reason == "" then reason = "high saturation (110%)" end
|
||||||
|
elseif reason == "" then
|
||||||
|
reason = "normal operation"
|
||||||
|
end
|
||||||
|
|
||||||
|
result = math.max(0, math.floor(outputRate))
|
||||||
end
|
end
|
||||||
|
|
||||||
if state == STATES.COOLING then
|
if generationRate > 0 then
|
||||||
-- During cooling, output less than we generate to build saturation
|
print("[OUTPUT] " .. formatNumber(result) .. " RF/t (" .. reason .. ")")
|
||||||
return math.floor(generationRate * 0.5)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if state == STATES.CHARGING or state == STATES.WARMING_UP then
|
return result
|
||||||
-- During warmup, output slightly less than generation
|
|
||||||
return math.floor(generationRate * 0.8)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Normal operation: output slightly more than generation to keep temp rising slowly
|
|
||||||
-- But cap it if temperature is getting high
|
|
||||||
local tempFactor = 1.0
|
|
||||||
if temp > CONFIG.critical_temperature then
|
|
||||||
-- Reduce output as we approach max temp
|
|
||||||
local overTemp = temp - CONFIG.critical_temperature
|
|
||||||
local tempRange = CONFIG.max_temperature - CONFIG.critical_temperature
|
|
||||||
tempFactor = 1.0 - (overTemp / tempRange) * 0.5
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Output rate based on generation and saturation
|
|
||||||
local outputRate = generationRate * tempFactor
|
|
||||||
|
|
||||||
-- If saturation is high, we can output more
|
|
||||||
if saturation > 0.8 then
|
|
||||||
outputRate = generationRate * 1.1 * tempFactor
|
|
||||||
end
|
|
||||||
|
|
||||||
return math.max(0, math.floor(outputRate))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
-- STATE MACHINE LOGIC
|
-- STATE MACHINE LOGIC
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
|
|
||||||
|
local lastState = nil
|
||||||
|
|
||||||
|
local function setState(newState, reason)
|
||||||
|
if state ~= newState then
|
||||||
|
print("[STATE] " .. state .. " -> " .. newState .. " (" .. reason .. ")")
|
||||||
|
state = newState
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function processStateMachine()
|
local function processStateMachine()
|
||||||
if not reactorInfo or not reactorInfo.status then
|
if not reactorInfo or not reactorInfo.status then
|
||||||
-- SAFETY: Can't read reactor, go to emergency to maintain field
|
-- SAFETY: Can't read reactor, go to emergency to maintain field
|
||||||
if state ~= STATES.OFFLINE and state ~= STATES.ERROR then
|
if state ~= STATES.OFFLINE and state ~= STATES.ERROR then
|
||||||
state = STATES.EMERGENCY
|
setState(STATES.EMERGENCY, "cannot read reactor data")
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -429,15 +454,16 @@ local function processStateMachine()
|
|||||||
|
|
||||||
local fieldStrength = (reactorInfo.fieldStrength or 0) / maxField
|
local fieldStrength = (reactorInfo.fieldStrength or 0) / maxField
|
||||||
local saturation = (reactorInfo.energySaturation or 0) / maxSat
|
local saturation = (reactorInfo.energySaturation or 0) / maxSat
|
||||||
|
local fieldPct = string.format("%.1f%%", fieldStrength * 100)
|
||||||
|
|
||||||
-- Check for emergency conditions first (always)
|
-- Check for emergency conditions first (always)
|
||||||
if reactorStatus ~= "cold" and reactorStatus ~= "cooling" then
|
if reactorStatus ~= "cold" and reactorStatus ~= "cooling" then
|
||||||
if fieldStrength < CONFIG.min_field_strength then
|
if fieldStrength < CONFIG.min_field_strength then
|
||||||
state = STATES.EMERGENCY
|
setState(STATES.EMERGENCY, "field " .. fieldPct .. " below minimum " .. formatPercent(CONFIG.min_field_strength))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if temp > CONFIG.max_temperature then
|
if temp > CONFIG.max_temperature then
|
||||||
state = STATES.EMERGENCY
|
setState(STATES.EMERGENCY, "temp " .. formatTemp(temp) .. " exceeds max " .. formatTemp(CONFIG.max_temperature))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -445,26 +471,25 @@ local function processStateMachine()
|
|||||||
-- Check for shutdown request
|
-- Check for shutdown request
|
||||||
if shutdownRequested then
|
if shutdownRequested then
|
||||||
if reactorStatus == "cold" or reactorStatus == "cooling" then
|
if reactorStatus == "cold" or reactorStatus == "cooling" then
|
||||||
state = STATES.SHUTDOWN
|
setState(STATES.SHUTDOWN, "shutdown requested, reactor cooling")
|
||||||
shutdownRequested = false
|
shutdownRequested = false
|
||||||
elseif state ~= STATES.EMERGENCY then
|
elseif state ~= STATES.EMERGENCY then
|
||||||
state = STATES.SHUTDOWN
|
setState(STATES.SHUTDOWN, "shutdown requested")
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- State transitions based on reactor status
|
-- State transitions based on reactor status
|
||||||
if reactorStatus == "cold" or reactorStatus == "invalid" then
|
if reactorStatus == "cold" or reactorStatus == "invalid" then
|
||||||
state = STATES.OFFLINE
|
setState(STATES.OFFLINE, "reactor status: " .. reactorStatus)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Clear charge request flag once field is sufficiently charged
|
-- Clear charge request flag once field is sufficiently charged
|
||||||
if chargeRequested then
|
if chargeRequested then
|
||||||
local fieldPercent = fieldStrength -- Already calculated above as ratio
|
if fieldStrength >= CONFIG.charge_field_target then
|
||||||
if fieldPercent >= CONFIG.charge_field_target then
|
|
||||||
chargeRequested = false
|
chargeRequested = false
|
||||||
print("[INFO] Field charged to " .. string.format("%.1f%%", fieldPercent * 100) .. ", charge request cleared")
|
print("[INFO] Field charged to " .. fieldPct .. ", charge request cleared")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -473,33 +498,33 @@ local function processStateMachine()
|
|||||||
-- Keep current state during cooldown
|
-- Keep current state during cooldown
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
state = STATES.COOLING
|
setState(STATES.COOLING, "reactor cooling down")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if reactorStatus == "warming_up" then
|
if reactorStatus == "warming_up" then
|
||||||
-- Use 0.9 multiplier for hysteresis (consistent with RUNNING state)
|
-- Use 0.9 multiplier for hysteresis (consistent with RUNNING state)
|
||||||
if fieldStrength < CONFIG.charge_field_target * 0.9 then
|
if fieldStrength < CONFIG.charge_field_target * 0.9 then
|
||||||
state = STATES.CHARGING
|
setState(STATES.CHARGING, "field " .. fieldPct .. " below charge target")
|
||||||
else
|
else
|
||||||
state = STATES.WARMING_UP
|
setState(STATES.WARMING_UP, "field " .. fieldPct .. " sufficient, warming up")
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if reactorStatus == "running" then
|
if reactorStatus == "running" then
|
||||||
if fieldStrength < CONFIG.charge_field_target * 0.9 then
|
if fieldStrength < CONFIG.charge_field_target * 0.9 then
|
||||||
state = STATES.CHARGING
|
setState(STATES.CHARGING, "field " .. fieldPct .. " dropped below threshold while running")
|
||||||
elseif temp > CONFIG.critical_temperature then
|
elseif temp > CONFIG.critical_temperature then
|
||||||
state = STATES.COOLING
|
setState(STATES.COOLING, "temp " .. formatTemp(temp) .. " above critical " .. formatTemp(CONFIG.critical_temperature))
|
||||||
else
|
else
|
||||||
state = STATES.RUNNING
|
setState(STATES.RUNNING, "normal operation")
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if reactorStatus == "stopping" then
|
if reactorStatus == "stopping" then
|
||||||
state = STATES.SHUTDOWN
|
setState(STATES.SHUTDOWN, "reactor stopping")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -602,7 +627,7 @@ local function controlReactor()
|
|||||||
-- User requested charge - provide input flux to start charging the field
|
-- User requested charge - provide input flux to start charging the field
|
||||||
inputRate = CONFIG.emergency_field_input
|
inputRate = CONFIG.emergency_field_input
|
||||||
outputRate = 0
|
outputRate = 0
|
||||||
print("[DEBUG] OFFLINE+chargeRequested: inputRate=" .. inputRate)
|
print("[CHARGE] Providing " .. formatNumber(inputRate) .. " RF/t to charge field")
|
||||||
else
|
else
|
||||||
-- No action needed
|
-- No action needed
|
||||||
inputRate = 0
|
inputRate = 0
|
||||||
@ -623,7 +648,6 @@ local function controlReactor()
|
|||||||
lastInputRate = inputRate
|
lastInputRate = inputRate
|
||||||
lastOutputRate = outputRate
|
lastOutputRate = outputRate
|
||||||
|
|
||||||
print("[DEBUG] Setting flux gates: input=" .. inputRate .. " output=" .. outputRate)
|
|
||||||
local inputSuccess = pcall(function()
|
local inputSuccess = pcall(function()
|
||||||
inputGate.setFlowOverride(math.floor(inputRate))
|
inputGate.setFlowOverride(math.floor(inputRate))
|
||||||
end)
|
end)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user