class FluidChamber(DynamicalModel): VFluid = F.RealVariable(causality=CS.Parameter, variability=VR.Constant, default=0.1) pInit = F.RealVariable(causality=CS.Parameter, variability=VR.Constant, default=300e5) molarMass = F.RealVariable(causality=CS.Parameter, variability=VR.Constant, default=16e-3) RGas = F.RealVariable(causality=CS.Parameter, variability=VR.Constant) T = F.RealState(start=300) rho = F.RealState(start=1) p = F.RealVariable(causality=CS.Output) m = F.RealVariable(causality=CS.Output) QDotWall = F.RealVariable(causality=CS.Input) portWall = F.Port([p, T, QDotWall]) def initialize(self): self.RGas = 8.13 / self.molarMass self.rho = self.pInit / (self.RGas * self.rho * self.T) @F.Function(inputs=[T, rho], outputs=[p]) def setState(self, t): self.p = self.RGas * self.rho * self.T def compute(self, t): self.m = self.VFluid * self.rho self.der.rho = 0 self.der.T = self.QDotWall / self.m / (5. / 2 * self.RGas)
class ForceSource(DynamicalModel): f = F.RealVariable(causality=CS.Output, variability=VR.Constant, default=-10.) x = F.RealVariable(causality=CS.Input) v = F.RealVariable(causality=CS.Input) p = F.Port([f, v, x])
class FlowController(DynamicalModel): waterLevel = F.RealVariable(causality=CS.Input) valveOpen = F.RealVariable(causality=CS.Output, default=1) def detectLevelEvent(self): if (self.valveOpen > 0.5): return self.waterLevel - 0.35 else: return self.waterLevel - 0.5 @F.StateEvent(locate=detectLevelEvent) def onLevelEvent(self): self.valveOpen = 1 - self.valveOpen
class ThermalConduction(DynamicalModel): k = F.RealVariable(causality=CS.Parameter, variability=VR.Constant, default=1) T1 = F.RealVariable(causality=CS.Input) QDot1 = F.RealVariable(causality=CS.Output) T2 = F.RealVariable(causality=CS.Input) QDot2 = F.RealVariable(causality=CS.Output) p1 = ThermalPort('R', TVar=T1, QVar=QDot1) p2 = ThermalPort('R', TVar=T2, QVar=QDot2) def compute(self, t): self.QDot1 = self.k * (self.T2 - self.T1) self.QDot2 = -self.QDot1
class FluidSystem(DynamicalModel): source = F.SubModel(FlowSource) waterTower = F.SubModel(WaterTower) valveOut = F.SubModel(Valve) flowController = F.SubModel(FlowController) sink = F.SubModel(PressureSource) def __init__(self): self.source.meta.port.connect(self.waterTower.meta.portIn) self.waterTower.meta.portOut.connect(self.valveOut.meta.port1) self.valveOut.meta.port2.connect(self.sink.meta.port) self.waterTower.meta.hWater.connect( self.flowController.meta.waterLevel) self.flowController.meta.valveOpen.connect( self.valveOut.meta.controlSignal)
class ThermalMass(DynamicalModel): m = F.RealVariable(causality=CS.Parameter, variability=VR.Constant, default=10.) cp = F.RealVariable(causality=CS.Parameter, variability=VR.Constant, default=100.) T = F.RealState(start=300) QDot1 = F.RealVariable(causality=CS.Input) QDot2 = F.RealVariable(causality=CS.Input) p1 = ThermalPort('C', TVar=T, QVar=QDot1) p2 = ThermalPort('C', TVar=T, QVar=QDot2) def compute(self, t): self.der.T = (self.QDot1 + self.QDot2) / self.m / self.cp
class BoundMass(DynamicalModel): m = F.RealVariable(causality=CS.Parameter, variability=VR.Constant, default=10.) f = F.RealVariable(causality=CS.Input, default=10.) x = F.RealState(start=0.1) v = F.RealState(start=1.) p = F.Port([f, v, x]) def compute(self, t): self.der.x = self.v self.der.v = self.f / self.m def checkBounce(self): return self.x @F.StateEvent(locate=checkBounce) def onBounce(self): if (self.v < 0): self.v = -0.9 * self.v
class HeatSource(DynamicalModel): T = F.RealVariable(causality=CS.Input) QDot = F.RealVariable(causality=CS.Output) p = ThermalPort('R', TVar=T, QVar=QDot) isHeating = F.IntegerVariable(default=1) def compute(self, t): #self.QDot = 100 * math.sin(t / 1000) #self.QDot = 10 * (350 - self.T) self.QDot = 100 * (self.isHeating - 0.5) def checkState(self): newState = -1 if (self.isHeating == 1 and self.T > 350): newState = 1 elif (self.isHeating == 0 and self.T < 250): newState = 2 return newState @F.StateEvent(locate=checkState) def onHeatSwitch(self): self.isHeating = self.checkState() - 1 print("isHeating = {}".format(self.isHeating))
class Convection(DynamicalModel): hConv = F.RealVariable(causality=CS.Parameter, variability=VR.Constant, default=10) area = F.RealVariable(causality=CS.Parameter, variability=VR.Constant, default=0.2) pFluid = F.RealVariable(causality=CS.Input) TFluid = F.RealVariable(causality=CS.Input) TWall = F.RealVariable(causality=CS.Input) QFluid = F.RealVariable(causality=CS.Output) QWall = F.RealVariable(causality=CS.Output) portFluid = F.Port([pFluid, TFluid, QFluid]) portWall = ThermalPort('R', TVar=TWall, QVar=QWall) def compute(self, t): self.QFluid = self.hConv * self.area * (self.TWall - self.TFluid) self.QWall = -self.QFluid
class Valve(DynamicalModel): Kv = F.RealVariable(causality=CS.Parameter, variability=VR.Constant, default=2000.) VDot = F.RealVariable(causality=CS.Output) mDot1 = F.RealVariable(causality=CS.Output) mDot2 = F.RealVariable(causality=CS.Output) p1 = F.RealVariable(causality=CS.Input) p2 = F.RealVariable(causality=CS.Input) controlSignal = F.RealVariable(causality=CS.Input, default=1) port1 = F.Port([p1, mDot1]) port2 = F.Port([p2, mDot2]) def compute(self, t): N1 = 8.784e-07 if (self.p1 > self.p2): self.VDot = N1 * self.Kv * m.sqrt((self.p1 - self.p2) / 1.0) self.mDot2 = 1000 * self.VDot * self.controlSignal self.mDot1 = -self.mDot2 else: self.VDot = 0 self.mDot2 = 0 self.mDot1 = 0 print self.mDot1
class Tank(DynamicalModel): qSource = F.SubModel(HeatSource) m1 = F.SubModel(ThermalMass) m2 = F.SubModel(ThermalMass) c = F.SubModel(ThermalConduction) conv = F.SubModel(Convection) ch = F.SubModel(FluidChamber) def __init__(self): self.m1.meta.p1.connect(self.qSource.meta.p) self.m1.meta.p2.connect(self.c.meta.p1) self.c.meta.p2.connect(self.m2.meta.p1) self.m2.meta.p2.connect(self.conv.meta.portWall) self.ch.meta.portWall.connect(self.conv.meta.portFluid)
class WaterTower(DynamicalModel): ACrossSection = F.RealVariable(causality=CS.Parameter, variability=VR.Constant, default=1.0) hWater = F.RealState(start=0.5) mDotIn = F.RealVariable(causality=CS.Input) mDotOut = F.RealVariable(causality=CS.Input) p = F.RealVariable(causality=CS.Output) portIn = F.Port([p, mDotIn]) portOut = F.Port([p, mDotOut]) @F.Function(inputs=[hWater], outputs=[p]) def compute_p(self, t): self.p = 1e5 + 1000 * 9.8 * self.hWater def compute(self, t): self.der.hWater = (self.mDotIn + self.mDotOut) / 1000. / self.ACrossSection
class FlowSource(DynamicalModel): mDot = F.RealVariable(causality=CS.Output, variability=VR.Constant, default=100.0) p = F.RealVariable(causality=CS.Input) port = F.Port([p, mDot])
class PressureSource(DynamicalModel): p = F.RealVariable(causality=CS.Output, variability=VR.Constant, default=1e5) mDot = F.RealVariable(causality=CS.Input) port = F.Port([p, mDot])
class MechSystem(DynamicalModel): fs = F.SubModel(ForceSource) mass = F.SubModel(BoundMass) def __init__(self): self.fs.meta.p.connect(self.mass.meta.p)