]> git.mxchange.org Git - flightgear.git/blob - src/Systems/electrical.cxx
Fixed a spelling error in the api. (ouch) :-)
[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/misc/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
60     int i;
61     for ( i = 0; i < node->nChildren(); ++i ) {
62         SGPropertyNode *child = node->getChild(i);
63         // cout << " scanning: " << child->getName() << endl;
64         if ( (string)child->getName() == "prop" ) {
65             string prop = child->getStringValue();
66             // cout << "  Adding prop = " << prop << endl;
67             add_prop( prop );
68             fgSetDouble( prop.c_str(), amps );
69         }
70     }
71
72     _rpm_node = fgGetNode("/engines/engine[0]/rpm", true);
73 }  
74
75
76 double FGElectricalSupplier::get_output() {
77     if ( model == FG_BATTERY ) {
78         // cout << "battery amps = " << amps << endl;
79         return amps;
80     } else if ( model == FG_ALTERNATOR ) {
81         // scale alternator output for rpms < 600.  For rpms >= 600
82         // give full output.  This is just a WAG, and probably not how
83         // it really works but I'm keeping things "simple" to start.
84         double rpm = _rpm_node->getDoubleValue();
85         double factor = rpm / 600.0;
86         if ( factor > 1.0 ) {
87             factor = 1.0;
88         }
89         // cout << "alternator amps = " << amps * factor << endl;
90         return amps * factor;
91     } else if ( model == FG_EXTERNAL ) {
92         // cout << "external amps = " << 0.0 << endl;
93         return 0.0;
94     } else {
95         SG_LOG( SG_ALL, SG_ALERT, "unknown supplier type" );
96     }
97
98     return 0.0;
99 }
100
101
102 FGElectricalBus::FGElectricalBus ( SGPropertyNode *node ) {
103     kind = FG_BUS;
104
105     name = node->getStringValue("name");
106     int i;
107     for ( i = 0; i < node->nChildren(); ++i ) {
108         SGPropertyNode *child = node->getChild(i);
109         if ( (string)child->getName() == "prop" ) {
110             string prop = child->getStringValue();
111             add_prop( prop );
112         }
113     }
114 }  
115
116
117 FGElectricalOutput::FGElectricalOutput ( SGPropertyNode *node ) {
118     kind = FG_OUTPUT;
119
120     name = node->getStringValue("name");
121     int i;
122     for ( i = 0; i < node->nChildren(); ++i ) {
123         SGPropertyNode *child = node->getChild(i);
124         if ( (string)child->getName() == "prop" ) {
125             string prop = child->getStringValue();
126             add_prop( prop );
127         }
128     }
129 }  
130
131
132 FGElectricalConnector::FGElectricalConnector ( SGPropertyNode *node,
133                                                FGElectricalSystem *es ) {
134     kind = FG_CONNECTOR;
135     name = "connector";
136     int i;
137     for ( i = 0; i < node->nChildren(); ++i ) {
138         SGPropertyNode *child = node->getChild(i);
139         string cname = child->getName();
140         string cval = child->getStringValue();
141         // cout << "  " << cname << " = " << cval << endl;
142         if ( cname == "input" ) {
143             FGElectricalComponent *s = es->find( child->getStringValue() );
144             if ( s != NULL ) {
145                 add_input( s );
146                 if ( s->get_kind() == FG_SUPPLIER ) {
147                     s->add_output( this );
148                 } else if ( s->get_kind() == FG_BUS ) {
149                     s->add_output( this );
150                 } else {
151                     SG_LOG( SG_ALL, SG_ALERT,
152                             "Attempt to connect to something that can't provide an output: " 
153                             << child->getStringValue() );
154                 }
155             } else {
156                 SG_LOG( SG_ALL, SG_ALERT, "Can't find named source: " 
157                         << child->getStringValue() );
158             }
159         } else if ( cname == "output" ) {
160             FGElectricalComponent *s = es->find( child->getStringValue() );
161             if ( s != NULL ) {
162                 add_output( s );
163                 if ( s->get_kind() == FG_BUS ) {
164                     s->add_input( this );
165                 } else if ( s->get_kind() == FG_OUTPUT ) {
166                     s->add_input( this );
167                 } else {
168                     SG_LOG( SG_ALL, SG_ALERT,
169                             "Attempt to connect to something that can't provide an input: " 
170                             << child->getStringValue() );
171                 }
172             } else {
173                 SG_LOG( SG_ALL, SG_ALERT, "Can't find named source: " 
174                         << child->getStringValue() );
175             }
176         } else if ( cname == "switch" ) {
177             // set default value of switch to true
178             // cout << "Switch = " << child->getStringValue() << endl;
179             fgSetBool( child->getStringValue(), true );
180             add_switch( fgGetNode( child->getStringValue(), true ) );
181         }
182     }
183
184     // do a 2nd pass to pick up starting switch value if specified
185     for ( i = 0; i < node->nChildren(); ++i ) {
186         SGPropertyNode *child = node->getChild(i);
187         string cname = child->getName();
188         string cval = child->getStringValue();
189         // cout << "  " << cname << " = " << cval << endl;
190         if ( cname == "initial-state" ) {
191             if ( cval == "off" ) {
192                 set_switches( false );
193             } else {
194                 set_switches( true );
195             }
196         }
197     }
198 }  
199
200
201 // set all switches to the specified state
202 void FGElectricalConnector::set_switches( bool state ) {
203     cout << "setting switch state to " << state << endl;
204     for ( unsigned int i = 0; i < switches.size(); ++i ) {
205         switches[i]->setBoolValue( state );
206     }
207 }
208
209
210 // return true if all switches are true, false otherwise.  A connector
211 // could have multiple switches, but they all need to be true(closed)
212 // for current to get through.
213 bool FGElectricalConnector::get_state() {
214     unsigned int i;
215     for ( i = 0; i < switches.size(); ++i ) {
216         if ( ! switches[i]->getBoolValue() ) {
217             return false;
218         }
219     }
220
221     return true;
222 }
223
224
225 FGElectricalSystem::FGElectricalSystem () :
226     enabled(false)
227 {
228 }
229
230
231 FGElectricalSystem::~FGElectricalSystem () {
232 }
233
234
235 void FGElectricalSystem::init () {
236     config_props = new SGPropertyNode;
237
238     SGPropertyNode *path_n = fgGetNode("/sim/systems/electrical/path");
239
240     if (path_n) {
241         SGPath config( globals->get_fg_root() );
242         config.append( path_n->getStringValue() );
243
244         SG_LOG( SG_ALL, SG_ALERT, "Reading electrical system model from "
245                 << config.str() );
246         try {
247             readProperties( config.str(), config_props );
248
249             if ( build() ) {
250                 enabled = true;
251             } else {
252                 SG_LOG( SG_ALL, SG_ALERT,
253                         "Detected an internal inconsistancy in the electrical");
254                 SG_LOG( SG_ALL, SG_ALERT,
255                         " system specification file.  See earlier errors for" );
256                 SG_LOG( SG_ALL, SG_ALERT,
257                         " details.");
258                 exit(-1);
259             }        
260         } catch (const sg_exception& exc) {
261             SG_LOG( SG_ALL, SG_ALERT, "Failed to load electrical system model: "
262                     << config.str() );
263         }
264
265     } else
266         SG_LOG( SG_ALL, SG_ALERT,
267                 "No electrical model specified for this model!");
268
269     delete config_props;
270 }
271
272
273 void FGElectricalSystem::bind () {
274 }
275
276
277 void FGElectricalSystem::unbind () {
278 }
279
280
281 void FGElectricalSystem::update (double dt) {
282     if ( !enabled ) {
283         return;
284     }
285
286     // cout << "Updating electrical system" << endl;
287
288     unsigned int i;
289
290     // zero everything out before we start
291     for ( i = 0; i < suppliers.size(); ++i ) {
292         suppliers[i]->set_value( 0.0 );
293     }
294     for ( i = 0; i < buses.size(); ++i ) {
295         buses[i]->set_value( 0.0 );
296     }
297     for ( i = 0; i < outputs.size(); ++i ) {
298         outputs[i]->set_value( 0.0 );
299     }
300     for ( i = 0; i < connectors.size(); ++i ) {
301         connectors[i]->set_value( 0.0 );
302     }
303
304     // for each supplier, propagate the electrical current
305     for ( i = 0; i < suppliers.size(); ++i ) {
306         // cout << " Updating: " << suppliers[i]->get_name() << endl;
307         propagate( suppliers[i], 0.0, " " );
308     }
309
310 }
311
312
313 bool FGElectricalSystem::build () {
314     SGPropertyNode *node;
315     int i;
316
317     int count = config_props->nChildren();
318     for ( i = 0; i < count; ++i ) {
319         node = config_props->getChild(i);
320         string name = node->getName();
321         // cout << name << endl;
322         if ( name == "supplier" ) {
323             FGElectricalSupplier *s =
324                 new FGElectricalSupplier( node );
325             suppliers.push_back( s );
326         } else if ( name == "bus" ) {
327             FGElectricalBus *b =
328                 new FGElectricalBus( node );
329             buses.push_back( b );
330         } else if ( name == "output" ) {
331             FGElectricalOutput *o =
332                 new FGElectricalOutput( node );
333             outputs.push_back( o );
334         } else if ( name == "connector" ) {
335             FGElectricalConnector *c =
336                 new FGElectricalConnector( node, this );
337             connectors.push_back( c );
338         } else {
339             SG_LOG( SG_ALL, SG_ALERT, "Unknown component type specified: " 
340                     << name );
341             return false;
342         }
343     }
344
345     return true;
346 }
347
348
349 // propagate the electrical current through the network
350 void FGElectricalSystem::propagate( FGElectricalComponent *node, double val,
351                                     string s ) {
352     s += " ";
353
354     // determine the current to carry forward
355     double current = 0.0;
356     if ( !fgGetBool("/systems/electrical/serviceable") ) {
357         current = 0;
358     } else if ( node->get_kind() == FG_SUPPLIER ) {
359         // cout << s << " is a supplier" << endl;
360         current = ((FGElectricalSupplier *)node)->get_output();
361     } else if ( node->get_kind() == FG_BUS ) {
362         // cout << s << " is a bus" << endl;
363         current = val;
364     } else if ( node->get_kind() == FG_OUTPUT ) {
365         // cout << s << " is an output" << endl;
366         current = val;
367     } else if ( node->get_kind() == FG_CONNECTOR ) {
368         // cout << s << " is a connector" << endl;
369         if ( ((FGElectricalConnector *)node)->get_state() ) {
370             current = val;
371         } else {
372             current = 0.0;
373         }
374         // cout << s << "  val = " << current << endl;
375     } else {
376         SG_LOG( SG_ALL, SG_ALERT, "unkown node type" );
377     }
378
379     if ( current > node->get_value() ) {
380         node->set_value( current );
381     }
382
383     int i;
384
385     // publish values to specified properties
386     for ( i = 0; i < node->get_num_props(); ++i ) {
387         fgSetDouble( node->get_prop(i).c_str(), node->get_value() );
388     }
389     // cout << s << node->get_name() << " -> " << node->get_value() << endl;
390
391     // propagate to all children
392     for ( i = 0; i < node->get_num_outputs(); ++i ) {
393         propagate( node->get_output(i), current, s );
394     }
395 }
396
397
398 // search for the named component and return a pointer to it, NULL otherwise
399 FGElectricalComponent *FGElectricalSystem::find ( const string &name ) {
400     unsigned int i;
401     string s;
402
403     // search suppliers
404     for ( i = 0; i < suppliers.size(); ++i ) {
405         s = suppliers[i]->get_name();
406         // cout <<  "    " << s << endl;
407         if ( s == name ) {
408             return suppliers[i];
409         }
410     }
411
412     // then search buses
413     for ( i = 0; i < buses.size(); ++i ) {
414         s = buses[i]->get_name();
415         // cout <<  "    " << s << endl;
416         if ( s == name ) {
417             return buses[i];
418         }
419     }
420
421     // then search outputs
422     for ( i = 0; i < outputs.size(); ++i ) {
423         s = outputs[i]->get_name();
424         // cout <<  "    " << s << endl;
425         if ( s == name ) {
426             return outputs[i];
427         }
428     }
429
430     // nothing found
431     return NULL;
432 }