hi there,

the main stuff of the new electrical system is done. if attached 3 nasal
files which should be put into the Systems directory. also i've attached
a diff file which registers the nasal stuff in the set-xml and connects
the pfds and the eicas to the system (as example). the whole system is
currently working parallel to the old one and is not affecting it. it
implements the all the generators, busses, switches, relays, lights and
gauges of the system. what is not done, is connecting all the systems to
the busses (except of the the pfds and eicas mentioned above).

electrical.nas                  implements the abstract elect. system
                                classes. could maybe used for other
                                aircrafts too. i think its pretty
                                flexible, but could need some   
                                improvments. :)

737-electrical.nas              implements the electrical system of the
                                737-300

737-electrical-devices.nas      implements the connectionion to the
                                aircrafts devices.


for the people who want to connect new (or old) devices to the system:

the basic function of the system is, that a tree structure of ElecNodes
is created (by connecting the nodes). then the current and voltage of
each node is calculated (you find them in the property tree, described
below). i will not describe the system in detail here (read the code in
electrical.nas, i hope its not hard to understand). important for
implementing is (take a look at the examples in 737-electrical-devices.nas):

- create a node and give it a name and 'device' as type
- overwrite the GetMyCurrent function. it should return the current
  sources at that time. you can read me.voltage to get the voltage
  currently attached to the device.
