]> git.mxchange.org Git - flightgear.git/blob - src/Systems/electrical.cxx
- Added ultra-light traffic is now a separate traffic class that can have its
[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  - http://www.flightgear.org/~curt
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23 #ifdef HAVE_CONFIG_H
24 #  include <config.h>
25 #endif
26
27 #include <simgear/structure/exception.hxx>
28 #include <simgear/misc/sg_path.hxx>
29
30 #include <Main/fg_props.hxx>
31 #include <Main/globals.hxx>
32
33 #include "electrical.hxx"
34
35
36 FGElectricalComponent::FGElectricalComponent() :
37     kind(-1),
38     name(""),
39     volts(0.0),
40     load_amps(0.0)
41 {
42 }
43
44
45 FGElectricalSupplier::FGElectricalSupplier ( SGPropertyNode *node ) {
46     kind = FG_SUPPLIER;
47
48     // cout << "Creating a supplier" << endl;
49     name = node->getStringValue("name");
50     string _model = node->getStringValue("kind");
51     // cout << "_model = " << _model << endl;
52     if ( _model == "battery" ) {
53         model = FG_BATTERY;
54         amp_hours = node->getFloatValue("amp-hours", 40.0);
55         percent_remaining = node->getFloatValue("percent-remaining", 1.0);
56         charge_amps = node->getFloatValue("charge-amps", 7.0);
57     } else if ( _model == "alternator" ) {
58         model = FG_ALTERNATOR;
59         rpm_src = node->getStringValue("rpm-source");
60         rpm_threshold = node->getFloatValue("rpm-threshold", 600.0);
61         ideal_amps = node->getFloatValue("amps", 60.0);
62     } else if ( _model == "external" ) {
63         model = FG_EXTERNAL;
64         ideal_amps = node->getFloatValue("amps", 60.0);
65     } else {
66         model = FG_UNKNOWN;
67     }
68     ideal_volts = node->getFloatValue("volts");
69
70     int i;
71     for ( i = 0; i < node->nChildren(); ++i ) {
72         SGPropertyNode *child = node->getChild(i);
73         // cout << " scanning: " << child->getName() << endl;
74         if ( !strcmp(child->getName(), "prop") ) {
75             string prop = child->getStringValue();
76             // cout << "  Adding prop = " << prop << endl;
77             add_prop( prop );
78             fgSetFloat( prop.c_str(), ideal_amps );
79         }
80     }
81
82     _rpm_node = fgGetNode( rpm_src.c_str(), true);
83 }  
84
85
86 float FGElectricalSupplier::apply_load( float amps, float dt ) {
87     if ( model == FG_BATTERY ) {
88         // calculate amp hours used
89         float amphrs_used = amps * dt / 3600.0;
90
91         // calculate percent of total available capacity
92         float percent_used = amphrs_used / amp_hours;
93         percent_remaining -= percent_used;
94         if ( percent_remaining < 0.0 ) {
95             percent_remaining = 0.0;
96         } else if ( percent_remaining > 1.0 ) {
97             percent_remaining = 1.0;
98         }
99         // cout << "battery percent = " << percent_remaining << endl;
100         return amp_hours * percent_remaining;
101     } else if ( model == FG_ALTERNATOR ) {
102         // scale alternator output for rpms < 600.  For rpms >= 600
103         // give full output.  This is just a WAG, and probably not how
104         // it really works but I'm keeping things "simple" to start.
105         float rpm = _rpm_node->getFloatValue();
106         float factor = rpm / rpm_threshold;
107         if ( factor > 1.0 ) {
108             factor = 1.0;
109         }
110         // cout << "alternator amps = " << amps * factor << endl;
111         float available_amps = ideal_amps * factor;
112         return available_amps - amps;
113     } else if ( model == FG_EXTERNAL ) {
114         // cout << "external amps = " << 0.0 << endl;
115         float available_amps = ideal_amps;
116         return available_amps - amps;
117     } else {
118         SG_LOG( SG_ALL, SG_ALERT, "unknown supplier type" );
119     }
120
121     return 0.0;
122 }
123
124
125 float FGElectricalSupplier::get_output_volts() {
126     if ( model == FG_BATTERY ) {
127         // cout << "battery amps = " << amps << endl;
128         float x = 1.0 - percent_remaining;
129         float tmp = -(3.0 * x - 1.0);
130         float factor = (tmp*tmp*tmp*tmp*tmp + 32) / 32;
131         // cout << "battery % = " << percent_remaining <<
132         //         " factor = " << factor << endl;
133         // percent_remaining -= 0.001;
134         return ideal_volts * factor;
135     } else if ( model == FG_ALTERNATOR ) {
136         // scale alternator output for rpms < 600.  For rpms >= 600
137         // give full output.  This is just a WAG, and probably not how
138         // it really works but I'm keeping things "simple" to start.
139         float rpm = _rpm_node->getFloatValue();
140         float factor = rpm / rpm_threshold;
141         if ( factor > 1.0 ) {
142             factor = 1.0;
143         }
144         // cout << "alternator amps = " << amps * factor << endl;
145         return ideal_volts * factor;
146     } else if ( model == FG_EXTERNAL ) {
147         // cout << "external amps = " << 0.0 << endl;
148         return ideal_volts;
149     } else {
150         SG_LOG( SG_ALL, SG_ALERT, "unknown supplier type" );
151     }
152
153     return 0.0;
154 }
155
156
157 float FGElectricalSupplier::get_output_amps() {
158     if ( model == FG_BATTERY ) {
159         // cout << "battery amp_hours = " << amp_hours << endl;
160
161         // This is a WAG, but produce enough amps to burn the entire
162         // battery in one minute.
163         return amp_hours * 60.0;
164     } else if ( model == FG_ALTERNATOR ) {
165         // scale alternator output for rpms < 600.  For rpms >= 600
166         // give full output.  This is just a WAG, and probably not how
167         // it really works but I'm keeping things "simple" to start.
168         float rpm = _rpm_node->getFloatValue();
169         float factor = rpm / rpm_threshold;
170         if ( factor > 1.0 ) {
171             factor = 1.0;
172         }
173         // cout << "alternator amps = " << ideal_amps * factor << endl;
174         return ideal_amps * factor;
175     } else if ( model == FG_EXTERNAL ) {
176         // cout << "external amps = " << 0.0 << endl;
177         return ideal_amps;
178     } else {
179         SG_LOG( SG_ALL, SG_ALERT, "unknown supplier type" );
180     }
181
182     return 0.0;
183 }
184
185
186 FGElectricalBus::FGElectricalBus ( SGPropertyNode *node ) {
187     kind = FG_BUS;
188
189     name = node->getStringValue("name");
190     int i;
191     for ( i = 0; i < node->nChildren(); ++i ) {
192         SGPropertyNode *child = node->getChild(i);
193         if ( !strcmp(child->getName(), "prop") ) {
194             string prop = child->getStringValue();
195             add_prop( prop );
196         }
197     }
198 }  
199
200
201 FGElectricalOutput::FGElectricalOutput ( SGPropertyNode *node ) {
202     kind = FG_OUTPUT;
203     load_amps = 0.1;            // arbitrary default value
204
205     name = node->getStringValue("name");
206     SGPropertyNode *draw = node->getNode("rated-draw");
207     if ( draw != NULL ) {
208         load_amps = draw->getFloatValue();
209     }
210     // cout << "rated draw = " << output_amps << endl;
211
212     int i;
213     for ( i = 0; i < node->nChildren(); ++i ) {
214         SGPropertyNode *child = node->getChild(i);
215         if ( !strcmp(child->getName(), "prop") ) {
216             string prop = child->getStringValue();
217             add_prop( prop );
218         }
219     }
220 }  
221
222
223 FGElectricalSwitch::FGElectricalSwitch( SGPropertyNode *node ) :
224     switch_node( NULL ),
225     rating_amps( 0.0f ),
226     circuit_breaker( false )
227 {
228     bool initial_state = true;
229     int i;
230     for ( i = 0; i < node->nChildren(); ++i ) {
231         SGPropertyNode *child = node->getChild(i);
232         string cname = child->getName();
233         string cval = child->getStringValue();
234         if ( cname == "prop" ) {
235             switch_node = fgGetNode( cval.c_str(), true );
236             // cout << "switch node = " << cval << endl;
237         } else if ( cname == "initial-state" ) {
238             if ( cval == "off" || cval == "false" ) {
239                 initial_state = false;
240             }
241             // cout << "initial state = " << initial_state << endl;
242         } else if ( cname == "rating-amps" ) {
243             rating_amps = atof( cval.c_str() );
244             circuit_breaker = true;
245             // cout << "initial state = " << initial_state << endl;
246         }            
247     }
248
249     switch_node->setBoolValue( initial_state );
250     // cout << "  value = " << switch_node->getBoolValue() << endl;
251 }
252
253
254 FGElectricalConnector::FGElectricalConnector ( SGPropertyNode *node,
255                                                FGElectricalSystem *es ) {
256     kind = FG_CONNECTOR;
257     name = "connector";
258     int i;
259     for ( i = 0; i < node->nChildren(); ++i ) {
260         SGPropertyNode *child = node->getChild(i);
261         string cname = child->getName();
262         string cval = child->getStringValue();
263         // cout << "  " << cname << " = " << cval << endl;
264         if ( cname == "input" ) {
265             FGElectricalComponent *s = es->find( child->getStringValue() );
266             if ( s != NULL ) {
267                 add_input( s );
268                 if ( s->get_kind() == FG_SUPPLIER ) {
269                     s->add_output( this );
270                 } else if ( s->get_kind() == FG_BUS ) {
271                     s->add_output( this );
272                 } else {
273                     SG_LOG( SG_ALL, SG_ALERT,
274                             "Attempt to connect to something that can't provide an output: " 
275                             << child->getStringValue() );
276                 }
277             } else {
278                 SG_LOG( SG_ALL, SG_ALERT, "Can't find named source: " 
279                         << child->getStringValue() );
280             }
281         } else if ( cname == "output" ) {
282             FGElectricalComponent *s = es->find( child->getStringValue() );
283             if ( s != NULL ) {
284                 add_output( s );
285                 if ( s->get_kind() == FG_BUS ) {
286                     s->add_input( this );
287                 } else if ( s->get_kind() == FG_OUTPUT ) {
288                     s->add_input( this );
289                 } else if ( s->get_kind() == FG_SUPPLIER &&
290                             ((FGElectricalSupplier *)s)->get_model()
291                             == FGElectricalSupplier::FG_BATTERY ) {
292                     s->add_output( this );
293                 } else {
294                     SG_LOG( SG_ALL, SG_ALERT,
295                             "Attempt to connect to something that can't provide an input: " 
296                             << child->getStringValue() );
297                 }
298             } else {
299                 SG_LOG( SG_ALL, SG_ALERT, "Can't find named source: " 
300                         << child->getStringValue() );
301             }
302         } else if ( cname == "switch" ) {
303              // cout << "Switch = " << child->getStringValue() << endl;
304             FGElectricalSwitch s( child );
305             add_switch( s );
306         }
307     }
308 }  
309
310
311 // set all switches to the specified state
312 void FGElectricalConnector::set_switches( bool state ) {
313     // cout << "setting switch state to " << state << endl;
314     for ( unsigned int i = 0; i < switches.size(); ++i ) {
315         switches[i].set_state( state );
316     }
317 }
318
319
320 // return true if all switches are true, false otherwise.  A connector
321 // could have multiple switches, but they all need to be true(closed)
322 // for current to get through.
323 bool FGElectricalConnector::get_state() {
324     unsigned int i;
325     for ( i = 0; i < switches.size(); ++i ) {
326         if ( ! switches[i].get_state() ) {
327             return false;
328         }
329     }
330
331     return true;
332 }
333
334
335 FGElectricalSystem::FGElectricalSystem ( SGPropertyNode *node ) :
336     name(node->getStringValue("name", "electrical")),
337     num(node->getIntValue("number", 0)),
338     path(node->getStringValue("path")),
339     enabled(false)
340 {
341 }
342
343
344 FGElectricalSystem::~FGElectricalSystem () {
345 }
346
347
348 void FGElectricalSystem::init () {
349     config_props = new SGPropertyNode;
350
351     _volts_out = fgGetNode( "/systems/electrical/volts", true );
352     _amps_out = fgGetNode( "/systems/electrical/amps", true );
353
354     // allow the electrical system to be specified via the
355     // aircraft-set.xml file (for backwards compatibility) or through
356     // the aircraft-systems.xml file.  If a -set.xml entry is
357     // specified, that overrides the system entry.
358     SGPropertyNode *path_n = fgGetNode("/sim/systems/electrical/path");
359     if ( path_n ) {
360         if ( path.length() ) {
361             SG_LOG( SG_ALL, SG_INFO,
362                     "NOTICE: System manager configuration specifies an " <<
363                     "electrical system: " << path << " but it is " <<
364                     "being overridden by the one specified in the -set.xml " <<
365                     "file: " << path_n->getStringValue() );
366         }
367
368         path = path_n->getStringValue();
369     }
370
371     if ( path.length() ) {
372         SGPath config( globals->get_fg_root() );
373         config.append( path );
374
375         // load an obsolete xml configuration
376         SG_LOG( SG_ALL, SG_WARN,
377                 "Reading deprecated xml electrical system model from\n    "
378                 << config.str() );
379         try {
380             readProperties( config.str(), config_props );
381
382             if ( build() ) {
383                 enabled = true;
384             } else {
385                 SG_LOG( SG_ALL, SG_ALERT,
386                         "Detected a logic error in the electrical system ");
387                 SG_LOG( SG_ALL, SG_ALERT,
388                         "specification file.  See earlier errors for " );
389                 SG_LOG( SG_ALL, SG_ALERT,
390                         "details.");
391                 exit(-1);
392             }        
393         } catch (const sg_exception& exc) {
394             SG_LOG( SG_ALL, SG_ALERT,
395                     "Failed to load electrical system model: "
396                     << config.str() );
397         }
398     } else {
399         SG_LOG( SG_ALL, SG_INFO,
400                 "No xml-based electrical model specified for this model!");
401     }
402
403     if ( !enabled ) {
404         _amps_out->setDoubleValue(0);
405     }
406
407     delete config_props;
408 }
409
410
411 void FGElectricalSystem::bind () {
412 }
413
414
415 void FGElectricalSystem::unbind () {
416 }
417
418
419 void FGElectricalSystem::update (double dt) {
420     if ( !enabled ) {
421         return;
422     }
423
424     // cout << "Updating electrical system, dt = " << dt << endl;
425
426     unsigned int i;
427
428     // zero out the voltage before we start, but don't clear the
429     // requested load values.
430     for ( i = 0; i < suppliers.size(); ++i ) {
431         suppliers[i]->set_volts( 0.0 );
432     }
433     for ( i = 0; i < buses.size(); ++i ) {
434         buses[i]->set_volts( 0.0 );
435     }
436     for ( i = 0; i < outputs.size(); ++i ) {
437         outputs[i]->set_volts( 0.0 );
438     }
439     for ( i = 0; i < connectors.size(); ++i ) {
440         connectors[i]->set_volts( 0.0 );
441     }
442
443     // for each "external" supplier, propagate the electrical current
444     for ( i = 0; i < suppliers.size(); ++i ) {
445         FGElectricalSupplier *node = (FGElectricalSupplier *)suppliers[i];
446         if ( node->get_model() == FGElectricalSupplier::FG_EXTERNAL ) {
447             float load;
448             // cout << "Starting propagation: " << suppliers[i]->get_name()
449             //      << endl;
450             load = propagate( suppliers[i], dt,
451                               node->get_output_volts(),
452                               node->get_output_amps(),
453                               " " );
454
455             if ( node->apply_load( load, dt ) < 0.0 ) {
456                 cout << "Error drawing more current than available!" << endl;
457             }
458         }     
459     }
460
461     // for each "alternator" supplier, propagate the electrical
462     // current
463     for ( i = 0; i < suppliers.size(); ++i ) {
464         FGElectricalSupplier *node = (FGElectricalSupplier *)suppliers[i];
465         if ( node->get_model() == FGElectricalSupplier::FG_ALTERNATOR) {
466             float load;
467             // cout << "Starting propagation: " << suppliers[i]->get_name()
468             //      << endl;
469             load = propagate( suppliers[i], dt,
470                               node->get_output_volts(),
471                               node->get_output_amps(),
472                               " " );
473
474             if ( node->apply_load( load, dt ) < 0.0 ) {
475                 cout << "Error drawing more current than available!" << endl;
476             }
477         }     
478     }
479
480     // for each "battery" supplier, propagate the electrical
481     // current
482     for ( i = 0; i < suppliers.size(); ++i ) {
483         FGElectricalSupplier *node = (FGElectricalSupplier *)suppliers[i];
484         if ( node->get_model() == FGElectricalSupplier::FG_BATTERY ) {
485             float load;
486             // cout << "Starting propagation: " << suppliers[i]->get_name()
487             //      << endl;
488             load = propagate( suppliers[i], dt,
489                               node->get_output_volts(),
490                               node->get_output_amps(),
491                               " " );
492             // cout << "battery load = " << load << endl;
493
494             if ( node->apply_load( load, dt ) < 0.0 ) {
495                 cout << "Error drawing more current than available!" << endl;
496             }
497         }     
498     }
499
500     float alt_norm
501         = fgGetFloat("/systems/electrical/suppliers/alternator") / 60.0;
502
503     // impliment an extremely simplistic voltage model (assumes
504     // certain naming conventions in electrical system config)
505     // FIXME: we probably want to be able to feed power from all
506     // engines if they are running and the master-alt is switched on
507     float volts = 0.0;
508     if ( fgGetBool("/controls/engines/engine[0]/master-bat") ) {
509         volts = 24.0;
510     }
511     if ( fgGetBool("/controls/engines/engine[0]/master-alt") ) {
512         if ( fgGetFloat("/engines/engine[0]/rpm") > 800 ) {
513             float alt_contrib = 28.0;
514             if ( alt_contrib > volts ) {
515                 volts = alt_contrib;
516             }
517         } else if ( fgGetFloat("/engines/engine[0]/rpm") > 200 ) {
518             float alt_contrib = 20.0;
519             if ( alt_contrib > volts ) {
520                 volts = alt_contrib;
521             }
522         }
523     }
524     _volts_out->setFloatValue( volts );
525
526     // impliment an extremely simplistic amps model (assumes certain
527     // naming conventions in the electrical system config) ... FIXME:
528     // make this more generic
529     float amps = 0.0;
530     if ( fgGetBool("/controls/engines/engine[0]/master-bat") ) {
531         if ( fgGetBool("/controls/engines/engine[0]/master-alt") &&
532              fgGetFloat("/engines/engine[0]/rpm") > 800 )
533         {
534             amps += 40.0 * alt_norm;
535         }
536         amps -= 15.0;            // normal load
537         if ( fgGetBool("/controls/switches/flashing-beacon") ) {
538             amps -= 7.5;
539         }
540         if ( fgGetBool("/controls/switches/nav-lights") ) {
541             amps -= 7.5;
542         }
543         if ( amps > 7.0 ) {
544             amps = 7.0;
545         }
546     }
547     _amps_out->setFloatValue( amps );
548 }
549
550
551 bool FGElectricalSystem::build () {
552     SGPropertyNode *node;
553     int i;
554
555     int count = config_props->nChildren();
556     for ( i = 0; i < count; ++i ) {
557         node = config_props->getChild(i);
558         string name = node->getName();
559         // cout << name << endl;
560         if ( name == "supplier" ) {
561             FGElectricalSupplier *s =
562                 new FGElectricalSupplier( node );
563             suppliers.push_back( s );
564         } else if ( name == "bus" ) {
565             FGElectricalBus *b =
566                 new FGElectricalBus( node );
567             buses.push_back( b );
568         } else if ( name == "output" ) {
569             FGElectricalOutput *o =
570                 new FGElectricalOutput( node );
571             outputs.push_back( o );
572         } else if ( name == "connector" ) {
573             FGElectricalConnector *c =
574                 new FGElectricalConnector( node, this );
575             connectors.push_back( c );
576         } else {
577             SG_LOG( SG_ALL, SG_ALERT, "Unknown component type specified: " 
578                     << name );
579             return false;
580         }
581     }
582
583     return true;
584 }
585
586
587 // propagate the electrical current through the network, returns the
588 // total current drawn by the children of this node.
589 float FGElectricalSystem::propagate( FGElectricalComponent *node, double dt,
590                                      float input_volts, float input_amps,
591                                      string s ) {
592     s += " ";
593     
594     float total_load = 0.0;
595
596     // determine the current to carry forward
597     float volts = 0.0;
598     if ( !fgGetBool("/systems/electrical/serviceable") ) {
599         volts = 0;
600     } else if ( node->get_kind() == FGElectricalComponent::FG_SUPPLIER ) {
601         // cout << s << "is a supplier (" << node->get_name() << ")" << endl;
602         FGElectricalSupplier *supplier = (FGElectricalSupplier *)node;
603         if ( supplier->get_model() == FGElectricalSupplier::FG_BATTERY ) {
604             // cout << s << " (and is a battery)" << endl;
605             float battery_volts = supplier->get_output_volts();
606             if ( battery_volts < (input_volts - 0.1) ) {
607                 // special handling of a battery charge condition
608                 // cout << s << "  (and is being charged) in v = "
609                 //      << input_volts << " current v = " << battery_volts
610                 //      << endl;
611                 supplier->apply_load( -supplier->get_charge_amps(), dt );
612                 return supplier->get_charge_amps();
613             }
614         }
615         volts = input_volts;
616     } else if ( node->get_kind() == FGElectricalComponent::FG_BUS ) {
617         // cout << s << "is a bus (" << node->get_name() << ")" << endl;
618         volts = input_volts;
619     } else if ( node->get_kind() == FGElectricalComponent::FG_OUTPUT ) {
620         // cout << s << "is an output (" << node->get_name() << ")" << endl;
621         volts = input_volts;
622         if ( volts > 1.0 ) {
623             // draw current if we have voltage
624             total_load = node->get_load_amps();
625         }
626     } else if ( node->get_kind() == FGElectricalComponent::FG_CONNECTOR ) {
627         // cout << s << "is a connector (" << node->get_name() << ")" << endl;
628         if ( ((FGElectricalConnector *)node)->get_state() ) {
629             volts = input_volts;
630         } else {
631             volts = 0.0;
632         }
633         // cout << s << "  input_volts = " << volts << endl;
634     } else {
635         SG_LOG( SG_ALL, SG_ALERT, "unkown node type" );
636     }
637
638     int i;
639
640     // if this node has found a stronger power source, update the
641     // value and propagate to all children
642     if ( volts > node->get_volts() ) {
643         node->set_volts( volts );
644         for ( i = 0; i < node->get_num_outputs(); ++i ) {
645             FGElectricalComponent *child = node->get_output(i);
646             // send current equal to load
647             total_load += propagate( child, dt,
648                                      volts, child->get_load_amps(),
649                                      s );
650         }
651
652         // if not an output node, register the downstream current draw
653         // (sum of all children) with this node.  If volts are zero,
654         // current draw should be zero.
655         if ( node->get_kind() != FGElectricalComponent::FG_OUTPUT ) {
656             node->set_load_amps( total_load );
657         }
658
659         node->set_available_amps( input_amps - total_load );
660
661         // publish values to specified properties
662         for ( i = 0; i < node->get_num_props(); ++i ) {
663             fgSetFloat( node->get_prop(i).c_str(), node->get_volts() );
664         }
665
666         /*
667         cout << s << node->get_name() << " -> (volts) " << node->get_volts()
668              << endl;
669         cout << s << node->get_name() << " -> (load amps) " << total_load
670              << endl;
671         cout << s << node->get_name() << " -> (input amps) " << input_amps
672              << endl;
673         cout << s << node->get_name() << " -> (extra amps) "
674              << node->get_available_amps() << endl;
675         */
676
677         return total_load;
678     } else {
679         // cout << s << "no further propagation" << endl;
680         return 0.0;
681     }
682 }
683
684
685 // search for the named component and return a pointer to it, NULL otherwise
686 FGElectricalComponent *FGElectricalSystem::find ( const string &name ) {
687     unsigned int i;
688     string s;
689
690     // search suppliers
691     for ( i = 0; i < suppliers.size(); ++i ) {
692         s = suppliers[i]->get_name();
693         // cout <<  "    " << s << endl;
694         if ( s == name ) {
695             return suppliers[i];
696         }
697     }
698
699     // then search buses
700     for ( i = 0; i < buses.size(); ++i ) {
701         s = buses[i]->get_name();
702         // cout <<  "    " << s << endl;
703         if ( s == name ) {
704             return buses[i];
705         }
706     }
707
708     // then search outputs
709     for ( i = 0; i < outputs.size(); ++i ) {
710         s = outputs[i]->get_name();
711         // cout <<  "    " << s << endl;
712         if ( s == name ) {
713             return outputs[i];
714         }
715     }
716
717     // nothing found
718     return NULL;
719 }