-------------------------------------------------------------------------------- -- 81-718 traction controller -------------------------------------------------------------------------------- -- Copyright (C) 2013-2018 Metrostroi Team & FoxWorks Aerospace s.r.o. -- Contains proprietary code. See license.txt for additional information. -------------------------------------------------------------------------------- Metrostroi.DefineSystem("81_718_PTTI") function TRAIN_SYSTEM:Initialize() self.State = 0 self.PTTIState = 0 self.Zero = false self.FreqStart = nil self.FreqState = 0 self.FreqBlock = 0 self.T = 0 self.RN = 0 self.RNState = 0 self.RNResistance = 1e9 self.RVState = 0.0 self.BlockRV = false self.RVResistance = 1e9 self.SubIterations = 16 end function TRAIN_SYSTEM:Inputs() return { } end function TRAIN_SYSTEM:Outputs() return { "State","RN","RNState","RN","RNState","FreqState" } end function TRAIN_SYSTEM:TriggerInput(name,value) end function TRAIN_SYSTEM:Think(dT,iter) local Train = self.Train local BUV = Train.BUV local T = math.abs(BUV.ISet or 0) local I = math.abs(Train.Electric.I13 + Train.Electric.I24)/2 if self.State ~= BUV.PTTIState then --self.PTTIState = BUV.PTTIState or 0 if self.State ~= 0 then self.State = 0 else self.State = BUV.PTTIState or 0 end end if self.State ~= 0 and T == 0 and not self.Zero and math.abs(I) < 25 then self.Zero = true self.State = 0 end if self.State == 0 then self.Zero = false self.RN = 0 self.RV = false self.RNState = 0 self.RVState = 0 self.FreqStart = nil self.FreqState = 0 self.RNBrakeReset = false self.T = 0 self.PrepareElectric = false end if self.State == 1 then if not self.RV and self.RN == 0 then self.RN = 1 self.RV = false self.RNState = 0 self.RVState = 0 self.FreqState = 0 self.FreqStart = nil end ---[[ if BUV.FreqBlock == 0 and not self.FreqStart then self.FreqStart = CurTime() end if BUV.FreqBlock > 0 and T > 0 then self.FreqState = 1/3 self.FreqStart = CurTime() T = 100 elseif T > 0 and self.FreqStart and self.FreqStart ~= true then self.FreqState = 1/3+(math.max(0,math.floor((CurTime()-self.FreqStart)/2*12)/12))*(2/3) --print(math.floor((CurTime()-self.FreqStart)/1.5*12)) --self.FreqState = 1/3+math.max(0,(CurTime()-self.FreqStart)*1*(2/3))--math.max(0,math.floor((CurTime()-self.FreqStart)*1.5*8)/8)*(2/3) T = self.FreqState*T end if self.FreqState > 1 and self.FreqStart then self.FreqStart = true self.FreqState = 1 end--]] end if self.State == -1 then if self.PrepareElectric and (CurTime()-self.PrepareElectric > 0.8 or I > T*0.8) then --self.RVState = 0.01 self.RN = self.RVState == 1 and 1 or 0 self.RV = self.RVState < 1 if self.RN == 0 then --self.RNBrakeReset = true self.RNState = 0 end self.PrepareElectric = false end --[[ if self.RNState == 0 or self.RN > 0 then self.RNBrakeReset = false end if self.RNBrakeReset then self.RNState = math.max(0,math.min(1,self.RNState-0.3*dT)) end--]] --[[ if not self.RV and self.RN == 0 or self.PrepareElectric then self.RN = 0 self.RV = false self.RNState = 0.93-(math.max(0,math.min(1,(Train.Engines.Speed-18)/60))^0.6)*0.85 self.RVState = 1-math.max(0,math.min(1,((Train.Engines.Speed-50)/32))^0.8)*0.75 if not self.PrepareElectric then self.PrepareElectric = CurTime() end end--]] if not self.RV and self.RN == 0 and not self.PrepareElectric then self.RN = 0 self.RV = false self.RNState = 0.93-(math.max(0,math.min(1,(Train.Engines.Speed-18)/60))^0.6)*0.85 self.RVState = 1-(math.max(0,math.min(1,(Train.Engines.Speed-50)/32))^0.8)*0.75 self.PrepareElectric = CurTime() end end if (self.RN > 0 or self.RV) and self.SpeedUp and I > T*0.8 then self.SpeedUp = false end --if self.RN == 0 and not self.RV and not self.SpeedUp then self.SpeedUp = true end if T < self.T then self.T = self.T+(T*(0.95+math.random()*0.1)-self.T)*dT*4--6 else self.T = self.T+(T*(0.95+math.random()*0.1)-self.T)*dT*1.5--3 end self:SolveRV(Train,self.T,dT,I,self.State < 0,self.State == 1 and Train.BUV.BlockRV) self:SolveRN(Train,self.T,dT,I,self.State < 0,self.State == 1 and T <= 150) end function TRAIN_SYSTEM:SolveRN(Train,T,dT,I,brake,start) -- General state local Active = self.RN > 0--and T > 0 --local I = math.abs(Train.Electric.I13 + Train.Electric.I24)/2 self.RNPrevCurrent = Current local rnd = 30+math.random()*20 if self.SpeedUp then rnd = brake and 25+((Train.Engines.Speed/80)^4)*100 or 25 --print(rnd) end -- Update RN controller signal if Active then local sign = brake and 1 or 1 -- Generate control signal local dC = math.min(math.abs(T-I),300) if T == 0 then self.RNState = math.max(0,self.RNState-5*dT*sign) elseif I > T then self.RNState = math.max(0,math.min(start and 0.1 or 1,self.RNState-dC*1/rnd*dT*sign)) else self.RNState = math.max(0,math.min(start and 0.1 or 1,self.RNState+dC*1/rnd*dT*sign)) end if (not brake and self.RNState == 1 or brake and self.RNState == 0) and self.RN > 0 and not self.RV then self.RV = true self.RN = 0 self.RVState = brake and 0.99 or 0.01 end end end function TRAIN_SYSTEM:SolveRV(Train,T,dT,I,brake,block) -- General state local Active = self.RV and (not block or self.RVState > 0) --local I = math.abs(Train.Electric.I13 + Train.Electric.I24)/2 self.RNPrevCurrent = Current -- Controllers resistance local Resistance = 0.036 local speedMul = math.max(0,math.min(1,(Train.Engines.Speed-40)/40)) local rnd = 30+math.random()*(20) if self.SpeedUp then rnd = brake and 25+((Train.Engines.Speed/80)^4)*100 or 25 end -- Update RV controller signal if Active then local sign = brake and -1 or 1 -- Generate control signal local dC = math.min(math.max(math.abs(T-I),1, 300)) if not self.PrepareElectric then if T == 0 or block then self.RVState = math.max(0,self.RVState-5*dT*sign) elseif brake and I T then self.RVState = math.max(0,math.min(1,self.RVState-dC*1/rnd*dT*sign)) else self.RVState = math.max(0,math.min(1,self.RVState+dC*1/rnd*dT*sign)) end end -- Generate resistance local keypoints = { 0.10,0.008, 0.20,0.018, 0.30,0.030, 0.40,0.047, 0.50,0.070, 0.60,0.105, 0.70,0.165, 0.80,0.280, 0.90,0.650, 1.00,15.00, } local TargetField if self.State < 0 then TargetField = 0.4 + 0.6*self.RVState else TargetField = 0.4 + 0.6*(1-self.RVState) end --TargetField = 0.4 + 0.6*(1-self.RVState) local Found = false for i=1,#keypoints/2 do local X1,Y1 = keypoints[(i-1)*2+1],keypoints[(i-1)*2+2] local X2,Y2 = keypoints[(i)*2+1],keypoints[(i)*2+2] if (not Found) and (not X2) then Resistance = Y1 Found = true elseif (TargetField >= X1) and (TargetField < X2) then local T = (TargetField-X1)/(X2-X1) Resistance = Y1 + (Y2-Y1)*T Found = true end if (self.State > 0 and self.RVState == 0 or self.State < 0 and self.RVState == 1) and self.RV and self.RN == 0 then self.RV = false self.RN = 1 self.RNState = brake and 0.01 or 0.99 end end end -- Set resistance self.RVResistance = Resistance + 1e9 * (Active and 0 or 1) end