- connect the node to to a bus with the e.concatNodes() function
  (you can find all the busses under /systems/electrics/bus/*)

to the property tree:

/systems/electrics/* contains the current state of each component of the
system. they are grouped by their type (bus,device,relay,source,tr).

/systems/electric/* contains the the interface for the panels. (input
and output). they are grouped by panels.

now a little extended description of the panel interfaces:

Meter Panel (/controls/electric/meterpanel/*):
-----------------------------------------------
Switches:
        dc_selector: The DC Source Selector
                0: DC Standby Bus
                1: Battery Bus
                2: Battery
                3: TR1
                4: TR2
                5: TR3
                6: Test

        ac_selector: The AC Source Selector
                0: AC Standby Bus
                1: External AC
                2: Engine Generator 1
                3: APU
                4: Engine Generator 2
                5: Static Inverter
                6: Test

        batteryswitch:  The Battery Switch

        galleyswitch:   The Galley Bus Switch

        not implemented yet:
                - Residual volts switch
        
Gauges (round analog):
        dc_amps:  DC ampere meter
        dc_volts: DC volts meter
        ac_freq:  AC frequency meter
        ac_volts: AC volts meter


Generator Bus Panel (/controls/electric/genbuspanel/*):
--------------------------------------------------------
Switches:
        grdpwr: Ground Power switch
        bustrans: Bus Transfer switch (0: off, 1: auto)
        
        (the next 4 have 3 positions 0=center 1=on 2=off.
         they automaticly flip back from on or off to the
         center position)
        gen0: Generator 1 on genbus 1 (left)
        apugen0: APU  Generator on genbus 1 (left)
        gen1: Generator 2 on genbus 2 (right)
        apugen1: APU  Generator on genbus 2 (right)

Lights:
        grdpwravailable: [GND POWER AVAILABLE] (blue)
        transferbusoff0: [TRANSFER BUS OFF] (red) left
        transferbusoff1: [TRANSFER BUS OFF] (red) right
        busoff0:         [BUS OFF] (red) left
        busoff1:         [BUS OFF] (red) right
        genoffbus0:      [GEN OFF BUS] (blue) left
        genoffbus1:      [GEN OFF BUS] (blue) right


Gauges (round analog):
        acamps0:        AC ampere meter (left)
        acamps1:        AC ampere meter (right)

        
Misc (/controls/electric/misc/*):
----------------------------------
grdsvcswitch:           Ground Service Switch

Standby Panel (/controls/electric/standbypanel/*):
--------------------------------------------------
standbypower:           Standby Switch 0:off, 1:auto 2:battery



TODO:
 - the FIXMEs :)
 - generator drive disconnect
 - res. volts switch in the meter panel
 - attach all the devices of the aircraft
 - external DC
 - the APU
 - better current calculation in the framework


closing - i think it is a good time for cvs :)


cu markus


-- 
Markus Barenhoff - Hamburg - Germany - Earth
url: http://www.alios.org/ - mail: [EMAIL PROTECTED]
pgpkey: 0xAE7C7759 fp: 79 64 AA D9 B7 16 F5 06  6A 88 5F A9 4D 49 45 BB

? Systems/737-electrical-devices.nas
? Systems/737-electrical.nas
? Systems/electrical.nas
Index: 737-300-set.xml
===================================================================
RCS file: /var/cvs/FlightGear-0.9/data/Aircraft/737-300/737-300-set.xml,v
retrieving revision 1.2
diff -r1.2 737-300-set.xml
109,111c109,121
<    <airground>
<      <file>Aircraft/737-300/Systems/air-ground.nas</file>
<    </airground>
---
>   <airground>
>    <file>Aircraft/737-300/Systems/air-ground.nas</file>
>   </airground>
>   <electrical-base>
>    <file>Aircraft/737-300/Systems/electrical.nas</file>
>    <module>e</module>
>   </electrical-base>
>   <electrical>
>    <file>Aircraft/737-300/Systems/737-electrical.nas</file>
>   </electrical>
>   <electrical-devices>
>    <file>Aircraft/737-300/Systems/737-electrical-devices.nas</file>
>   </electrical-devices>
Index: Panels/737-ifr-panel.xml
===================================================================
RCS file: /var/cvs/FlightGear-0.9/data/Aircraft/737-300/Panels/737-ifr-panel.xml,v
retrieving revision 1.2
diff -r1.2 737-ifr-panel.xml
144a145,150
>    <condition>
>     <greater-than>
>      <property>/systems/electrics/device/eicas/voltage</property>
>      <value type="double">27.0</value>
>     </greater-than>
>    </condition>
152a159,164
>    <condition>
>     <greater-than>
>      <property>/systems/electrics/device/pfd1-lh/voltage</property>
>      <value type="double">27.0</value>
>     </greater-than>
>    </condition>
160a173,178
>    <condition>
>     <greater-than>
>      <property>/systems/electrics/device/pfd2-lh/voltage</property>
>      <value type="double">27.0</value>
>     </greater-than>
>    </condition>
168a187,192
>    <condition>
>     <greater-than>
>      <property>/systems/electrics/device/pfd1-rh/voltage</property>
>      <value type="double">27.0</value>
>     </greater-than>
>    </condition>
176a201,206
>    <condition>
>     <greater-than>
>      <property>/systems/electrics/device/pfd2-rh/voltage</property>
>      <value type="double">27.0</value>
>     </greater-than>
>    </condition>
##########################################################################
# Copyright (c) 2006 Markus Barenhoff <[EMAIL PROTECTED]>
#
# This file is protected by the GNU Public License. For more details,
# please see the text file COPYING.
##########################################################################

# TODO:
#  - all the FIXMEs
#  - generator drive disconnect
#  - res. volts switch in the meter panel
#  - attach the devices with their work load to the busses
#  - external DC
net  = e.ElecNet.new();

# 
# helper functions
#
setprop_b() = func {
        props.globals.getNode(arg[0], 1).setBoolValue(arg[1]);
};

#
# sources
#
apu = e.ElecNode.new();
apu.type = "source";
apu.name = "apu";
apu.u_transformer = func {
# FIXME: implment apu stuff
        me.voltage = 115.0;
};
net.addSourceNode(apu);

external_ac = e.ElecNode.new();
external_ac.type = "source";
external_ac.name = "external_ac";
external_ac.u_transformer = func {
        if(getprop("/controls/gear/brake-parking")) {
                me.voltage = 115.0;
        } else {
                me.voltage = 0.0;
        }
};
net.addSourceNode(external_ac);

external_dc = e.ElecNode.new();
external_dc.type = "source";
external_dc.name = "external_dc";
external_dc.u_transformer = func {
        if(getprop("/controls/gear/brake-parking")) {
                me.voltage = 28.0;
        } else {
                me.voltage = 0.0;
        }
};
net.addSourceNode(external_dc);


enggen1 = e.ElecNode.new();
enggen1.type = "source";
enggen1.name = "generator1";
enggen1.u_transformer = func {
        rpm = getprop("/engines/engine[0]/n1");
        factor = rpm / 20;
        if(factor > 1.0) {
                factor = 1.0;
        }
        me.voltage = (115 * factor) + (3.0 * (rand() - 0.5));
};
net.addSourceNode(enggen1);

enggen2 = e.ElecNode.new();
enggen2.type = "source";
enggen2.name = "generator2";
enggen2.u_transformer = func {
        rpm = getprop("/engines/engine[1]/n1");
        factor = rpm / 20;
        if(factor > 1.0) {
                factor = 1.0;
        }
        me.voltage = (115 * factor) + (3.0 * (rand() - 0.5));
};
net.addSourceNode(enggen2);

# FIXME: implement battery stuff
battery = e.ElecNode.new();
battery.type = "source";
battery.name = "battery";
battery.remaining = 600; # in A/h FIXME: get correct values
battery.charging = 0;
battery.charger_powered = 0;
battery.u_transformer = func {
        me.charging = 0;
        me.charger_powered = 0;
        foreach(node; me.inputs) {
                if(node.voltage > 25.0) {
                        me.charger_powered = 1;
                        if(me.remaining < 600.0) {
                                me.charging = 1;
                        }
                }
        }

        if((me.charger_powered) or (me.remaining > 0.0)) {
                me.voltage = 28.0;
        } else {
                me.voltage = 0.0;
        }

};

battery.i_transformer = func {
        me.default_i_transformer();
        if(me.charging) {
                me.current = me.current + 20; # FIXME: correct load current
                me.remaining = me.remaining + 20;
        }

        if(!me.charger_powered) {
                me.remaining = me.remaining - me.current;
        }
};

net.addSourceNode(battery);

# busses
genbus1 = e.ElecNode.new(); 
genbus1.name = "genbus1"; 

genbus2 = e.ElecNode.new(); 
genbus2.name = "genbus2"; 

extern_ac_bus = e.ElecNode.new();
extern_ac_bus.name = "extern_ac_bus";

grd_svc_bus = e.ElecNode.new();
grd_svc_bus.name = "ground_service_bus";

main_bus1 = e.ElecNode.new();
main_bus1.name = "main_bus1";

main_bus2 = e.ElecNode.new();
main_bus2.name = "main_bus2";

xfr_bus1 = e.ElecNode.new();
xfr_bus1.name = "xfr_bus1";

xfr_bus2 = e.ElecNode.new();
xfr_bus2.name = "xfr_bus2";

dc_bus1 = e.ElecNode.new();
dc_bus1.name = "dc_bus1";

dc_bus2 = e.ElecNode.new();
dc_bus2.name = "dc_bus2";

dctie_bus = e.ElecNode.new();
dctie_bus.name = "dctie_bus";

battery_bus = e.ElecNode.new();
battery_bus.name = "battery_bus";

hot_battery_bus = e.ElecNode.new();
hot_battery_bus.name = "hot_battery_bus";

sw_hot_battery_bus = e.ElecNode.new();
sw_hot_battery_bus.name = "sw_hot_battery_bus";

ac_stby_bus = e.ElecNode.new();
ac_stby_bus.name = "ac_stby_bus";

dc_stby_bus = e.ElecNode.new();
dc_stby_bus.name = "dc_stby_bus";

galley_bus1  = e.ElecNode.new();
galley_bus1.name = "galley_bus1";

galley_bus2  = e.ElecNode.new();
galley_bus2.name = "galley_bus2";

# relays
grdpwrrelay = e.ElecNode.new();
grdpwrrelay.name = "grdpwrrelay";
grdpwrrelay.type = "relay"; 
grdpwrrelay.switch = func { 
        getprop("/controls/electric/genbuspanel/grdpwr");
};

grdsvcrelay1 = e.ElecNode.new();
grdsvcrelay1.name = "grdsvcrelay1";
grdsvcrelay1.type = "relay"; 
grdsvcrelay1.switch = func { 
        getprop("/controls/electric/misc/grdsvcswitch");
};

grdsvcrelay2 = e.ElecNode.new();
grdsvcrelay2.name = "grdsvcrelay2";
grdsvcrelay2.type = "relay"; 
grdsvcrelay2.switch = func { 
        (!getprop("/controls/electric/misc/grdsvcswitch"));
};

gengenbusrelay1 = e.ElecNode.new();
gengenbusrelay1.name = "gengenbusrelay1";
gengenbusrelay1.type = "relay";
gengenbusrelay1.switch = func {1;}; 

apugenbusrelay1 = e.ElecNode.new();
apugenbusrelay1.name = "apugenbusrelay1"; 
apugenbusrelay1.type = "relay"; 
apugenbusrelay1.switch = func {0;};

extgenbusrelay1 = e.ElecNode.new();
extgenbusrelay1.name = "extgenbusrelay1";
extgenbusrelay1.type = "relay";
extgenbusrelay1.switch = func {0;};

gengenbusrelay2 = e.ElecNode.new(); 
gengenbusrelay2.name = "gengenbusrelay2";
gengenbusrelay2.type = "relay";
gengenbusrelay2.switch = func {1;}; 

apugenbusrelay2 = e.ElecNode.new(); 
apugenbusrelay2.name = "apugenbusrelay2";
apugenbusrelay2.type = "relay";
apugenbusrelay2.switch = func {0;};

extgenbusrelay2 = e.ElecNode.new();
extgenbusrelay2.name = "extgenbusrelay2";
extgenbusrelay2.type = "relay";
extgenbusrelay2.switch = func {0;};


xfrbusrelay1norm = e.ElecNode.new();
xfrbusrelay1norm.name = "xfrbusrelay1norm";
xfrbusrelay1norm.type = "relay";
xfrbusrelay1norm.switch = func { 1; };

xfrbusrelay1alt = e.ElecNode.new();
xfrbusrelay1alt.name = "xfrbusrelay1alt";
xfrbusrelay1alt.type = "relay";
xfrbusrelay1alt.switch = func { 0; };

xfrbusrelay2norm = e.ElecNode.new();
xfrbusrelay2norm.name = "xfrbusrelay2norm";
xfrbusrelay2norm.type = "relay";
xfrbusrelay2norm.switch = func { 1; };

xfrbusrelay2alt = e.ElecNode.new();
xfrbusrelay2alt.name = "xfrbusrelay2alt";
xfrbusrelay2alt.type = "relay";
xfrbusrelay2alt.switch = func { 0; };

batchrgrelaynorm = e.ElecNode.new();
batchrgrelaynorm.name = "batchrgrelaynorm";
batchrgrelaynorm.type = "relay";
batchrgrelaynorm.switch = func { 1; };

batchrgrelayalt = e.ElecNode.new();
batchrgrelayalt.name = "batchrgrelaynorm";
batchrgrelayalt.type = "relay";
batchrgrelayalt.switch = func { 1; };

batteryrelay = e.ElecNode.new();
batteryrelay.name = "batteryrelay";
batteryrelay.type = "relay";
batteryrelay.switch = func {
        getprop("/controls/electric/meterpanel/batteryswitch");
};

stbynormalrelay1 = e.ElecNode.new();
stbynormalrelay1.name = "stbynormalrelay1";
stbynormalrelay1.type = "relay";
stbynormalrelay1.switch = func { 1; };

stbynormalrelay2 = e.ElecNode.new();
stbynormalrelay2.name = "stbynormalrelay2";
stbynormalrelay2.type = "relay";
stbynormalrelay2.switch = func { 1; };

stbyaltrelay1 = e.ElecNode.new();
stbyaltrelay1.name = "stbyaltrelay1";
stbyaltrelay1.type = "relay";
stbyaltrelay1.switch = func { 0; };

stbyaltrelay2 = e.ElecNode.new();
stbyaltrelay2.name = "stbyaltrelay2";
stbyaltrelay2.type = "relay";
stbyaltrelay2.switch = func { 0; };

batbusnormrelay = e.ElecNode.new();
batbusnormrelay.name = "batbusnormrelay";
batbusnormrelay.type = "relay";
batbusnormrelay.switch = func { 1; };

batbusaltrelay = e.ElecNode.new();
batbusaltrelay.name = "batbusaltrelay";
batbusaltrelay.type = "relay";
batbusaltrelay.switch = func { 0; };

tr3discrelay = e.ElecNode.new();
tr3discrelay.name = "tr3disconnectrelay";
tr3discrelay.type = "relay";
tr3discrelay.switch = func { 1; };

f = func { 
        v = getprop("/controls/electric/meterpanel/galleyswitch");
        
        # if switch is off -> open relay
        if(!v) { return 0; }
        
        # if apu power exceeds 167A on the ground
        if((apu.current > 167) and (airground.INAIR == "true")) { return 0; };
        
        # close relay if one of the generator buses is not powered
        if((genbus1.voltage < 110) or (genbus2.voltage < 110)) { return 0;};

        return 1;
};
galleybusrelay1 = e.ElecNode.new();
galleybusrelay1.name = "galleybusrelay1";
galleybusrelay1.type = "relay";
galleybusrelay1.switch = f;

galleybusrelay2 = e.ElecNode.new();
galleybusrelay2.name = "galleybusrelay2";
galleybusrelay2.type = "relay";
galleybusrelay2.switch = f;


# TRs
tr_u_transformer = func {
        fact = 4.1071428571428568;

        me.default_u_transformer();
        me.voltage = me.voltage / fact;
};

tr_i_transformer = func {
        fact = 4.1071428571428568;

        me.default_i_transformer();
        me.current = me.current / fact;
};

tr1 = e.ElecNode.new();
tr1.type = "tr";
tr1.name = "TR1";
tr1.u_transformer = tr_u_transformer;
tr1.i_transformer = tr_i_transformer;

tr2 = e.ElecNode.new();
tr2.type = "tr";
tr2.name = "TR2";
tr2.u_transformer = tr_u_transformer;
tr2.i_transformer = tr_i_transformer;

tr3 = e.ElecNode.new();
tr3.type = "tr";
tr3.name = "TR3";
tr3.u_transformer = tr_u_transformer;
tr3.i_transformer = tr_i_transformer;

battery_chrg = e.ElecNode.new();
battery_chrg.type = "device";
battery_chrg.name = "battery_charger";
battery_chrg.u_transformer = tr_u_transformer;
battery_chrg.i_transformer = tr_i_transformer;

static_inverter = e.ElecNode.new();
static_inverter.type = "device";
static_inverter.name = "static_inverter";
static_inverter.u_transformer = func {
        fact = 0.24347826086956523;

        me.default_u_transformer();
        me.voltage = me.voltage / fact;
};
static_inverter.i_transformer = func {
        fact = 0.24347826086956523;

        me.default_i_transformer();
        me.current = me.current / fact;
};

# FIXME: implement battery charging stuff
battery_chrg.getMyCurrent = func { if(me.voltage > 110.0) {23.0;} else {0.0;} };

# set initial switch positions

## genbus panel
# this are all 3 way switches 0:neutral 1:on  2:off
setprop("/controls/electric/genbuspanel/gen0", 0);
gen1inlistener = 0;
f = func { 
        if(gen1inlistener) { return; }
        if(enggen1.voltage < 110) { return;}
        gen1inlistener = 1;
        v = getprop("/controls/electric/genbuspanel/gen0");
        if(v == 1) {
                gengenbusrelay1.switch = func {1;}; 
                apugenbusrelay1.switch = func {0;};
                extgenbusrelay1.switch = func {0;};
        }
        if(v == 2) {
                gengenbusrelay1.switch = func {0;}; 
        }
        setprop("/controls/electric/genbuspanel/gen0", 0);
        gen1inlistener = 0;
};
setlistener("/controls/electric/genbuspanel/gen0", f);

setprop("/controls/electric/genbuspanel/gen1", 0);
gen2inlistener = 0;
f = func { 
        if(gen2inlistener) { return; }
        if(enggen2.voltage < 110) { return;}
        gen2inlistener = 1;
        v = getprop("/controls/electric/genbuspanel/gen1");
        if(v == 1) {
                gengenbusrelay2.switch = func {1}; 
                apugenbusrelay2.switch = func {0};
                extgenbusrelay2.switch = func {0};
        }
        if(v == 2) {
                gengenbusrelay2.switch = func {0;}; 
        }
        setprop("/controls/electric/genbuspanel/gen1", 0);
        gen2inlistener = 0;
};
setlistener("/controls/electric/genbuspanel/gen1", f);

setprop("/controls/electric/genbuspanel/apugen0", 0);
apu1inlistener = 0;
f = func { 
        if(apu1inlistener) { return; }
        if(apu.voltage < 110) { return;}
        apu1inlistener = 1;
        v = getprop("/controls/electric/genbuspanel/apugen0");
        if(v == 1) {
                gengenbusrelay1.switch = func {0}; 
                apugenbusrelay1.switch = func {1};
                extgenbusrelay1.switch = func {0};
        }
        if(v == 2) {
                apugenbusrelay1.switch = func {0;}; 
        }
        setprop("/controls/electric/genbuspanel/apugen0", 0);
        apu1inlistener = 0;
};
setlistener("/controls/electric/genbuspanel/apugen0", f);

setprop("/controls/electric/genbuspanel/apugen1", 0);
apu2inlistener = 0;
f = func { 
        if(apu2inlistener) { return; }
        if(apu.voltage < 110) { return;}
        apu2inlistener = 1;
        v = getprop("/controls/electric/genbuspanel/apugen1");
        if(v == 1) {
                gengenbusrelay2.switch = func {0}; 
                apugenbusrelay2.switch = func {1};
                extgenbusrelay2.switch = func {0};
        } 
        if(v == 2) {
                apugenbusrelay2.switch = func {0;}; 
        }
        setprop("/controls/electric/genbuspanel/apugen1", 0);
        apu2inlistener = 0;
};
setlistener("/controls/electric/genbuspanel/apugen1", f);

setprop_b("/controls/electric/genbuspanel/grdpwr", 0);
f = func {
        v = getprop("/controls/electric/genbuspanel/grdpwr");
        if(v) {
                gengenbusrelay1.switch = func {0}; 
                apugenbusrelay1.switch = func {0};
                extgenbusrelay1.switch = func {1};
                gengenbusrelay2.switch = func {0}; 
                apugenbusrelay2.switch = func {0};
                extgenbusrelay2.switch = func {1};              
        } else {
                extgenbusrelay2.switch = func {0};
                extgenbusrelay2.switch = func {0};
        }
}
setlistener("/controls/electric/genbuspanel/grdpwr", f);

setprop_b("/controls/electric/genbuspanel/bustrans", 1);

## meter panel
setprop_b("/controls/electric/meterpanel/batteryswitch", 1);
setprop("/controls/electric/meterpanel/ac_selector", 0);
setprop("/controls/electric/meterpanel/dc_selector", 0);
setprop_b("/controls/electric/meterpanel/galleyswitch", 0);

## standby panel
# Standby Power
# 0 => off
# 1 => auto
# 2 => battery
setprop("/controls/electric/standbypanel/standbypower", 1);

## misc panels
setprop_b("/controls/electric/misc/grdsvcswitch", 0);
    
# set initial light and gauge states
## genbus panel
setprop_b("/controls/electric/genbuspanel/grdpwravailable", 0);
setprop_b("/controls/electric/genbuspanel/apugenoffbus", 0);
setprop_b("/controls/electric/genbuspanel/transferbusoff0", 0);
setprop_b("/controls/electric/genbuspanel/transferbusoff1", 0);
setprop_b("/controls/electric/genbuspanel/busoff0", 0);
setprop_b("/controls/electric/genbuspanel/busoff1", 0);
setprop_b("/controls/electric/genbuspanel/genoffbus0", 0);
setprop_b("/controls/electric/genbuspanel/genoffbus1", 0);
setprop("/controls/electric/genbuspanel/acamps0", 0.0);
setprop("/controls/electric/genbuspanel/acamps1", 0.0);

## meter panel
setprop("/controls/electric/meterpanel/ac_volts", 0);
setprop("/controls/electric/meterpanel/ac_freq", 0);
setprop("/controls/electric/meterpanel/dc_volts", 0);
setprop("/controls/electric/meterpanel/dc_amps", 0);


# geneartor bus 1
e.concatNodes(enggen1, gengenbusrelay1);
e.concatNodes(gengenbusrelay1, genbus1);
e.concatNodes(apu,apugenbusrelay1);
e.concatNodes(apugenbusrelay1, genbus1);
e.concatNodes(external_ac, grdpwrrelay);
e.concatNodes(grdpwrrelay, extgenbusrelay1);
e.concatNodes(extgenbusrelay1, genbus1);
e.concatNodes(genbus1, galleybusrelay1);
e.concatNodes(galleybusrelay1, galley_bus1);

# generator bus 2
e.concatNodes(enggen2, gengenbusrelay2);
e.concatNodes(gengenbusrelay2, genbus2);
e.concatNodes(apu,apugenbusrelay2);
e.concatNodes(apugenbusrelay2, genbus2);
e.concatNodes(grdpwrrelay,extgenbusrelay2);
e.concatNodes(extgenbusrelay2, genbus2);
e.concatNodes(genbus2, galleybusrelay2);
e.concatNodes(galleybusrelay2, galley_bus2);


# external power
e.concatNodes(external_ac, extern_ac_bus);
e.concatNodes(extern_ac_bus,grdsvcrelay1);
e.concatNodes(grdsvcrelay1, grd_svc_bus);
e.concatNodes(genbus1, grdsvcrelay2);
e.concatNodes(grdsvcrelay2, grd_svc_bus);

# main busses
e.concatNodes(genbus1, main_bus1);
e.concatNodes(genbus2, main_bus2);

# transfer busses
e.concatNodes(genbus1, xfrbusrelay1norm);
e.concatNodes(genbus1, xfrbusrelay2alt);
e.concatNodes(genbus2, xfrbusrelay2norm);
e.concatNodes(genbus2, xfrbusrelay1alt);
e.concatNodes(xfrbusrelay1norm, xfr_bus1);
e.concatNodes(xfrbusrelay1alt,  xfr_bus1);
e.concatNodes(xfrbusrelay2norm, xfr_bus2);
e.concatNodes(xfrbusrelay2alt,  xfr_bus2);

# battery charger
e.concatNodes(grd_svc_bus, batchrgrelaynorm);
e.concatNodes(main_bus2, batchrgrelayalt);
e.concatNodes(batchrgrelaynorm, battery_chrg);
e.concatNodes(batchrgrelayalt, battery_chrg);

e.concatNodes(battery_chrg, hot_battery_bus);
e.concatNodes(battery, hot_battery_bus);

e.concatNodes(battery_chrg, batteryrelay);
e.concatNodes(battery, batteryrelay);
e.concatNodes(batteryrelay, sw_hot_battery_bus);

e.concatNodes(hot_battery_bus, batbusaltrelay);
e.concatNodes(batbusaltrelay, battery_bus);

e.concatNodes(tr3, batbusnormrelay);
e.concatNodes(batbusnormrelay, battery_bus);

#e.concatNodes(external_dc, hot_battery_bus);

# TRs
e.concatNodes(xfr_bus1, tr1);
e.concatNodes(xfr_bus2, tr2);
e.concatNodes(main_bus2, tr3);

# DC busses
e.concatNodes(tr1, dc_bus1);
e.concatNodes(tr2, dc_bus2);
e.concatNodes(tr3, dc_bus2);

e.concatNodes(tr1, dctie_bus);
e.concatNodes(tr2, dctie_bus);
e.concatNodes(tr3, dctie_bus);
e.concatNodes(dctie_bus, tr3discrelay);
e.concatNodes(tr3discrelay, dc_bus1);
e.concatNodes(tr3discrelay, dc_bus2);

# standby stuff
e.concatNodes(dc_bus1, stbynormalrelay2);
e.concatNodes(stbynormalrelay2, dc_stby_bus);
e.concatNodes(battery_bus, stbyaltrelay2);
e.concatNodes(stbyaltrelay2, dc_stby_bus);

e.concatNodes(battery_bus, static_inverter);
e.concatNodes(xfr_bus1, stbynormalrelay1);
e.concatNodes(stbynormalrelay1, ac_stby_bus);
e.concatNodes(static_inverter, stbyaltrelay1);
e.concatNodes(stbyaltrelay1, ac_stby_bus);

updateLights() = func {
        v = (external_ac.voltage > 110);
        setprop_b("/controls/electric/genbuspanel/grdpwravailable", v);

        v = (gengenbusrelay1.voltage < 110);
        setprop_b("/controls/electric/genbuspanel/genoffbus0", v);

        v = (gengenbusrelay2.voltage < 110);
        setprop_b("/controls/electric/genbuspanel/genoffbus1", v);

        # FIXME: apugenoffbus sometimes has nan as value
        v = (apugenbusrelay1.voltage < 110) and (apugenbusrelay2.voltage < 110);
        setprop_b("/controls/electric/genbuspanel/apugenoffbus", v);

        v = (xfr_bus1.voltage < 110);
        setprop_b("/controls/electric/genbuspanel/transferbusoff0", v);

        v = (xfr_bus2.voltage < 110);
        setprop_b("/controls/electric/genbuspanel/transferbusoff1", v);

        v = (genbus1.voltage < 110);
        setprop_b("/controls/electric/genbuspanel/busoff0", v);

        v = (genbus2.voltage < 110);
        setprop_b("/controls/electric/genbuspanel/busoff1", v);

        setprop("/controls/electric/genbuspanel/acamps0", enggen1.current);
        setprop("/controls/electric/genbuspanel/acamps1", enggen2.current);


        # the meter panel       
        setACMeters = func {
                u = arg[0];
                if(u == nil) { u = 0.0; }

                setprop("/controls/electric/meterpanel/ac_volts", u);
                if(u > 0) { 
                        setprop("/controls/electric/meterpanel/ac_freq", 
400.0); 
                } else { 
                        setprop("/controls/electric/meterpanel/ac_freq", 0.0); 
                }

        };

        if(getprop("/controls/electric/meterpanel/ac_selector") == 0) {
                
setACMeters(getprop("/systems/electrics/bus/ac_stby_bus/voltage"));
        }

        if(getprop("/controls/electric/meterpanel/ac_selector") == 1) {
                
setACMeters(getprop("/systems/electrics/source/external_ac/voltage"));
        }

        if(getprop("/controls/electric/meterpanel/ac_selector") == 2) {
                
setACMeters(getprop("/systems/electrics/source/generator1/voltage"));
        }       

        if(getprop("/controls/electric/meterpanel/ac_selector") == 3) {
                setACMeters(getprop("/systems/electrics/source/apu/voltage"));
        }       

        if(getprop("/controls/electric/meterpanel/ac_selector") == 4) {
                
setACMeters(getprop("/systems/electrics/source/generator2/voltage"));
        }       

        if(getprop("/controls/electric/meterpanel/ac_selector") == 5) {
                
setACMeters(getprop("/systems/electrics/device/static_inverter/voltage"));
        }       

        if(getprop("/controls/electric/meterpanel/ac_selector") == 6) {
                setACMeters(0.0);
        }       

        if(getprop("/controls/electric/meterpanel/dc_selector") == 0) {
                u  = getprop("/systems/electrics/bus/dc_stby_bus/voltage");
                setprop("/controls/electric/meterpanel/dc_volts", u);
                setprop("/controls/electric/meterpanel/dc_amps", 0);
        }       

        if(getprop("/controls/electric/meterpanel/dc_selector") == 1) {
                u  = getprop("/systems/electrics/bus/battery_bus/voltage");
                setprop("/controls/electric/meterpanel/dc_volts", u);
                setprop("/controls/electric/meterpanel/dc_amps", 0);
        }       

        if(getprop("/controls/electric/meterpanel/dc_selector") == 2) {
                u = 0.0; i = 0.0;
                if(battery.charging) {
                        u  = 
getprop("/systems/electrics/device/battery_charger/voltage");
                        i  = 
getprop("/systems/electrics/device/battery_charger/current");
                } else {
                        u  = 
getprop("/systems/electrics/source/battery/voltage");
                        i  = 
getprop("/systems/electrics/source/battery/current");
                }
                setprop("/controls/electric/meterpanel/dc_volts", u);
                setprop("/controls/electric/meterpanel/dc_amps", i);
        }       

        if(getprop("/controls/electric/meterpanel/dc_selector") == 3) {
                u  = getprop("/systems/electrics/bus/dc_bus1/voltage");
                i  = getprop("/systems/electrics/tr/TR1/current");
                setprop("/controls/electric/meterpanel/dc_volts", u);
                setprop("/controls/electric/meterpanel/dc_amps", i);
        }       

        if(getprop("/controls/electric/meterpanel/dc_selector") == 4) {
                u  = getprop("/systems/electrics/bus/dc_bus2/voltage");
                i  = getprop("/systems/electrics/tr/TR2/current");
                setprop("/controls/electric/meterpanel/dc_volts", u);
                setprop("/controls/electric/meterpanel/dc_amps", i);
        }       

        if(getprop("/controls/electric/meterpanel/dc_selector") == 5) {
                u  = getprop("/systems/electrics/tr/TR3/voltage");
                i  = getprop("/systems/electrics/tr/TR3/current");
                setprop("/controls/electric/meterpanel/dc_volts", u);
                setprop("/controls/electric/meterpanel/dc_amps", i);
        }       

        if(getprop("/controls/electric/meterpanel/dc_selector") == 6) {
                u  = getprop("/systems/electrics/bus/battery_bus/voltage");
                setprop("/controls/electric/meterpanel/dc_volts", 0);
                setprop("/controls/electric/meterpanel/dc_amps", 0);
        }       

};

updateMisc() = func {
        # switch ground power off if batteryswitch is not on
        if(!getprop("/controls/electric/meterpanel/batteryswitch")) {
                setprop_b("/controls/electric/genbuspanel/grdpwr", 0);
        }
        
        # switch ground service to off if gndpwr is switched on
        if(getprop("/controls/electric/genbuspanel/grdpwr")) {
                setprop_b("/controls/electric/misc/grdsvcswitch", 0);
        }

        # the transfer bus stuff
        if(getprop("/controls/electric/genbuspanel/bustrans")) {
                if(genbus1.voltage < 110) {
                        xfrbusrelay1norm.switch = func { 0; };
                        xfrbusrelay1alt.switch  = func { 1; };
                } else {
                        xfrbusrelay1norm.switch = func { 1; };
                        xfrbusrelay1alt.switch  = func { 0; };
                }

                if(genbus2.voltage < 110) {
                        xfrbusrelay2norm.switch = func { 0; };
                        xfrbusrelay2alt.switch  = func { 1; };
                } else {
                        xfrbusrelay2norm.switch = func { 1; };
                        xfrbusrelay2alt.switch  = func { 0; };
                }

                # FIXME: check if in glide scope during fd or ap
                if(1) {
                        tr3discrelay.switch = func { 1; };
                } else {
                        tr3discrelay.switch = func { 0; };
                }

        } else {
                xfrbusrelay1norm.switch = func { 1; };
                xfrbusrelay1alt.switch  = func { 0; };
                xfrbusrelay2norm.switch = func { 1; };
                xfrbusrelay2alt.switch  = func { 0; };
                tr3discrelay.switch = func { 0; };
        }

        # the battery charger: switch to mainbus if gen1 is offline
        if(gengenbusrelay1.voltage < 110) {
                batchrgrelaynorm.switch = func { 0; };
                batchrgrelayalt.switch = func { 1; };           
        } else {
                batchrgrelaynorm.switch = func { 1; };
                batchrgrelayalt.switch = func { 0; };           
        }

        # the battery switch & hot battery bus switching
        if(getprop("/controls/electric/meterpanel/batteryswitch")) {
                # on
                if(main_bus2.voltage < 110) {
                        batbusaltrelay.switch = func { 1; };
                        batbusnormrelay.switch = func { 0; };           
                } else {
                        batbusaltrelay.switch = func { 0; };
                        batbusnormrelay.switch = func { 1; };           
                }               
        } else {
                # off
                batbusaltrelay.switch = func { 0; };
                batbusnormrelay.switch = func { 0; };           
        }

        # switch to standby (battery) if no1 dc bus or not1 transfer bus 
        # looses power
        if(getprop("/controls/electric/standbypanel/standbypower") == 0) {
                # off
                stbynormalrelay1.switch = func { 0; };
                stbynormalrelay2.switch = func { 0; };
                stbyaltrelay1.switch = func { 0; };
                stbyaltrelay2.switch = func { 0; };
        }
        if(getprop("/controls/electric/standbypanel/standbypower") == 1) {
                # auto
                if((dc_bus1.voltage < 25) or (xfr_bus1.voltage < 110)) {
                        if(airground.INAIR == "true") {
                                stbynormalrelay1.switch = func { 0; };
                                stbynormalrelay2.switch = func { 0; };
                                stbyaltrelay1.switch = func { 1; };
                                stbyaltrelay2.switch = func { 1; };             
                                        
                                batbusaltrelay.switch = func { 1; };
                                batbusnormrelay.switch = func { 0; };
                        } else {
                                batbusaltrelay.switch = func { 0; };
                                batbusnormrelay.switch = func { 1; };
                        }
                } else {
                        stbynormalrelay1.switch = func { 1; };
                        stbynormalrelay2.switch = func { 1; };
                        stbyaltrelay1.switch = func { 0; };
                        stbyaltrelay2.switch = func { 0; };                     
                }
        }

        if(getprop("/controls/electric/standbypanel/standbypower") == 2) {
                # battery
                batbusaltrelay.switch = func { 1; };
                batbusnormrelay.switch = func { 0; };
                stbynormalrelay1.switch = func { 0; };
                stbynormalrelay2.switch = func { 0; };
                stbyaltrelay1.switch = func { 1; };
                stbyaltrelay2.switch = func { 1; };
        }

};

run = func {
        print("updateing electrical system");
        net.updateNet();
        updateLights();
        updateMisc();
        settimer(run,1.0);
};

# start the electrical system
settimer(run, 0);
##########################################################################
# Copyright (c) 2006 Markus Barenhoff <[EMAIL PROTECTED]>
#
# This file is protected by the GNU Public License. For more details,
# please see the text file COPYING.
##########################################################################

# devices

# FIXME: source current
pfd1lh = e.ElecNode.new();
pfd1lh.type = "device";
pfd1lh.name = "pfd1-lh";
pfd1lh.getMyCurrent = func { if(me.voltage > 27.0) {1.0;} else {0.0;} };
e.concatNodes(electrical.dc_bus1, pfd1lh);

# FIXME: source current
pfd2lh = e.ElecNode.new();
pfd2lh.type = "device";
pfd2lh.name = "pfd2-lh";
pfd2lh.getMyCurrent = func { if(me.voltage > 27.0) {1.0;} else {0.0;} };
e.concatNodes(electrical.dc_bus2, pfd2lh);

# FIXME: source current
pfd1rh = e.ElecNode.new();
pfd1rh.type = "device";
pfd1rh.name = "pfd1-rh";
pfd1rh.getMyCurrent = func { if(me.voltage > 27.0) {1.0;} else {0.0;} };
e.concatNodes(electrical.dc_bus1, pfd1rh);

# FIXME: source current
pfd2rh = e.ElecNode.new();
pfd2rh.type = "device";
pfd2rh.name = "pfd2-rh";
pfd2rh.getMyCurrent = func { if(me.voltage > 27.0) {1.0;} else {0.0;} };
e.concatNodes(electrical.dc_bus2, pfd2rh);

# FIXME: source current
eicas = e.ElecNode.new();
eicas.type = "device";
eicas.name = "eicas";
eicas.getMyCurrent = func { if(me.voltage > 27.0) {1.0;} else {0.0;} };
e.concatNodes(electrical.dc_bus2, eicas);
##########################################################################
# Copyright (c) 2006 Markus Barenhoff <[EMAIL PROTECTED]>
#
# This file is protected by the GNU Public License. For more details,
# please see the text file COPYING.
##########################################################################

# TODO:
# - better current calculation if a bus has more than one powered sources
#


ElecNode = {
        
# constructor   
        new : func {
                obj = {};
                obj.parents = [ElecNode];

# the type of the Node
# possible types: bus, source, device
                obj.type = "bus";
                obj.name = "default";
                obj.altPropPath = nil;

# current_voltage, current_current
                obj.voltage = 0.0;              obj.current = 0.0;
                

# overwrite getMyCurrent to implement a device 
# which sources current
                obj.getMyCurrent = func {
                        return 0.0;
                };


# the inputs and outputs are a lists of ElecNode's
                obj.inputs  = [];
                obj.outputs = [];
                
                obj.addInput = func {
                        append(me.inputs, arg[0]);
                };

                obj.addOutput = func {
                        append(me.outputs, arg[0]);
                };

# the switch method
# inputs are switched on outputs if method
# returns a non nil value (used to implement
# switches and relays
                obj.switch  = func { 1; };
                
# the transform methods
# overwrite it to change the calulation
# can be used to implement a transformer or amplifier 
#
# the u_transformer should calculate the voltage based on the 
# values of the inputs.
# the i_transformer should calculate the current based on the 
# the value of the outputs outputs
#
                obj.default_u_transformer = func {
                        if(!me.switch()) {
                                me.voltage = 0.0;
                                return;
                        }

                        umax = 0.0;
                        foreach(node; me.inputs) {
                                if(node.voltage > umax) {
                                        umax = node.voltage;
                                }
                        }
                        me.voltage = umax;
                };
                obj.u_transformer = obj.default_u_transformer;

                obj.default_i_transformer = func {
                        if(!me.switch()) {
                                me.current = 0.0;
                                return;
                        }

                        isum = 0.0;
                        foreach(node; me.outputs) {
                                isum = isum + node.current;
                        }
                        me.current = isum + me.getMyCurrent();
                };
                obj.i_transformer = obj.default_i_transformer;

                # updates the propery tree
                obj.updatePropTree = func {
                        if (me.altPropPath) {
                                prefix = me.altPropPath;
                        } else {
                                prefix = "/systems/electrics/" ~ me.type ~ "/" 
~ me.name ~ "/";
                        }

                        setprop(prefix, "voltage", me.voltage);
                        setprop(prefix, "current", me.current);
                };
                
                # reset the current voltage and current
                obj.reset = func {
                        me.voltage = 0.0;
                        me.current = 0.0;
                };

                return obj;
        }
}; 

#
# This class represents a whole network
#
# You should construct your net with ElecNode objects. 
# Then create a ElecNet instance and add all the source-nodes
# with the addSourceNode()-method.
#
# After that you can call updateNet() to recalculate the whole
# network.
#
ElecNet = {
        new : func {
                obj = {};
                obj.parents = [ElecNet];
                obj.sources = [];

                # add a source node
                obj.addSourceNode = func {
                        append(me.sources, arg[0]);
                }

                # apply function arg[1] on arg[0] and all its outputs
                obj.applyFuncNetDown = func {
                        node = arg[0];
                        f    = arg[1];

                        f(node);
                        
                        foreach(child; node.outputs) {
                                me.applyFuncNetDown(child, f);
                        }                       
                };

                # apply function arg[1] on arg[0] and all its outputs...
                # ...starting from the bottom
                obj.applyFuncNetUp = func {
                        node = arg[0];
                        f    = arg[1];
                        
                        foreach(child; node.outputs) {
                                me.applyFuncNetUp(child, f);
                        }

                        f(node);

                        return;
                };

                # reset the network
                obj.resetNet = func {
                        foreach(node; me.sources) {
                                me.applyFuncNetDown(node, func { 
arg[0].reset(); });
                        }
                };


                # calculate the voltage on each node
                obj.calcVoltage = func {
                        foreach(node; me.sources) {
                                me.applyFuncNetDown(node, func { 
arg[0].u_transformer(); });
                        }
                };

                # calculate the current on each node
                obj.calcCurrent = func {
                        foreach(node; me.sources) {
                                me.applyFuncNetUp(node, func 
{arg[0].i_transformer(); });
                        }
                };

                # update the property tree
                obj.updateNodeProps() = func {
                        foreach(node; me.sources) {
                                me.applyFuncNetDown(node, func { 
arg[0].updatePropTree(); });
                        }                       
                };

                # updates the network
                obj.updateNet = func {
                        me.resetNet();
                        me.calcVoltage();
                        me.calcCurrent();
                        me.updateNodeProps();
                };

                return obj;
        }
};


# helper functions
concatNodes = func {
        n1 = arg[0];
        n2 = arg[1];
        n1.addOutput(n2);
        n2.addInput(n1);
};

Reply via email to