JSBSim Flight Dynamics Model  1.2.0 (05 Nov 2023)
An Open Source Flight Dynamics and Control Software Library in C++
FGGain.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Module: FGGain.cpp
4  Author: Jon S. Berndt
5  Date started: 4/2000
6 
7  ------------- Copyright (C) 2000 -------------
8 
9  This program is free software; you can redistribute it and/or modify it under
10  the terms of the GNU Lesser General Public License as published by the Free
11  Software Foundation; either version 2 of the License, or (at your option) any
12  later version.
13 
14  This program is distributed in the hope that it will be useful, but WITHOUT
15  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
17  details.
18 
19  You should have received a copy of the GNU Lesser General Public License along
20  with this program; if not, write to the Free Software Foundation, Inc., 59
21  Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23  Further information about the GNU Lesser General Public License can also be
24  found on the world wide web at http://www.gnu.org.
25 
26 FUNCTIONAL DESCRIPTION
27 --------------------------------------------------------------------------------
28 
29 HISTORY
30 --------------------------------------------------------------------------------
31 
32 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33 COMMENTS, REFERENCES, and NOTES
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 
36 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37 INCLUDES
38 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
39 
40 #include "FGGain.h"
41 #include "models/FGFCS.h"
42 #include "math/FGParameterValue.h"
43 #include "math/FGTable.h"
44 
45 using namespace std;
46 
47 namespace JSBSim {
48 
49 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
50 CLASS IMPLEMENTATION
51 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
52 
53 FGGain::FGGain(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
54 {
55  Gain = nullptr;
56  Table = nullptr;
57  InMin = -1.0;
58  InMax = 1.0;
59  OutMin = OutMax = 0.0;
60 
61  CheckInputNodes(1, 1, element);
62 
63  if (Type == "PURE_GAIN") {
64  if ( !element->FindElement("gain") ) {
65  cerr << element->ReadFrom()
66  << highint << " No GAIN specified (default: 1.0)" << normint
67  << endl;
68  }
69  }
70 
71  auto PropertyManager = fcs->GetPropertyManager();
72  Element* gain_element = element->FindElement("gain");
73  if (gain_element)
74  Gain = new FGParameterValue(gain_element, PropertyManager);
75  else
76  Gain = new FGRealValue(1.0);
77 
78  if (Type == "AEROSURFACE_SCALE") {
79  Element* scale_element = element->FindElement("domain");
80  if (scale_element) {
81  if (scale_element->FindElement("max") && scale_element->FindElement("min") )
82  {
83  InMax = scale_element->FindElementValueAsNumber("max");
84  InMin = scale_element->FindElementValueAsNumber("min");
85  }
86  }
87  scale_element = element->FindElement("range");
88  if (!scale_element)
89  throw(string("No range supplied for aerosurface scale component"));
90  if (scale_element->FindElement("max") && scale_element->FindElement("min") )
91  {
92  OutMax = scale_element->FindElementValueAsNumber("max");
93  OutMin = scale_element->FindElementValueAsNumber("min");
94  } else {
95  cerr << scale_element->ReadFrom()
96  << "Maximum and minimum output values must be supplied for the "
97  "aerosurface scale component" << endl;
98  throw("Some inputs are missing.");
99  }
100  ZeroCentered = true;
101  Element* zero_centered = element->FindElement("zero_centered");
102  //ToDo if zero centered, then mins must be <0 and max's must be >0
103  if (zero_centered) {
104  string sZeroCentered = element->FindElementValue("zero_centered");
105  if (sZeroCentered == string("0") || sZeroCentered == string("false")) {
106  ZeroCentered = false;
107  }
108  }
109  }
110 
111  if (Type == "SCHEDULED_GAIN") {
112  if (element->FindElement("table")) {
113  Table = new FGTable(PropertyManager, element->FindElement("table"));
114  } else {
115  cerr << element->ReadFrom()
116  << "A table must be provided for the scheduled gain component"
117  << endl;
118  throw("Some inputs are missing.");
119  }
120  }
121 
122  bind(element, PropertyManager.get());
123 
124  Debug(0);
125 }
126 
127 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
128 
129 FGGain::~FGGain()
130 {
131  delete Table;
132 
133  Debug(1);
134 }
135 
136 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
137 
138 bool FGGain::Run(void )
139 {
140  Input = InputNodes[0]->getDoubleValue();
141 
142  if (Type == "PURE_GAIN") { // PURE_GAIN
143 
144  Output = Gain * Input;
145 
146  } else if (Type == "SCHEDULED_GAIN") { // SCHEDULED_GAIN
147 
148  double SchedGain = Table->GetValue();
149  Output = Gain * SchedGain * Input;
150 
151  } else if (Type == "AEROSURFACE_SCALE") { // AEROSURFACE_SCALE
152 
153  if (ZeroCentered) {
154  if (Input == 0.0) {
155  Output = 0.0;
156  } else if (Input > 0) {
157  Output = (Input / InMax) * OutMax;
158  } else {
159  Output = (Input / InMin) * OutMin;
160  }
161  } else {
162  Output = OutMin + ((Input - InMin) / (InMax - InMin)) * (OutMax - OutMin);
163  }
164 
165  Output *= Gain->GetValue();
166  }
167 
168  Clip();
169  SetOutput();
170 
171  return true;
172 }
173 
174 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
175 // The bitmasked value choices are as follows:
176 // unset: In this case (the default) JSBSim would only print
177 // out the normally expected messages, essentially echoing
178 // the config files as they are read. If the environment
179 // variable is not set, debug_lvl is set to 1 internally
180 // 0: This requests JSBSim not to output any messages
181 // whatsoever.
182 // 1: This value explicity requests the normal JSBSim
183 // startup messages
184 // 2: This value asks for a message to be printed out when
185 // a class is instantiated
186 // 4: When this value is set, a message is displayed when a
187 // FGModel object executes its Run() method
188 // 8: When this value is set, various runtime state variables
189 // are printed out periodically
190 // 16: When set various parameters are sanity checked and
191 // a message is printed out when they go out of bounds
192 
193 void FGGain::Debug(int from)
194 {
195  if (debug_lvl <= 0) return;
196 
197  if (debug_lvl & 1) { // Standard console startup message output
198  if (from == 0) { // Constructor
199  cout << " INPUT: " << InputNodes[0]->GetNameWithSign() << endl;
200  cout << " GAIN: " << Gain->GetName() << endl;
201 
202  for (auto node: OutputNodes)
203  cout << " OUTPUT: " << node->getNameString() << endl;
204 
205  if (Type == "AEROSURFACE_SCALE") {
206  cout << " In/Out Mapping:" << endl;
207  cout << " Input MIN: " << InMin << endl;
208  cout << " Input MAX: " << InMax << endl;
209  cout << " Output MIN: " << OutMin << endl;
210  cout << " Output MAX: " << OutMax << endl;
211  }
212  if (Table != 0) {
213  cout << " Scheduled by table: " << endl;
214  Table->Print();
215  }
216  }
217  }
218  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
219  if (from == 0) cout << "Instantiated: FGGain" << endl;
220  if (from == 1) cout << "Destroyed: FGGain" << endl;
221  }
222  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
223  }
224  if (debug_lvl & 8 ) { // Runtime state variables
225  }
226  if (debug_lvl & 16) { // Sanity checking
227  }
228  if (debug_lvl & 64) {
229  if (from == 0) { // Constructor
230  }
231  }
232 }
233 }