]> git.mxchange.org Git - flightgear.git/blob - src/Systems/electrical.cxx
Fix a problem which was introduced by the previous patch
[flightgear.git] / src / Systems / electrical.cxx
1 // electrical.cxx - a flexible, generic electrical system model.
2 //
3 // Written by Curtis Olson, started September 2002.
4 //
5 // Copyright (C) 2002  Curtis L. Olson  - curt@flightgear.org
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23
24 #include <simgear/structure/exception.hxx>
25 #include <simgear/misc/sg_path.hxx>
26
27 #include <Main/fg_props.hxx>
28 #include <Main/globals.hxx>
29
30 #include "electrical.hxx"
31
32
33 FGElectricalComponent::FGElectricalComponent() :
34     kind(-1),
35     name(""),
36     value(0.0)
37 {
38 }
39
40
41 FGElectricalSupplier::FGElectricalSupplier ( SGPropertyNode *node ) {
42     kind = FG_SUPPLIER;
43
44     // cout << "Creating a supplier" << endl;
45     name = node->getStringValue("name");
46     string _model = node->getStringValue("kind");
47     // cout << "_model = " << _model << endl;
48     if ( _model == "battery" ) {
49         model = FG_BATTERY;
50     } else if ( _model == "alternator" ) {
51         model = FG_ALTERNATOR;
52     } else if ( _model == "external" ) {
53         model = FG_EXTERNAL;
54     } else {
55         model = FG_UNKNOWN;
56     }
57     volts = node->getDoubleValue("volts");
58     amps = node->getDoubleValue("amps");
59     rpm_src = node->getStringValue("rpm-source");
60
61     int i;
62     for ( i = 0; i < node->nChildren(); ++i ) {
63         SGPropertyNode *child = node->getChild(i);
64         // cout << " scanning: " << child->getName() << endl;
65         if ( !strcmp(child->getName(), "prop") ) {
66             string prop = child->getStringValue();
67             // cout << "  Adding prop = " << prop << endl;
68             add_prop( prop );
69             fgSetDouble( prop.c_str(), amps );
70         }
71     }
72
73     _rpm_node = fgGetNode( rpm_src.c_str(), true);
74 }  
75
76
77 double FGElectricalSupplier::get_output() {
78     if ( model == FG_BATTERY ) {
79         // cout << "battery amps = " << amps << endl;
80         return amps;
81     } else if ( model == FG_ALTERNATOR ) {
82         // scale alternator output for rpms < 600.  For rpms >= 600
83         // give full output.  This is just a WAG, and probably not how
84         // it really works but I'm keeping things "simple" to start.
85         double rpm = _rpm_node->getDoubleValue();
86         double factor = rpm / 600.0;
87         if ( factor > 1.0 ) {
88             factor = 1.0;
89         }
90         // cout << "alternator amps = " << amps * factor << endl;
91         return amps * factor;
92     } else if ( model == FG_EXTERNAL ) {
93         // cout << "external amps = " << 0.0 << endl;
94         return 0.0;
95     } else {
96         SG_LOG( SG_ALL, SG_ALERT, "unknown supplier type" );
97     }
98
99     return 0.0;
100 }
101
102
103 FGElectricalBus::FGElectricalBus ( SGPropertyNode *node ) {
104     kind = FG_BUS;
105
106     name = node->getStringValue("name");
107     int i;
108     for ( i = 0; i < node->nChildren(); ++i ) {
109         SGPropertyNode *child = node->getChild(i);
110         if ( !strcmp(child->getName(), "prop") ) {
111             string prop = child->getStringValue();
112             add_prop( prop );
113         }
114     }
115 }  
116
117
118 FGElectricalOutput::FGElectricalOutput ( SGPropertyNode *node ) {
119     kind = FG_OUTPUT;
120
121     name = node->getStringValue("name");
122     int i;
123     for ( i = 0; i < node->nChildren(); ++i ) {
124         SGPropertyNode *child = node->getChild(i);
125         if ( !strcmp(child->getName(), "prop") ) {
126             string prop = child->getStringValue();
127             add_prop( prop );
128         }
129     }
130 }  
131
132
133 FGElectricalConnector::FGElectricalConnector ( SGPropertyNode *node,
134                                                FGElectricalSystem *es ) {
135     kind = FG_CONNECTOR;
136     name = "connector";
137     int i;
138     for ( i = 0; i < node->nChildren(); ++i ) {
139         SGPropertyNode *child = node->getChild(i);
140         string cname = child->getName();
141         string cval = child->getStringValue();
142         // cout << "  " << cname << " = " << cval << endl;
143         if ( cname == "input" ) {
144             FGElectricalComponent *s = es->find( child->getStringValue() );
145             if ( s != NULL ) {
146                 add_input( s );
147                 if ( s->get_kind() == FG_SUPPLIER ) {
148                     s->add_output( this );
149                 } else if ( s->get_kind() == FG_BUS ) {
150                     s->add_output( this );
151                 } else {
152                     SG_LOG( SG_ALL, SG_ALERT,
153                             "Attempt to connect to something that can't provide an output: " 
154                             << child->getStringValue() );
155                 }
156             } else {
157                 SG_LOG( SG_ALL, SG_ALERT, "Can't find named source: " 
158                         << child->getStringValue() );
159             }
160         } else if ( cname == "output" ) {
161             FGElectricalComponent *s = es->find( child->getStringValue() );
162             if ( s != NULL ) {
163                 add_output( s );
164                 if ( s->get_kind() == FG_BUS ) {
165                     s->add_input( this );
166                 } else if ( s->get_kind() == FG_OUTPUT ) {
167                     s->add_input( this );
168                 } else {
169                     SG_LOG( SG_ALL, SG_ALERT,
170                             "Attempt to connect to something that can't provide an input: " 
171                             << child->getStringValue() );
172                 }
173             } else {
174                 SG_LOG( SG_ALL, SG_ALERT, "Can't find named source: " 
175                         << child->getStringValue() );
176             }
177         } else if ( cname == "switch" ) {
178             // set default value of switch to true
179             // cout << "Switch = " << child->getStringValue() << endl;
180             fgSetBool( child->getStringValue(), true );
181             add_switch( fgGetNode( child->getStringValue(), true ) );
182         }
183     }
184
185     // do a 2nd pass to pick up starting switch value if specified
186     for ( i = 0; i < node->nChildren(); ++i ) {
187         SGPropertyNode *child = node->getChild(i);
188         string cname = child->getName();
189         string cval = child->getStringValue();
190         // cout << "  " << cname << " = " << cval << endl;
191         if ( cname == "initial-state" ) {
192             if ( cval == "off" ) {
193                 set_switches( false );
194             } else {
195                 set_switches( true );
196             }
197         }
198     }
199 }  
200
201
202 // set all switches to the specified state
203 void FGElectricalConnector::set_switches( bool state ) {
204     // cout << "setting switch state to " << state << endl;
205     for ( unsigned int i = 0; i < switches.size(); ++i ) {
206         switches[i]->setBoolValue( state );
207     }
208 }
209
210
211 // return true if all switches are true, false otherwise.  A connector
212 // could have multiple switches, but they all need to be true(closed)
213 // for current to get through.
214 bool FGElectricalConnector::get_state() {
215     unsigned int i;
216     for ( i = 0; i < switches.size(); ++i ) {
217         if ( ! switches[i]->getBoolValue() ) {
218             return false;
219         }
220     }
221
222     return true;
223 }
224
225
226 FGElectricalSystem::FGElectricalSystem () :
227     enabled(false)
228 {
229 }
230
231
232 FGElectricalSystem::~FGElectricalSystem () {
233 }
234
235
236 void FGElectricalSystem::init () {
237     config_props = new SGPropertyNode;
238
239     SGPropertyNode *path_n = fgGetNode("/sim/systems/electrical/path");
240     _volts_out = fgGetNode( "/systems/electrical/volts", true );
241     _amps_out = fgGetNode( "/systems/electrical/amps", true );
242
243     if (path_n) {
244         SGPath config( globals->get_fg_root() );
245         config.append( path_n->getStringValue() );
246
247         SG_LOG( SG_ALL, SG_ALERT, "Reading electrical system model from "
248                 << config.str() );
249         try {
250             readProperties( config.str(), config_props );
251
252             if ( build() ) {
253                 enabled = true;
254             } else {
255                 SG_LOG( SG_ALL, SG_ALERT,
256                         "Detected an internal inconsistancy in the electrical");
257                 SG_LOG( SG_ALL, SG_ALERT,
258                         " system specification file.  See earlier errors for" );
259                 SG_LOG( SG_ALL, SG_ALERT,
260                         " details.");
261                 exit(-1);
262             }        
263         } catch (const sg_exception& exc) {
264             SG_LOG( SG_ALL, SG_ALERT, "Failed to load electrical system model: "
265                     << config.str() );
266         }
267
268     } else
269         SG_LOG( SG_ALL, SG_ALERT,
270                 "No electrical model specified for this model!");
271
272     delete config_props;
273 }
274
275
276 void FGElectricalSystem::bind () {
277 }
278
279
280 void FGElectricalSystem::unbind () {
281 }
282
283
284 void FGElectricalSystem::update (double dt) {
285     if ( !enabled ) {
286         _amps_out->setDoubleValue(0);
287         return;
288     }
289
290     // cout << "Updating electrical system" << endl;
291
292     unsigned int i;
293
294     // zero everything out before we start
295     for ( i = 0; i < suppliers.size(); ++i ) {
296         suppliers[i]->set_value( 0.0 );
297     }
298     for ( i = 0; i < buses.size(); ++i ) {
299         buses[i]->set_value( 0.0 );
300     }
301     for ( i = 0; i < outputs.size(); ++i ) {
302         outputs[i]->set_value( 0.0 );
303     }
304     for ( i = 0; i < connectors.size(); ++i ) {
305         connectors[i]->set_value( 0.0 );
306     }
307
308     // for each supplier, propagate the electrical current
309     for ( i = 0; i < suppliers.size(); ++i ) {
310         // cout << " Updating: " << suppliers[i]->get_name() << endl;
311         propagate( suppliers[i], 0.0, " " );
312     }
313
314     double alt_norm
315         = fgGetDouble("/systems/electrical/suppliers/alternator") / 60.0;
316
317     // impliment an extremely simplistic voltage model (assumes
318     // certain naming conventions in electrical system config)
319     double volts = 0.0;
320     if ( fgGetBool("/controls/switches/master-bat") ) {
321         volts = 24.0;
322     }
323     if ( fgGetBool("/controls/switches/master-alt") &&
324          fgGetDouble("/engines/engine[0]/rpm") > 800 )
325     {
326         double alt_contrib = 28.0;
327         if ( alt_contrib > volts ) {
328             volts = alt_contrib;
329         }
330     }
331     _volts_out->setDoubleValue( volts );
332
333     // impliment an extremely simplistic amps model (assumes certain
334     // naming conventions in the electrical system config) ... FIXME:
335     // make this more generic
336     double amps = 0.0;
337     if ( fgGetBool("/controls/switches/master-bat") ) {
338         if ( fgGetBool("/controls/switches/master-alt") &&
339              fgGetDouble("/engines/engine[0]/rpm") > 800 )
340         {
341             amps += 40.0 * alt_norm;
342         }
343         amps -= 15.0;            // normal load
344         if ( fgGetBool("/controls/switches/flashing-beacon") ) {
345             amps -= 7.5;
346         }
347         if ( fgGetBool("/controls/switches/nav-lights") ) {
348             amps -= 7.5;
349         }
350         if ( amps > 7.0 ) {
351             amps = 7.0;
352         }
353     }
354     _amps_out->setDoubleValue( amps );
355 }
356
357
358 bool FGElectricalSystem::build () {
359     SGPropertyNode *node;
360     int i;
361
362     int count = config_props->nChildren();
363     for ( i = 0; i < count; ++i ) {
364         node = config_props->getChild(i);
365         string name = node->getName();
366         // cout << name << endl;
367         if ( name == "supplier" ) {
368             FGElectricalSupplier *s =
369                 new FGElectricalSupplier( node );
370             suppliers.push_back( s );
371         } else if ( name == "bus" ) {
372             FGElectricalBus *b =
373                 new FGElectricalBus( node );
374             buses.push_back( b );
375         } else if ( name == "output" ) {
376             FGElectricalOutput *o =
377                 new FGElectricalOutput( node );
378             outputs.push_back( o );
379         } else if ( name == "connector" ) {
380             FGElectricalConnector *c =
381                 new FGElectricalConnector( node, this );
382             connectors.push_back( c );
383         } else {
384             SG_LOG( SG_ALL, SG_ALERT, "Unknown component type specified: " 
385                     << name );
386             return false;
387         }
388     }
389
390     return true;
391 }
392
393
394 // propagate the electrical current through the network
395 void FGElectricalSystem::propagate( FGElectricalComponent *node, double val,
396                                     string s ) {
397     s += " ";
398
399     // determine the current to carry forward
400     double current = 0.0;
401     if ( !fgGetBool("/systems/electrical/serviceable") ) {
402         current = 0;
403     } else if ( node->get_kind() == FG_SUPPLIER ) {
404         // cout << s << " is a supplier" << endl;
405         current = ((FGElectricalSupplier *)node)->get_output();
406     } else if ( node->get_kind() == FG_BUS ) {
407         // cout << s << " is a bus" << endl;
408         current = val;
409     } else if ( node->get_kind() == FG_OUTPUT ) {
410         // cout << s << " is an output" << endl;
411         current = val;
412     } else if ( node->get_kind() == FG_CONNECTOR ) {
413         // cout << s << " is a connector" << endl;
414         if ( ((FGElectricalConnector *)node)->get_state() ) {
415             current = val;
416         } else {
417             current = 0.0;
418         }
419         // cout << s << "  val = " << current << endl;
420     } else {
421         SG_LOG( SG_ALL, SG_ALERT, "unkown node type" );
422     }
423
424     if ( current > node->get_value() ) {
425         node->set_value( current );
426     }
427
428     int i;
429
430     // publish values to specified properties
431     for ( i = 0; i < node->get_num_props(); ++i ) {
432         fgSetDouble( node->get_prop(i).c_str(), node->get_value() );
433     }
434     // cout << s << node->get_name() << " -> " << node->get_value() << endl;
435
436     // propagate to all children
437     for ( i = 0; i < node->get_num_outputs(); ++i ) {
438         propagate( node->get_output(i), current, s );
439     }
440 }
441
442
443 // search for the named component and return a pointer to it, NULL otherwise
444 FGElectricalComponent *FGElectricalSystem::find ( const string &name ) {
445     unsigned int i;
446     string s;
447
448     // search suppliers
449     for ( i = 0; i < suppliers.size(); ++i ) {
450         s = suppliers[i]->get_name();
451         // cout <<  "    " << s << endl;
452         if ( s == name ) {
453             return suppliers[i];
454         }
455     }
456
457     // then search buses
458     for ( i = 0; i < buses.size(); ++i ) {
459         s = buses[i]->get_name();
460         // cout <<  "    " << s << endl;
461         if ( s == name ) {
462             return buses[i];
463         }
464     }
465
466     // then search outputs
467     for ( i = 0; i < outputs.size(); ++i ) {
468         s = outputs[i]->get_name();
469         // cout <<  "    " << s << endl;
470         if ( s == name ) {
471             return outputs[i];
472         }
473     }
474
475     // nothing found
476     return NULL;
477 }