CCCPaste

962689254477c

--[[
神龙反应堆控制器(ComputerCraft: Tweaked 版)
作者:ChatGPT
结构:双PID + 预测辅助安全限幅
依赖接口:
  reactor: activateReactor(), chargeReactor(), getReactorInfo(), stopReactor(), toggleFailSafe()
  flow_gate: getFlow(), setFlowOverride(), setOverrideEnabled(), getOverrideEnabled()
--]]

-- ===== 手动 peripheral 配置 =====
local reactor = peripheral.wrap("reactor_0")
local inGate  = peripheral.wrap("flow_gate_in")
local outGate = peripheral.wrap("flow_gate_out")
local monitor = peripheral.wrap("monitor_0") -- 可选

-- ===== 参数配置 =====
local TARGET_TEMP = 8000
local TARGET_FIELD = 0.05
local SAFETY_TEMP = 8300
local MIN_FIELD = 0.02
local CHARGE_INPUT_MAX = 64000000
local MAIN_SLEEP = 0.2
local GUI_UPDATE_INTERVAL = 0.5
local PREDICT_STEPS = 10
local ALLOW_TOUCH_START = true

-- ===== 反应堆信息封装 =====
local function info() return reactor.getReactorInfo() end
local function temp() return info().temperature or 0 end
local function field() return info().fieldStrength or 0 end
local function fieldMax() return info().maxFieldStrength or 1 end
local function energy() return info().energySaturation or 0 end
local function energyMax() return info().maxEnergySaturation or 1 end
local function genRate() return info().generationRate or 0 end
local function status() return tostring(info().status) end

-- ===== PID 控制 =====
local function newPID(kp,ki,kd)
  return {kp=kp,ki=ki,kd=kd,lastErr=0,int=0,step=function(self,target,cur,dt)
    local e=target-cur
    self.int=self.int+e*dt
    local d=(e-self.lastErr)/dt
    self.lastErr=e
    return self.kp*e+self.ki*self.int+self.kd*d
  end}
end

-- 主PID(温控基于能空率)
local pidTemp = newPID(0.5,0.02,0.3)
-- 次PID(场强维持)
local pidField = newPID(20000000,10000,0)

-- ===== 预测模块(辅助限幅) =====
local function predict(steps)
  local t=temp()
  local f=field()
  local e=energy()
  local fmax=fieldMax()
  local emax=energyMax()
  for _=1,steps do
    local erate=(1-e/emax)*99
    local trate=(t/20000)*50
    local upIndex=(erate^3)/(100-erate+1e-9)+444.7
    local upResist=(trate^4)/(100-trate+1e-9)
    local rise=(upIndex+upResist*(0.5-1))/1000+0.5
    t=t+rise
    f=f-(1-e/emax)
    e=e+(1-(e/emax))*5000
  end
  return t,f
end

-- ===== 控制函数 =====
local function setIn(v)
  if not inGate then return end
  if v<0 then v=0 end
  if v>CHARGE_INPUT_MAX then v=CHARGE_INPUT_MAX end
  inGate.setFlowOverride(v)
  inGate.setOverrideEnabled(true)
end

local function setOut(v)
  if not outGate then return end
  if v<0 then v=0 end
  if v>CHARGE_INPUT_MAX then v=CHARGE_INPUT_MAX end
  outGate.setFlowOverride(v)
  outGate.setOverrideEnabled(true)
end

-- ===== 状态机 =====
local function emergency(reason)
  print("!!! 紧急停机: "..reason)
  setOut(0)
  setIn(CHARGE_INPUT_MAX)
  reactor.stopReactor()
end

local function tryActivate()
  local fi=field()/fieldMax()
  local ei=energy()/energyMax()
  if fi>=0.5 and ei>=0.5 and temp()>=2500 then
    reactor.activateReactor()
    return true
  end
end

-- ===== GUI =====
local function draw()
  if not monitor then return end
  monitor.setTextScale(1)
  monitor.clear()
  monitor.setCursorPos(1,1)
  monitor.write("神龙反应堆控制")
  monitor.setCursorPos(1,2)
  monitor.write("状态: "..status())
  monitor.setCursorPos(1,3)
  monitor.write(string.format("温度: %.1fC",temp()))
  monitor.setCursorPos(1,4)
  monitor.write(string.format("场强: %.2f%%",(field()/fieldMax())*100))
  monitor.setCursorPos(1,5)
  monitor.write(string.format("能量: %.2f%%",(energy()/energyMax())*100))
  monitor.setCursorPos(1,7)
  monitor.write("[触摸底部启动/停止]")
end

-- ===== 主循环 =====
local manualStart, manualStop=false,false
local function monitorTouch()
  if not monitor then return end
  while true do
    local _,side,x,y=os.pullEvent("monitor_touch")
    if y>=7 then
      if status()=="running" then manualStop=true else manualStart=true end
    end
  end
end

local function main()
  local running=false
  while true do
    draw()
    local st=status()
    local T=temp()
    local fRatio=field()/fieldMax()
    local eRatio=energy()/energyMax()

    -- 安全检查
    if st=="running" and (T>=SAFETY_TEMP or fRatio=SAFETY_TEMP)
      local outAdj=pidTemp:step(TARGET_TEMP,T,MAIN_SLEEP)
      if predictedOverheat then
        outAdj=outAdj*0.2 -- 限幅抑制
      end
      local outFlow=math.max(0,math.min(CHARGE_INPUT_MAX,genRate()+outAdj*1000))
      setOut(outFlow)

      -- 次PID:控制场强维持
      local inAdj=pidField:step(TARGET_FIELD,fRatio,MAIN_SLEEP)
      if predF/fieldMax()