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