Howto:A system engine in Nasal

From FlightGear wiki
Revision as of 13:14, 27 April 2013 by AndersM (talk | contribs) (More text)
Jump to navigation Jump to search

This page describes an engine for aircraft systems, or rather for staging an impression of such a system. It doesn’t handle potentials, pressures or Kirchhoff's laws. It checks if switches are on or off and if minimum criterion’s are met.

The system is defined in a text-file with rows of entries, connections, each connection consists of a comma separated list consisting of: depends,limit,in,out,off,ramp

depends: The output depends on the value of this property. Must be of type number or boolean.

limit: A value or property that sets the lower limit. If depends is greater than limit then the state will be considered on.

in: A property or value if the state is on. If in is set to . the depends value is copied to out regardless of state.

out: The output property. Set to in if the state is on and off if not.

off: A value or property that out is set to if the state is off.

ramp: max change in out per second. Unlimited if 0.


An example:

engines/engine[0]/n1,27,1,systems/electrical/generator_enabled,0,0
systems/electrical/generator_enabled,0,controls/electric/engine/generator,systems/electrical/generator_on,0,0
systems/electrical/generator_on,0,200,systems/electrical/outputs/main_ac,0,0
systems/electrical/generator_on,0,45,systems/electrical/outputs/inst_ac,0,0
systems/electrical/generator_on,0,29,systems/electrical/battery_voltage,24,0
controls/electric/battery-switch,0,systems/electrical/battery_voltage,systems/electrical/outputs/battery,0,0
systems/electrical/battery_voltage,0,.,systems/electrical/outputs/comm[0],0,0
systems/electrical/outputs/battery,0,systems/electrical/outputs/main_ac,systems/electrical/outputs/fuel,0,0
systems/electrical/outputs/battery,0,.,systems/electrical/outputs/turn-coordinator,0,0
systems/electrical/outputs/battery,0,.,systems/electrical/outputs/nav[0],0,0
systems/electrical/outputs/battery,0,.,systems/electrical/outputs/gps,0,0
systems/electrical/outputs/inst_ac,0,.,systems/electrical/outputs/adf,0,0


# Potemkin system

# Connections
#dep: depends on this property.
#limit: value or property, lower limit for true. dep > limit eq. true
#in: input property eg. orientation/pitch-deg or number constant. 
#    Use . to copy dep value to out.
#out output property eg.instruments/ai/spin
#off: value if not dep true, can be a property to be read
#ramp: max change per second of out, 0 no limit

var Connection = {
  new : func(cv) {
    var m = {parents:[Connection] };
    m.dep=cv[0];
    m.limit=cv[1];
    m.in=cv[2];
    m.out=cv[3];
    m.off=cv[4];
    m.ramp=num(cv[5]);
    return m;
  },
  
};

var System_P = {

  new : func(system_file) {
    var m = {parents:[System_P] };
    m.file=system_file;
    m.connections = [];
    m.verbose = 2;
    m.running=0;
    m.dt=0;
    m.oldtime=0;
    return m;
    },

  read_connections : func {
    if (me.verbose > 0) print("Reading connections");
    var fh = io.open(getprop("/sim/aircraft-dir")~"/"~me.file, "r");
    var line="";
    while (line != nil) {
      line = io.readln(fh);
      if (line != nil) {
        var c_arr=split(",", line);
        if (size(c_arr) == 6) {
          append(me.connections, Connection.new(c_arr));
          if (me.verbose > 1) print("Adding: "~line);
        } else if (me.verbose > 1) print("Skipping: "~line);
      }
    }
    io.close(fh); 
    if (me.verbose > 0) print("Read connections");
  },

  change_value : func(prop, value, ramp) {
    if (ramp == 0) setprop(prop, value);
    else {
      var ov=num(getprop(prop));
      if (ov<value and value-ov > ramp*me.dt) setprop(prop, ov+ramp*me.dt);
      else if (ov>value and ov-value > ramp*me.dt) setprop(prop, ov-ramp*me.dt);
      else setprop(prop, value);
    }
  },

  update : func {
    if (!me.running) return;
    var time=getprop("/sim/time/elapsed-sec");
    me.dt= time-me.oldtime;
    foreach (con; me.connections) {
      dp=getprop(con.dep);
      if (dp != nil) {
        if (num(con.limit) != nil) limit=num(con.limit); else limit=getprop(con.limit);
        if (con.in == ".") me.change_value(con.out, dp, con.ramp); #copy dep value to out
        else if (dp <= limit) {
            if (num(con.off) != nil) me.change_value(con.out, num(con.off), con.ramp);
            else me.change_value(con.out, getprop(con.off), con.ramp);
        } else {
          if (num(con.in) != nil) me.change_value(con.out, num(con.in), con.ramp);
          else me.change_value(con.out, getprop(con.in), con.ramp);
        }
      }
    }
    me.oldtime=time;
    settimer( func me.update(), 0.05);    
  },

  init : func {
    me.read_connections();
    foreach (con; me.connections) {
      if (num(con.off) != nil) setprop(con.out, num(con.off));
      else setprop(con.out, getprop(con.off));
    }
    me.running=1;
    me.oldtime= getprop("/sim/time/elapsed-sec");
    if (me.verbose > 0) print("Initialized system");
    me.update();
  },
};