SDRC

                Never    
Lua
       
-- EterniaLogic (DreadEnd - IGN)
-- Draconic Reactor Control Script
-- http://imgur.com/a/BPPKN

-----------
-- The Field input value should be 30% of the power provied
-- Capacitors are used to help guage when the power storage is full
-- The inflow flux gate can also be modem networked together with the computer
--
-----------

-- ReS - Reactor Stabilizer
-- "+" - Cryo-stabilized fluxduct
-- CPU - Computer
-- FxG - Flux Gate
-- ___ - Air
-- CAP - Basic Capacitor (The smaller the total value, the better)

-- ==Level 1==
-- ReS +
-- CPU FxG
-- ___ +

-- ==Level 2==
-- ___ CAP
-- CAP CAP
-- ___ CAP

wantedField=50000000 					-- Force the field value to this approximate value

FluxMODEMVALUE = 104
ValueChange = 10000 -- Change on the Flux Gate over time (Not exact, temperature and saturation divide this)
MinEnergySat = 1000000 -- Minimum energy saturation level
WantedRFt = 1200000
totalFuel = 10368   -- Fully upgraded reactor

CapacitorNum = 5 							-- 5 Capacitors on top of computer
CapacitorVal = 1000000 					-- Power holding capacity of the capacitors


FIRavg = {} 	-- last FIR to go     [Flux Input Rate]
FIRLen = 20 	-- length of averages
FIRi = 0 		-- location to do running average
FIRVal = 200000 -- initial value for FIR
FIRChg = false  -- has an up-down happened?
FIRLow = 0
FIRHigh = 0
FIRLastDelta = 999999

for i=0, FIRLen-1 do
	FIRavg[i] = FIRVal
end

-----------
function init()
	inflowFluxGate = peripheral.wrap("bottom")
	if inflowFluxGate ~= nil then
		inflowFluxGate.open(1)
		print("|# Input fluxgate:      "..inflowFluxGate.callRemote("flux_gate_"..FluxMODEMVALUE,"getSignalLowFlow"))
	end


	
	maxFieldCharge = totalFuel * 96.45061728395062 * 100
	maxEnergySaturation = (totalFuel * 96.45061728395062 * 1000)

	-- Capacitor on top
	CapacitorMax = CapacitorVal*CapacitorNum 	-- Power holding capacity of the capacitors



	capacitor_1 = peripheral.wrap("left")
	tbl = peripheral.call("top","getReactorInfo")
	FluxGateStatus = peripheral.call("back", "getSignalLowFlow")

	for k, v in pairs (tbl) do
		--print(k,v)
		if k == "temperature" then -- Weise bestimmte programmrelevante Parameter einzelnen Variablen zu
			temperatur = v
		end
		if k == "energySaturation" then
			energysat = v
		end
		if k == "fieldStrength" then
			feldst = v
		end
		if k == "generationRate" then
			RFpt = v
		end
		if k == "fuelConversion" then
			RestKraftstoff = v
		end
		if k == "fuelConversionRate" then
			Kraftstoffverbrauch = v
		end
	end
	energieladung = energysat * 0.0000001
	fieldstr = feldst * 0.000001
	kRFpt = RFpt / 1000
	fuel = RestKraftstoff / 10368
	FuelConv = fuel * 100
	--------------------------------------------------
	print("|# Reactor temperature: "..math.ceil(temperatur))
	print("|# Energy saturation %: "..math.ceil(energieladung))
	print("|# Field strength %:    "..math.ceil(fieldstr))
	print("|# Refuel level %:      "..math.ceil(FuelConv))
	--print("|# ConvesionRate:     "..math.ceil(Kraftstoffverbrauch))
	print("|# Energyproduction:    "..math.ceil(kRFpt).." kRF/t")
	-------------------------------------------------
end

function doFIRavg()
	local val=0
	for i=0, FIRLen-1 do
		val = val+FIRavg[i]
	end
	return val/FIRLen
end

