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