JSBSim Flight Dynamics Model 1.3.0 (09 Apr 2026)
An Open Source Flight Dynamics and Control Software Library in C++
Loading...
Searching...
No Matches
FGLinearActuator.cpp
1/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 *
3Module: FGLinearActuator.cpp
4Author: Adriano Bassignana
5Date started: 2019-01-03
6
7------------- Copyright (C) 2019 Adriano Bassignana -------------
8
9This program is free software; you can redistribute it and/or modify it under
10the terms of the GNU Lesser General Public License as published by the Free
11Software Foundation; either version 2 of the License, or (at your option) any
12later version.
13
14This program is distributed in the hope that it will be useful, but WITHOUT
15ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
17details.
18
19You should have received a copy of the GNU Lesser General Public License along
20with this program; if not, write to the Free Software Foundation, Inc., 59
21Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23Further information about the GNU Lesser General Public License can also be
24found on the world wide web at http://www.gnu.org.
25
26FUNCTIONAL DESCRIPTION
27--------------------------------------------------------------------------------
28
29HISTORY
30--------------------------------------------------------------------------------
31
32%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33COMMENTS, REFERENCES, and NOTES
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
36%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37INCLUDES
38%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
39
40#include "FGLinearActuator.h"
41#include "models/FGFCS.h"
42#include "math/FGParameterValue.h"
43#include "input_output/FGLog.h"
44
45using namespace std;
46
47namespace JSBSim {
48
49/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
50CLASS IMPLEMENTATION
51%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
52
54 : FGFCSComponent(fcs, element)
55{
56 CheckInputNodes(1, 1, element);
57
58 ptrSet = nullptr;
59 auto PropertyManager = fcs->GetPropertyManager();
60 if (element->FindElement("set")) {
61 string property_string = element->FindElementValue("set");
62 ptrSet = new FGParameterValue(property_string, PropertyManager, element);
63 if (ptrSet && ptrSet->IsConstant()) {
64 set = ptrSet->GetValue() >= 0.5;
65 }
66 }
67
68 ptrReset = nullptr;
69 if (element->FindElement("reset")) {
70 string property_string = element->FindElementValue("reset");
71 ptrReset = new FGParameterValue(property_string, PropertyManager, element);
72 if (ptrReset && ptrReset->IsConstant()) {
73 reset = ptrReset->GetValue() >= 0.5;
74 }
75 }
76
77 ptrVersus = nullptr;
78 if (element->FindElement("versus")) {
79 string property_string = element->FindElementValue("versus");
80 ptrVersus = new FGParameterValue(property_string, PropertyManager, element);
81 if (ptrVersus && ptrVersus->IsConstant()) {
82 versus = ptrVersus->GetValue();
83 }
84 }
85
86 ptrBias = nullptr;
87 if (element->FindElement("bias")) {
88 string property_string = element->FindElementValue("bias");
89 ptrBias = new FGParameterValue(property_string, PropertyManager, element);
90 if (ptrBias && ptrBias->IsConstant()) {
91 bias = ptrBias->GetValue();
92 }
93 }
94
95 if (element->FindElement("module")) {
96 module = element->FindElementValueAsNumber("module");
97 if (module < 0) {
98 FGLogging log(LogLevel::WARN);
99 log << "FGLinearActuator::Run " << InputNodes[0]->GetNameWithSign()
100 << " <module> parameter is forced from " << fixed << module
101 << " value to 1.0 value\n";
102 module = 1.0;
103 }
104 }
105
106 if (element->FindElement("hysteresis")) {
107 hysteresis = element->FindElementValueAsNumber("hysteresis");
108 if (hysteresis < 0) {
109 FGLogging log(LogLevel::WARN);
110 log << "FGLinearActuator::Run " << InputNodes[0]->GetNameWithSign()
111 << " <hysteresis> parameter is forced from " << fixed << hysteresis
112 << " value to 0.0 value\n";
113 hysteresis = 0.0;
114 }
115 }
116
117 if (element->FindElement("lag")) {
118 lag = element->FindElementValueAsNumber("lag");
119 if (lag > 0.0) {
120 double denom = 2.00 + dt*lag;
121 ca = dt * lag / denom;
122 cb = (2.00 - dt * lag) / denom;
123 previousLagInput = previousLagOutput = 0.0;
124 } else {
125 if (lag < 0) {
126 FGLogging log(LogLevel::WARN);
127 log << "FGLinearActuator::Run " << InputNodes[0]->GetNameWithSign()
128 << " <lag> parameter is forced from " << fixed << lag
129 << " value to 0.0 value\n";
130 lag = 0;
131 }
132 }
133 }
134
135 if (element->FindElement("rate")) {
136 rate = element->FindElementValueAsNumber("rate");
137 if (rate <= 0 || rate > 1.0) {
138 FGLogging log(LogLevel::WARN);
139 log << "FGLinearActuator::Run " << InputNodes[0]->GetNameWithSign()
140 << " <rate> parameter is forced from " << fixed << rate
141 << " value to 0.5 value\n";
142 rate = 0.5;
143 }
144 }
145
146 if (element->FindElement("gain"))
147 gain = element->FindElementValueAsNumber("gain");
148
149 bind(element, PropertyManager.get());
150
151 Debug(0);
152}
153
154// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
155
157{
158 Debug(1);
159}
160
161// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
162
164{
165 if (ptrSet && !ptrSet->IsConstant()) set = ptrSet->GetValue() >= 0.5;
166 if (ptrReset && !ptrReset->IsConstant()) reset = ptrReset->GetValue() >= 0.5;
167
168 if (reset) {
169 inputMem = 0.0;
170 countSpin = 0;
171 direction = 0;
172 Output = 0.0;
173 inputLast = 0.0;
174 } else {
175 if (set) {
176 Input = InputNodes[0]->getDoubleValue() - inputLast;
177 double inputDelta = Input - inputMem;
178 if (abs(inputDelta) >= hysteresis) {
179 if (ptrVersus && !ptrVersus->IsConstant()) {
180 versus = ptrVersus->GetValue();
181 if (versus >= 0.5) {
182 versus = 1;
183 } else if (versus <= -0.5) {
184 versus = -1;
185 } else versus = 0;
186 }
187 if (abs(inputDelta) <= (module * rate)) {
188 if (inputDelta > 0.0) {
189 direction = 1;
190 } else if (inputDelta < 0.0) {
191 direction = -1;
192 }
193 }
194 if ((versus == 0) || (versus == direction)) {
195 inputMem = Input;
196 if (abs(inputDelta) >= (module*rate)) {
197 if (inputDelta < 0)
198 countSpin++;
199 else
200 countSpin--;
201 }
202 } else if ((versus != 0) && (direction != 0) && (versus != direction)) {
203 inputLast += inputDelta;
204 }
205 }
206 }
207 if (ptrBias && !ptrBias->IsConstant()) {
208 bias = ptrBias->GetValue();
209 }
210 Output = gain * (bias + inputMem + module*countSpin);
211 }
212
213 if (lag > 0.0) {
214 double input = Output;
215 Output = ca * (input + previousLagInput) + previousLagOutput * cb;
216 previousLagInput = input;
217 previousLagOutput = Output;
218 }
219
220 SetOutput();
221
222 return true;
223}
224
225// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
226// The bitmasked value choices are as follows:
227// unset: In this case (the default) JSBSim would only print
228// out the normally expected messages, essentially echoing
229// the config files as they are read. If the environment
230// variable is not set, debug_lvl is set to 1 internally
231// 0: This requests JSBSim not to output any messages
232// whatsoever.
233// 1: This value explicitly requests the normal JSBSim
234// startup messages
235// 2: This value asks for a message to be printed out when
236// a class is instantiated
237// 4: When this value is set, a message is displayed when a
238// FGModel object executes its Run() method
239// 8: When this value is set, various runtime state variables
240// are printed out periodically
241// 16: When set various parameters are sanity checked and
242// a message is printed out when they go out of bounds
243void FGLinearActuator::Debug(int from)
244{
245 if (debug_lvl <= 0) return;
246
247 if (debug_lvl & 1) { // Standard console startup message output
248 if (from == 0) { // Constructor
249 FGLogging log(LogLevel::DEBUG);
250 log << " INPUT: " << InputNodes[0]->GetNameWithSign() << fixed << "\n";
251 log << " inputMem: " << inputMem << "\n";
252 log << " bias: " << bias << "\n";
253 log << " module: " << module << "\n";
254 log << " hysteresis: " << hysteresis << "\n";
255 log << " rate: " << rate << "\n";
256 log << " versus: " << versus << "\n";
257 log << " direction: " << direction << "\n";
258 log << " countSpin: " << countSpin << "\n";
259 log << " Lag: " << lag << "\n";
260 log << " Gain: " << gain << "\n";
261 log << " set: " << set << "\n";
262 log << " reset: " << reset << "\n";
263 for (auto node: OutputNodes)
264 log << " OUTPUT: " << node->getNameString() << "\n";
265 }
266 }
267 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
268 FGLogging log(LogLevel::DEBUG);
269 if (from == 0) log << "Instantiated: FGLinearActuator\n";
270 if (from == 1) log << "Destroyed: FGLinearActuator\n";
271 }
272 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
273 }
274 if (debug_lvl & 8 ) { // Runtime state variables
275 }
276 if (debug_lvl & 16) { // Sanity checking
277 }
278 if (debug_lvl & 64) {
279 if (from == 0) { // Constructor
280 }
281 }
282}
283}
Element * FindElement(const std::string &el="")
Searches for a specified element.
std::string FindElementValue(const std::string &el="")
Searches for the named element and returns the string data belonging to it.
double FindElementValueAsNumber(const std::string &el="")
Searches for the named element and returns the data belonging to it as a number.
Base class for JSBSim Flight Control System Components.
Encapsulates the Flight Control System (FCS) functionality.
Definition FGFCS.h:189
bool Run(void) override
The execution method for this FCS component.
FGLinearActuator(FGFCS *fcs, Element *element)
Constructor.
Represents a either a real value or a property value.
Main namespace for the JSBSim Flight Dynamics Model.
Definition FGFDMExec.cpp:71