function calcFieldDrain()
		if FIRi >= FIRLen then
			FIRi = 0
		else
			FIRi = FIRi+1
		end
		
		FIRavg[FIRi]=feldst
		local avg = doFIRavg()
		--print(avg.." "..wantedField)
		local difference = math.abs(avg-wantedField)
		
		--local valuedelta = math.pow(avg-wantedField, 2)/(300*avg)
		
		local height = 40000
		
		local Offset = 78540000
		local valuedelta = math.sin((avg-(wantedField+Offset))/(50000000))*height+height
		if(valuedelta < 0) then 
			valuedelta = 1
			--print("Neg at: "..avg)
		end
		
		--print("TTT: "..valuedelta)
		
		
		if (avg > wantedField) then
			if FIRVal-valuedelta < 10000 then
				FIRVal = 10000
			else
				FIRVal = FIRVal-valuedelta
			end
			if(FIRChg) then
				FIRChg = false
				FIRHigh = FIRVal
				
				-- Predict middle
				--FIRVal = (FIRHigh+FIRLow)/2
			end
		else 
			if (avg < wantedField) then
				if FIRVal+valuedelta > (900000-valuedelta) then
					FIRVal = 900000
				else
					FIRVal = FIRVal+valuedelta
				end
			end
			if(not FIRChg) then
				FIRChg = true
				FIRLow = FIRVal
				
				-- Predict middle
				--FIRVal = (FIRHigh+FIRLow)/2
			end
			
		end
		
		--print("Low: "..FIRLow)
		--print("High: "..FIRHigh)
		--print("Delta: "..math.abs(FIRHigh-FIRLow))
		
		fluxval = FIRVal
		print("|#== FluxInputRate:     "..math.floor(fluxval).." kRF/t")
end
	

-- Set the shield input level
function setLowLevel()
	if inflowFluxGate ~= nil then
		calcFieldDrain()
		inflowFluxGate.callRemote("flux_gate_"..FluxMODEMVALUE,"setSignalLowFlow",fluxval)
	end
end


function setLevel(level)
	print("|#== FluxGate set to:   "..math.ceil(FluxGateStatus).." kRF/t")
	peripheral.call("back", "setSignalLowFlow", FluxGateStatus)
	
end


function limitLevel(FluxStatus)
	-- Set the maximum value
	if FluxGateStatus >= (WantedRFt*0.9-FluxGateStatus*0.3) then 
		FluxGateStatus = (WantedRFt*0.9-FluxGateStatus*0.3)
	end
end


-- Start the reactor
function startReactor()
	peripheral.call("top", "chargeReactor")
		print("|#==        Reactor charge !!        ==#|")
	if feldst >= 50000000 then
		peripheral.call("top", "activateReactor")
			print("|#==        Reactor activate !       ==#|")
	end
end


function testFieldStrength()
	if feldst <= 15000000 then
		peripheral.call("top", "stopReactor")
		print("|#==     Reactor Emergency stop !    ==#|")
		print("|#==     Field strength too low !     ==#|")
	else
		if feldst >= 20000000 then
			peripheral.call("top", "activateReactor")
			--print("|#==         Reactor active !        ==#|")
		end
	end
end


function calcNewValueChange()
	local chg = ValueChange
	local saturationchg = (energieladung/100)-0.3
	local reactorTempx = 1-((temperatur-3000)/10000+0.2) -- reactor temperature accounting for +3000 heat
	
	print("|# Temperature Factor:  "..reactorTempx)
	print("|# Saturation Factor:   "..saturationchg)
	chg = chg*math.min(saturationchg,reactorTempx) -- Account for saturation and Temperature
	
	return chg
end


function testCapacitor()
	-- Slow down the reactor to 1/8 of the requested power level
	-- This is so that a slow-start is not required for later use
	if capacitor_1 ~= nil then
		local energyStored = capacitor_1.getEnergyStored()
		if energyStored >= CapacitorMax then
			FluxGateStatus = WantedRFt/8
			setLevel(FluxGateStatus)
		end
	end
end


-- Run this program!
function doRun()
	if temperatur > 7777 then -- Temperatur check wenn mehr als 7777 Grad
		FluxGateStatus = 200000
	end


	-- Set the energy level to be produced
	if energysat > MinEnergySat then 
		limitLevel(FluxGateStatus)
		FluxGateStatus = RFpt + calcNewValueChange() -- anpassen der Flux-Gate_Variablen an den neuen Wert
		setLevel(FluxGateStatus)
	end




	-- Energy Saturation settings
	--if energysat < MinEnergySat then
	--	if FluxGateStatus <= 10000 then -- Minimalwert abregelung auf 0
	--		FluxGateStatus = 10000
	--	end
	--	FluxGateStatus = FluxGateStatus - ValueChange -- anpassen der Flux-Gate_Variablen an den neuen Wert
	--  setLevel(FluxGateStatus)
	--end



	-- Stop the reactor when 90% of the fuel is gone
	if FuelConv >= 90 then 
		peripheral.call("top", "stopReactor")

		print("|#==      Reactor refuel stop !      ==#|")
		print("|#============#| S D R C |#============#|")
		sleep(300)
	end

	if temperatur <= 2000 then -- Starttest zum aufladen des Reaktors
		startReactor()
	else
		testFieldStrength()
	end

	setLowLevel(level)
	testCapacitor()
end

while true do
	term.clear()
	term.setCursorPos(1,1)
	init()
	doRun()
	sleep(0.06)
end