|
|
||||||
|
|
luafaudes Tutorial: 5_faulttolerant.luaTo run the below Lua script, cd to the tutorial section of the respective plug-in and enter luafaudes 5_faulttolerant.lua at the command prompt. The script will read input data from ./tutorial/data/. -- Demo for implementing synthesis algorithms in luafaudes, tmoor, 20110315 -- This luafaudes script makes use of state- and transition-iterators -- to implement a merge operation that combines a nominal and a degraded specification. -- The resulting fault-accommodating specification is meant to insist in the nominal specification -- only until a failure event occurs. After the ocurance of the failure event, the system -- needs to satisfy an alternative specification (so called degraded specification). Using a -- fault-accommodating specification for a standard supervisor design procedure is meant -- to result in a fault-tolerant controller. -- Note. This really is just a demo script and must not be confused with the -- general discussion given in "Fault-Tolerant Control of Discrete Event Systems based -- on Fault-Accommodating Models" by Wittmann/Richter/Moor, accepted for presentation at -- Safeprocess 2012. -- Say hello print([[ This demo script implements the function FtcSpecification to support a naive variant of fault-tolerant control. As a test case, the script runs an extended version of the very-simple-machine scenario, where the second machine may fail to process a workpiece. Input data is embedded with the script, incl some more comments. For graphical representations of input data and results see the files "tmp_ftc_*,png". ]]) -- ------------------------------------------------------------------------------- -- ------------------------------------------------------------------------------- -- ------------------------------------------------------------------------------- -- Tolerant specification synthesis function faudes.FtcSpecification(En,Ef,SigmaF,Et) -- Parameters -- En: nominal specification -- Ef: degraded specification -- SigmaF: set of failure events -- Et: fault-tolerant specification (return value) -- Declare variables local to this function local Enf, evf local pcmap, sit, tit local tr, qf, qn, sname, nname, fx, nx, qfnext -- Test input data consistency -- -- The current implementation assumes SigmaF to hold exactly one failure event. if SigmaF:Size()~= 1 then faudes.Error("FtcSpecification(): Error: SigmaF must consist of one failure event") end evf=SigmaF:Begin():Index() -- Relate states between En and Ef -- -- Technically, we apply a procduct composition Enf = En x Ef to realize the -- intersection L(En) ^ L(Ef) and use the composition map to relate states. Enf=faudes.Generator() pcmap=faudes.ProductCompositionMap() faudes.Product(En,Ef,pcmap,Enf) -- Union construct to merge Enf, En and Ef. -- -- At this stage, only Enf contributes to the initial states and neither -- En nor Ef are reachable. The construct uses consecutive states with offset nx -- for En-states and fx for Ef-states. A future version of libFAUDES may provide -- a UnionCompositionMap with similar semantics as the ProductCompositionMap. Et:Assign(Enf) -- (tech. note: must use "Assign" for "return by reference") Et:InsEvents(SigmaF) nx=Et:MaxStateIndex()+1 sit=En:StatesBegin() while sit~=En:StatesEnd() do Et:InsState(sit:Index() + nx) if En:ExistsMarkedState(sit:Index()) then Et:SetMarkedState(sit:Index() + nx) end sit:Inc() end tit=En:TransRelBegin() while tit~=En:TransRelEnd() do tr=tit:Transition(); Et:SetTransition(tr.X1+nx,tr.Ev,tr.X2+nx) tit:Inc() end fx=Et:MaxStateIndex()+1 sit=Ef:StatesBegin() while sit~=Ef:StatesEnd() do Et:InsState(sit:Index() + fx) if Ef:ExistsMarkedState(sit:Index()) then Et:SetMarkedState(sit:Index() + fx) end sit:Inc() end tit=Ef:TransRelBegin() while tit~=Ef:TransRelEnd() do tr=tit:Transition(); Et:SetTransition(tr.X1+fx,tr.Ev,tr.X2+fx) tit:Inc() end -- Have nice state names -- -- State names are purely cosmetic but essential for debugging/development if Et:StateNamesEnabled() and En:StateNamesEnabled() and Et:StateNamesEnabled() then Et:ClearStateNames() sit=Enf:StatesBegin() while sit~= Enf:StatesEnd() do qn=pcmap:Arg1State(sit:Index()) nname = En:StateName(qn) if nname == "" then nname = qn end sname = Et:UniqueStateName("NF_" .. nname) Et:StateName(qn,sname) sit:Inc() end sit=En:StatesBegin() while sit~=En:StatesEnd() do nname = En:StateName(sit:Index()) if nname == "" then nname = sit:Index() end sname = Et:UniqueStateName("NF_" .. nname) Et:StateName(sit:Index() + nx, sname) sit:Inc() end sit=Ef:StatesBegin() while sit~=Ef:StatesEnd() do nname = Ef:StateName(sit:Index()) if nname == "" then nname = sit:Index() end sname = Et:UniqueStateName("F_" .. sname) Et:StateName(sit:Index() + fx, sname) sit:Inc() end end -- Link Enf with Ef by failure-event transitions -- -- Iterate over all Enf-states, and test whether in the corresponding -- Ef-state a failure-event transition is enabled. If so, introduce a transion -- from the Enf-state to the corresponding Ef-state. sit=Enf:StatesBegin() while sit~= Enf:StatesEnd() do qf=pcmap:Arg2State(sit:Index()) qfnext=Ef:SuccessorState(qf,evf) if qfnext~=0 then Et:SetTransition(sit:Index(),evf,qfnext+fx) end sit:Inc() end -- Link Enf with En whenever Enf restricts En -- -- Iterate over all Enf-states, and test whether in the corresponding -- En-state an event is enabled which is disabled in Enf. If so, introduce a transtion -- from the Enf-state to the target En-state. sit=Enf:StatesBegin() while sit~= Enf:StatesEnd() do qn=pcmap:Arg1State(sit:Index()) tit=En:TransRelBegin(qn) while tit~= En:TransRelEnd(qn) do if tit:Transition().Ev ~= evf then if Enf:SuccessorState(sit:Index(),tit:Transition().Ev) == 0 then Et:SetTransition(sit:Index(),tit:Transition().Ev,tit:Transition().X2+nx) end end tit:Inc() end sit:Inc() end -- Remove unreachable artifacts Et:Accessible() -- Name return Et:Name("FtcSpecification(" .. En:Name() .. ", " .. Ef:Name() .. ")") end -- ------------------------------------------------------------------------------- -- ------------------------------------------------------------------------------- -- ------------------------------------------------------------------------------- -- Test scenario input data -- Report print("###################################################") print("### prepare input data") -- ------------------------------------------------------------------------------- -- Input data: plant component 1, nominal G1n=faudes.System() G1n:FromString([[ <Generator> "M1nominal" % Std "very simple machine" with events % alpha1: start process % beta1: process complete <Alphabet> alpha1 +C+ beta1 </Alphabet> <States> I B </States> <TransRel> I alpha1 B B beta1 I </TransRel> <InitStates> I </InitStates> <MarkedStates> I </MarkedStates> </Generator> ]]) -- ------------------------------------------------------------------------------- -- Input data: plant component 2, nominal G2n=faudes.System() G2n:FromString([[ <Generator> "M2nominal" % Extended "very simple machine", can run in "fast mode" % or "thorough mode". Mode selection is considered % controllable, while the "process start" event % alpha2 is uncontrollable. Hence, a supervisor must only enable % mode selection when a work piece is available. % gamma2: prepare to run process in "fast mode" % rho2: prepare to run process in "thorough mode" % alpha2: process start % beta2: process complete <Alphabet> alpha2 beta2 gamma2 +C+ rho2 +C+ </Alphabet> <States> I Sf St B </States> <TransRel> I gamma2 Sf I rho2 St Sf alpha2 B St alpha2 B B beta2 I </TransRel> <InitStates> I </InitStates> <MarkedStates> I </MarkedStates> </Generator> ]]) -- ------------------------------------------------------------------------------- -- Input data: nominal specification En=faudes.Generator() En:FromString([[ <Generator> "nominal specification" % The nominal specification models the constraints imposed % by a capacity-1 buffer placed between the two machines. % Since "thorough mode" is considered more expensive, % the nominal specification requires machine2 to run % in "fast mode" exclusively % % Technial note: we only enable mode selection of % M2 when the buffer is full; this reduces the state % count of the supervisors and makes them more easy % to inspect. <Alphabet> beta1 alpha2 gamma2 rho2</Alphabet> <States> E F </States> <TransRel> E beta1 F F alpha2 E F gamma2 F </TransRel> <InitStates> E </InitStates> <MarkedStates> E </MarkedStates> </Generator> ]]) -- ------------------------------------------------------------------------------- -- Input data: plant component 2, degraded G2f=faudes.System() G2f:FromString([[ <Generator> "M2degraded" % This varaint of M2 introduces the unobservable failure event "fault" % which can occur when choosing "fast mode". Thus, the degraded M2 % may fail to process a work piece in "fast mode", but it allways % succeeds in "thorough mode". Events % fault: machine break down in "fast mode" % *: as in M2nominal <Alphabet> alpha2 +C+ beta2 gamma2 +C+ rho2 +C+ fault +o+ </Alphabet> <States> I Sf St B </States> <TransRel> I gamma2 Sf I rho2 St Sf alpha2 B Sf fault I St alpha2 B B beta2 I </TransRel> <InitStates> I </InitStates> <MarkedStates> I </MarkedStates> </Generator> ]]) -- ------------------------------------------------------------------------------- -- Input data: degraded specification Ef=faudes.Generator() Ef:FromString([[ <Generator> "degraded specification" <Alphabet> beta1 alpha2 gamma2 rho2</Alphabet> % In contrast to the nominal specification, the degraded % case allows both "fast mode" and "thorough mode". Thus, % the generated fault tolerant specification will insist in % "fast mode" until a fault occurs, and then allow both modes. <States> E F </States> <TransRel> E beta1 F F alpha2 E F gamma2 F F rho2 F </TransRel> <InitStates> E </InitStates> <MarkedStates> E </MarkedStates> </Generator> ]]) -- ------------------------------------------------------------------------------- -- ------------------------------------------------------------------------------- -- ------------------------------------------------------------------------------- -- Test scenario synthesis -- Report print("###################################################") print("### compose components Gn and Gf") -- Nominal plant Gn = G1n:Copy(); faudes.Parallel(Gn,G2n,Gn); -- Faulty plant Gf = G1n:Copy(); faudes.Parallel(Gf,G2f,Gf); -- SigmaF SigmaF = faudes.EventSet() SigmaF:Insert("fault") -- SigmaN SigmaN = Gn:Alphabet():Copy(); -- Sigma Sigma = SigmaN + SigmaF -- Normalize specification alphabets faudes.InvProject(En,SigmaN,En) faudes.InvProject(Ef,Sigma,Ef) -- Prepare prefix closed plant models clGf=Gf:Copy() faudes.PrefixClosure(clGf) clGn=Gn:Copy() faudes.PrefixClosure(clGn) -- Report print("###################################################") print("### nominal design of Kn to satisfy En") -- Nominal design Kn=faudes.Generator() faudes.SupConNB(Gn,En,Kn) --Kn:SWrite() -- Report print("###################################################") print("### degraded design of Kf to satisfy Ef") -- Enforce ontrollability Kf=faudes.Generator() faudes.SupConNB(Gf,Ef,Kf) --Kf:SWrite() -- Test normality clKf=Kf:Copy() faudes.PrefixClosure(clKf) isnorm=faudes.IsNormal(clGf,clKf) if isnorm then print("normality test: passed") else print("normality test: failed (need to implement synthesis iteration!)") end -- Report print("###################################################") print("### synthesize tolerant specification Et") -- Synthesize tolerant specification Et=faudes.Generator() faudes.FtcSpecification(En,Ef,SigmaF,Et) --Et:SWrite(); -- Report print("###################################################") print("### tolerant design of Kt to satisfy Et") -- Enforce ontrollability Kt=faudes.Generator() faudes.SupConNB(Gf,Et,Kt) --Kt:SWrite() -- Test normality clKt=Kt:Copy() faudes.PrefixClosure(clKt) isnorm=faudes.IsNormal(clGf,clKt) if isnorm then print("normality test: passed") else print("normality test: failed (need to use SupConNormNB fro synthesis)") end -- Project for supervisor implementation SigmaO=Gf:ObservableEvents() Kto=faudes.Generator() faudes.Project(Kt,SigmaO,Kto) -- Report print("###################################################") print("### generating graph output") -- For inspection G1n:GraphWrite("tmp_ftc_g1n.png") G2n:GraphWrite("tmp_ftc_g2n.png") G2f:GraphWrite("tmp_ftc_g2f.png") En:GraphWrite("tmp_ftc_en.png") Ef:GraphWrite("tmp_ftc_ef.png") Et:GraphWrite("tmp_ftc_et.png") Kt:GraphWrite("tmp_ftc_kt.png") Kn:GraphWrite("tmp_ftc_kn.png") Kf:GraphWrite("tmp_ftc_kf.png") Kto:GraphWrite("tmp_ftc_kto.png") -- ------------------------------------------------------------------------------- -- ------------------------------------------------------------------------------- -- ------------------------------------------------------------------------------- -- Compare with expected result -- Report print("###################################################") print("### validate") -- ------------------------------------------------------------------------------- -- Input data: expected result RefKt=faudes.Generator() RefKt:FromString([[ <Generator> "fault-tolerant supervisor, as of 20110210" % Statistics % % States: 15 % Init/Marked: 1/2 % Events: 7 % Transitions: 22 % StateSymbols: 15 % Attrib. E/S/T: 0/0/0 % <Alphabet> alpha1 beta1 alpha2 beta2 gamma2 rho2 fault </Alphabet> <States> I|I|N_E B|I|N_E I|I|N_F I|Sf|N_F I|B|N_E I|I|F_F I|Sf|F_F I|St|F_F I|B|F_E B|B|F_E I|I|F_E B|I|F_E I|B|F_F B|B|N_E I|B|N_F </States> <TransRel> I|I|N_E alpha1 B|I|N_E B|I|N_E beta1 I|I|N_F I|I|N_F gamma2 I|Sf|N_F I|Sf|N_F alpha2 I|B|N_E I|Sf|N_F fault I|I|F_F I|B|N_E alpha1 B|B|N_E I|B|N_E beta2 I|I|N_E I|I|F_F gamma2 I|Sf|F_F I|I|F_F rho2 I|St|F_F I|Sf|F_F alpha2 I|B|F_E I|Sf|F_F fault I|I|F_F I|St|F_F alpha2 I|B|F_E I|B|F_E alpha1 B|B|F_E I|B|F_E beta2 I|I|F_E B|B|F_E beta1 I|B|F_F B|B|F_E beta2 B|I|F_E I|I|F_E alpha1 B|I|F_E B|I|F_E beta1 I|I|F_F I|B|F_F beta2 I|I|F_F B|B|N_E beta1 I|B|N_F B|B|N_E beta2 B|I|N_E I|B|N_F beta2 I|I|N_F </TransRel> <InitStates> I|I|N_E </InitStates> <MarkedStates> I|I|N_E I|I|F_E </MarkedStates> </Generator> ]]) -- ------------------------------------------------------------------------------- lmatch=faudes.LanguageEquality(RefKt,Kt) if lmatch then print("supervisor Kt matches the expected result") else print("validation failed") end -- Done print("###################################################")
libFAUDES 2.32b --- 2024.03.01 --- with "synthesis-observer-observability-diagnosis-hiosys-iosystem-multitasking-coordinationcontrol-timed-simulator-iodevice-luabindings-hybrid-example-pybindings" |