############################################################################### ## ## Oxygen system module for FlightGear. ## ## Copyright (C) 2010 Vivian Meazza (vivia.meazza(at)lineone.net) ## This file is licensed under the GPL license v2 or later. ## ############################################################################### # Properties under /consumables/fuel/tank[n]: # + level_cu_ft - Current free oxygen content. Must be set by user code. # + capacity_cu_ft - Tank volume # + selected - boolean indicating tank selection. # + name ...........- string # + pressure - OUTPUT ONLY property, do not try to set # Properties under /controls/oxygen/ # + altitude-norm - the selected supply altitude normalized 0 - 100% oxygen # + flowrate_cu_ft_ps - Max (100%) Oxygen flow rate # + flowrate considerations: # ref http://en.wikipedia.org/wiki/Human_lung # # when maximum (100%) oxygen is selected, we wish to deliver enough oxygen to fill # the pilot's lungs, with slight overpressure. # # let the tidal flow volume - that is the amount of gas which flows # into and out of the lungs on each breath = T ft^3; # and the number of breaths per minute at rest= N min^-1; # but we need to consider a pilot under stress factor = 1.5 # # so flowrate (ft^3.sec^-1) = (T*1.5*N)/60 # # substituting the values from the reference # # flowrate = 0.01765 * 1.5 * 20 / 60 = 0.008828 # # rounding up to provide overpressure # # flowrate = 0.01 (ft^3.sec^-1) #========================= Initialize =============================== var MAXTANKS = 20; var INHG2PSI = 0.491154077497; var initialize = func { print( "Initializing Oxygen System ..." ); props.globals.initNode("/systems/oxygen/serviceable", 1, "BOOL"); props.globals.initNode("/sim/freeze/oxygen", 0, "BOOL"); props.globals.initNode("/controls/oxygen/altitude-norm", 0.0, "DOUBLE"); props.globals.initNode("/controls/oxygen/flowrate-cu-ft-ps", 0.01, "DOUBLE"); for (var i = 0; i < MAXTANKS; i += 1){ props.globals.initNode("/consumables/oxygen/tank["~ i ~ "]/capacity-cu-ft", 0.01, "DOUBLE"); props.globals.initNode("/consumables/oxygen/tank["~ i ~ "]/level-cu-ft", 0, "DOUBLE"); props.globals.initNode("/consumables/oxygen/tank["~ i ~ "]/selected", 0, "BOOL"); props.globals.initNode("/consumables/oxygen/tank["~ i ~ "]/pressure-psi", 50, "DOUBLE"); } oxygen(); } #end init #========================= Oxygen System ============================ var oxygen = func { var freeze = getprop("/sim/freeze/oxygen"); var serviceable =getprop("/systems/oxygen/serviceable"); if(freeze or !serviceable) { return; } var dt = getprop("sim/time/delta-sec"); var oxygen_alt = getprop("controls/oxygen/altitude-norm"); var flowrate_cu_ft_ps = getprop("controls/oxygen/flowrate-cu-ft-ps"); var Pa = getprop("environment/pressure-inhg") * INHG2PSI; var flow_cu_ft = flowrate_cu_ft_ps * oxygen_alt * dt; var contents = 0; var cap = 0; var availableTanks = []; var selected = 0; var pressure = 2000; # Build a list of available tanks. An available tank is both selected, has # oxygen remaining.and pressure < ambient. var AllTanks = props.globals.getNode("consumables/oxygen").getChildren("tank"); foreach( var t; AllTanks) { cap = t.getNode("capacity-cu-ft", 1).getValue(); contents = t.getNode("level-cu-ft", 1).getValue(); selected = t.getNode("selected", 1).getBoolValue(); pressure = t.getNode("pressure-psi", 1).getValue(); if(cap != nil and cap > 0.01 ) { # print ("Pressure ", pressure, " " , Pa); if(selected and pressure > Pa) { append(availableTanks, t); } } } # print("flow_cu_ft ", flow_cu_ft," " ,size(availableTanks)); # Subtract flow_cu_ft from tanks, set auxilliary properties. Set out-of-gas # when all tanks are empty. var outOfGas = 0; if(size(availableTanks) == 0) { outOfGas = 1; } else { flowPerTank = flow_cu_ft / size(availableTanks); foreach( var t; availableTanks ) { cu_ft = t.getNode("level-cu-ft").getValue(); cu_ft -= flowPerTank; cap = t.getNode("capacity-cu-ft", 1).getValue(); if(cu_ft < 0) { cu_ft = 0;} # print ("pressure ", calcPressure(cu_ft, cap)); t.getNode("level-cu-ft").setDoubleValue(cu_ft); t.getNode("pressure-psi").setDoubleValue(calcPressure(cu_ft, cap)); } } settimer(oxygen, 0.3); } #end oxygen # We apply Boyle's Law to derive the pressure in the tank fom the capacity of the # tank and the contents. We ignore the effects of temperature. var calcPressure = func (cu_ft, cap){ var Vc = cap; var Va = cu_ft; var Pa = 14.7; # print (Vc, " ", Va, " ", Pa); Pc = (Pa * Va)/Vc; return Pc; } #end calcPressure setlistener("sim/signals/fdm-initialized", initialize); # end