JSBSim Flight Dynamics Model 1.0 (23 February 2013)
An Open Source Flight Dynamics and Control Software Library in C++

FGFCSComponent.cpp

00001 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00002 
00003  Module:       FGFCSComponent.cpp
00004  Author:       Jon S. Berndt
00005  Date started: 11/1999
00006 
00007  ------------- Copyright (C) 2000 -------------
00008 
00009  This program is free software; you can redistribute it and/or modify it under
00010  the terms of the GNU Lesser General Public License as published by the Free Software
00011  Foundation; either version 2 of the License, or (at your option) any later
00012  version.
00013 
00014  This program is distributed in the hope that it will be useful, but WITHOUT
00015  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00016  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00017  details.
00018 
00019  You should have received a copy of the GNU Lesser General Public License along with
00020  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021  Place - Suite 330, Boston, MA  02111-1307, USA.
00022 
00023  Further information about the GNU Lesser General Public License can also be found on
00024  the world wide web at http://www.gnu.org.
00025 
00026 FUNCTIONAL DESCRIPTION
00027 --------------------------------------------------------------------------------
00028 
00029 HISTORY
00030 --------------------------------------------------------------------------------
00031 
00032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00033 COMMENTS, REFERENCES,  and NOTES
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 
00036 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00037 INCLUDES
00038 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
00039 
00040 #include "FGFCSComponent.h"
00041 #include "input_output/FGPropertyManager.h"
00042 #include "input_output/FGXMLElement.h"
00043 #include "math/FGPropertyValue.h"
00044 #include <iostream>
00045 #include <cstdlib>
00046 
00047 using namespace std;
00048 
00049 namespace JSBSim {
00050 
00051 static const char *IdSrc = "$Id: FGFCSComponent.cpp,v 1.35 2013/01/26 17:06:50 bcoconni Exp $";
00052 static const char *IdHdr = ID_FCSCOMPONENT;
00053 
00054 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00055 CLASS IMPLEMENTATION
00056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
00057 
00058 FGFCSComponent::FGFCSComponent(FGFCS* _fcs, Element* element) : fcs(_fcs)
00059 {
00060   Element *input_element, *clip_el;
00061   Input = Output = clipmin = clipmax = delay_time = 0.0;
00062   treenode = 0;
00063   delay = index = 0;
00064   ClipMinPropertyNode = ClipMaxPropertyNode = 0;
00065   clipMinSign = clipMaxSign = 1.0;
00066   IsOutput   = clip = false;
00067   string input, clip_string;
00068   dt = fcs->GetDt();
00069 
00070   PropertyManager = fcs->GetPropertyManager();
00071   if        (element->GetName() == string("lag_filter")) {
00072     Type = "LAG_FILTER";
00073   } else if (element->GetName() == string("lead_lag_filter")) {
00074     Type = "LEAD_LAG_FILTER";
00075   } else if (element->GetName() == string("washout_filter")) {
00076     Type = "WASHOUT_FILTER";
00077   } else if (element->GetName() == string("second_order_filter")) {
00078     Type = "SECOND_ORDER_FILTER";
00079   } else if (element->GetName() == string("integrator")) {
00080     Type = "INTEGRATOR";
00081   } else if (element->GetName() == string("summer")) {
00082     Type = "SUMMER";
00083   } else if (element->GetName() == string("pure_gain")) {
00084     Type = "PURE_GAIN";
00085   } else if (element->GetName() == string("scheduled_gain")) {
00086     Type = "SCHEDULED_GAIN";
00087   } else if (element->GetName() == string("aerosurface_scale")) {
00088     Type = "AEROSURFACE_SCALE";
00089   } else if (element->GetName() == string("switch")) {
00090     Type = "SWITCH";
00091   } else if (element->GetName() == string("kinematic")) {
00092     Type = "KINEMATIC";
00093   } else if (element->GetName() == string("deadband")) {
00094     Type = "DEADBAND";
00095   } else if (element->GetName() == string("fcs_function")) {
00096     Type = "FCS_FUNCTION";
00097   } else if (element->GetName() == string("pid")) {
00098     Type = "PID";
00099   } else if (element->GetName() == string("sensor")) {
00100     Type = "SENSOR";
00101   } else if (element->GetName() == string("accelerometer")) {
00102     Type = "ACCELEROMETER";
00103   } else if (element->GetName() == string("magnetometer")) {
00104     Type = "MAGNETOMETER";
00105   } else if (element->GetName() == string("gyro")) {
00106     Type = "GYRO";
00107   } else if (element->GetName() == string("actuator")) {
00108     Type = "ACTUATOR";
00109   } else { // illegal component in this channel
00110     Type = "UNKNOWN";
00111   }
00112 
00113   Name = element->GetAttributeValue("name");
00114 
00115   input_element = element->FindElement("input");
00116   while (input_element) {
00117     input = input_element->GetDataLine();
00118     if (input[0] == '-') {
00119       InputSigns.push_back(-1.0);
00120       input.erase(0,1);
00121     } else {
00122       InputSigns.push_back( 1.0);
00123     }
00124     FGPropertyNode* node = 0L;
00125     if (PropertyManager->HasNode(input)) {
00126       node = PropertyManager->GetNode(input);
00127       InputNodes.push_back(new FGPropertyValue( node ));
00128     } else {
00129       InputNodes.push_back(new FGPropertyValue( input,
00130                                                 PropertyManager ));
00131     }
00132     InputNames.push_back( input );
00133 
00134     input_element = element->FindNextElement("input");
00135   }
00136 
00137   Element *out_elem = element->FindElement("output");
00138   while (out_elem) {
00139     IsOutput = true;
00140     string output_node_name = out_elem->GetDataLine();
00141     FGPropertyNode* OutputNode = PropertyManager->GetNode( output_node_name, true );
00142     OutputNodes.push_back(OutputNode);
00143     if (!OutputNode) {
00144       cerr << endl << "  Unable to process property: " << output_node_name << endl;
00145       throw(string("Invalid output property name in flight control definition"));
00146     }
00147     out_elem = element->FindNextElement("output");
00148   }
00149 
00150   Element* delay_elem = element->FindElement("delay");
00151   if ( delay_elem ) {
00152     delay_time = delay_elem->GetDataAsNumber();
00153     string delayType = delay_elem->GetAttributeValue("type");
00154     if (delayType.length() > 0) {
00155       if (delayType == "time") {
00156         delay = (unsigned int)(delay_time / dt);
00157       } else if (delayType == "frames") {
00158         delay = (unsigned int)delay_time;
00159       } else {
00160         cerr << "Unallowed delay type" << endl;
00161       }
00162     } else {
00163       delay = (unsigned int)(delay_time / dt);
00164     }
00165     output_array.resize(delay);
00166     for (unsigned int i=0; i<delay; i++) output_array[i] = 0.0;
00167   }
00168 
00169   clip_el = element->FindElement("clipto");
00170   if (clip_el) {
00171     clip_string = clip_el->FindElementValue("min");
00172     if (!is_number(clip_string)) { // it's a property
00173       if (clip_string[0] == '-') {
00174         clipMinSign = -1.0;
00175         clip_string.erase(0,1);
00176       }
00177       ClipMinPropertyNode = PropertyManager->GetNode( clip_string );
00178     } else {
00179       clipmin = clip_el->FindElementValueAsNumber("min");
00180     }
00181     clip_string = clip_el->FindElementValue("max");
00182     if (!is_number(clip_string)) { // it's a property
00183       if (clip_string[0] == '-') {
00184         clipMaxSign = -1.0;
00185         clip_string.erase(0,1);
00186       }
00187       ClipMaxPropertyNode = PropertyManager->GetNode( clip_string );
00188     } else {
00189       clipmax = clip_el->FindElementValueAsNumber("max");
00190     }
00191     clip = true;
00192   }
00193 
00194   Debug(0);
00195 }
00196 
00197 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00198 
00199 FGFCSComponent::~FGFCSComponent()
00200 {
00201   Debug(1);
00202   for (unsigned int i=0; i<InputNodes.size(); i++) {
00203     delete InputNodes[i];
00204   }
00205 }
00206 
00207 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00208 
00209 void FGFCSComponent::SetOutput(void)
00210 {
00211   for (unsigned int i=0; i<OutputNodes.size(); i++) OutputNodes[i]->setDoubleValue(Output);
00212 }
00213 
00214 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00215 
00216 bool FGFCSComponent::Run(void)
00217 {
00218   return true;
00219 }
00220 
00221 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00222 
00223 void FGFCSComponent::Delay(void)
00224 {
00225   output_array[index] = Output;
00226   if ((unsigned int)index == delay-1) index = 0;
00227   else index++;
00228   Output = output_array[index];
00229 }
00230 
00231 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00232 
00233 void FGFCSComponent::Clip(void)
00234 {
00235   if (clip) {
00236     if (ClipMinPropertyNode != 0) clipmin = clipMinSign*ClipMinPropertyNode->getDoubleValue();
00237     if (ClipMaxPropertyNode != 0) clipmax = clipMaxSign*ClipMaxPropertyNode->getDoubleValue();
00238     if (Output > clipmax)      Output = clipmax;
00239     else if (Output < clipmin) Output = clipmin;
00240   }
00241 }
00242 
00243 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00244 //
00245 // The old way of naming FCS components allowed upper or lower case, spaces, etc.
00246 // but then the names were modified to fit into a property name heirarchy. This
00247 // was confusing (it wasn't done intentionally - it was a carryover from the early
00248 // design). We now support the direct naming of properties in the FCS component
00249 // name attribute. The old way is supported in code at this time, but deprecated.
00250 
00251 void FGFCSComponent::bind(void)
00252 {
00253   string tmp;
00254   if (Name.find("/") == string::npos) {
00255     tmp = "fcs/" + PropertyManager->mkPropertyName(Name, true);
00256   } else {
00257     tmp = Name;
00258   }
00259   PropertyManager->Tie( tmp, this, &FGFCSComponent::GetOutput);
00260 }
00261 
00262 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00263 //    The bitmasked value choices are as follows:
00264 //    unset: In this case (the default) JSBSim would only print
00265 //       out the normally expected messages, essentially echoing
00266 //       the config files as they are read. If the environment
00267 //       variable is not set, debug_lvl is set to 1 internally
00268 //    0: This requests JSBSim not to output any messages
00269 //       whatsoever.
00270 //    1: This value explicity requests the normal JSBSim
00271 //       startup messages
00272 //    2: This value asks for a message to be printed out when
00273 //       a class is instantiated
00274 //    4: When this value is set, a message is displayed when a
00275 //       FGModel object executes its Run() method
00276 //    8: When this value is set, various runtime state variables
00277 //       are printed out periodically
00278 //    16: When set various parameters are sanity checked and
00279 //       a message is printed out when they go out of bounds
00280 
00281 void FGFCSComponent::Debug(int from)
00282 {
00283   string propsign="";
00284 
00285   if (debug_lvl <= 0) return;
00286 
00287   if (debug_lvl & 1) { // Standard console startup message output
00288     if (from == 0) {
00289       cout << endl << "    Loading Component \"" << Name
00290                    << "\" of type: " << Type << endl;
00291 
00292       if (clip) {
00293         if (ClipMinPropertyNode != 0L) {
00294           if (clipMinSign < 0.0) propsign="-";
00295           cout << "      Minimum limit: " << propsign << ClipMinPropertyNode->GetName() << endl;
00296           propsign="";
00297         } else {
00298           cout << "      Minimum limit: " << clipmin << endl;
00299         }
00300         if (ClipMaxPropertyNode != 0L) {
00301           if (clipMaxSign < 0.0) propsign="-";
00302           cout << "      Maximum limit: " << propsign << ClipMaxPropertyNode->GetName() << endl;
00303           propsign="";
00304         } else {
00305           cout << "      Maximum limit: " << clipmax << endl;
00306         }
00307       }  
00308       if (delay > 0) cout <<"      Frame delay: " << delay
00309                                    << " frames (" << delay*dt << " sec)" << endl;
00310     }
00311   }
00312   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
00313     if (from == 0) cout << "Instantiated: FGFCSComponent" << endl;
00314     if (from == 1) cout << "Destroyed:    FGFCSComponent" << endl;
00315   }
00316   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
00317   }
00318   if (debug_lvl & 8 ) { // Runtime state variables
00319   }
00320   if (debug_lvl & 16) { // Sanity checking
00321   }
00322   if (debug_lvl & 64) {
00323     if (from == 0) { // Constructor
00324       cout << IdSrc << endl;
00325       cout << IdHdr << endl;
00326     }
00327   }
00328 }
00329 }