1
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7
------------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) -------------
9
This program is free software; you can redistribute it and/or modify it under
10
the terms of the GNU General Public License as published by the Free Software
11
Foundation; either version 2 of the License, or (at your option) any later
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 General Public License for more
19
You should have received a copy of the GNU General Public License along with
20
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21
Place - Suite 330, Boston, MA 02111-1307, USA.
23
Further information about the GNU General Public License can also be found on
24
the world wide web at http://www.gnu.org.
28
--------------------------------------------------------------------------------
32
FUNCTIONAL DESCRIPTION
33
--------------------------------------------------------------------------------
35
The purpose of this class is to provide storage for computed forces and
36
encapsulate all the functionality associated with transforming those
37
forces from their native coord system to the body system. This includes
38
computing the moments due to the difference between the point of application
41
CAVEAT: if the custom transform is used for wind-to-body transforms then the
42
user *must* always pass this class the negative of beta. This is true
43
because sideslip angle does not follow the right hand rule i.e. it is
44
positive for aircraft nose left sideslip. Note that use of the custom
45
transform for this purpose shouldn't be necessary as it is already
46
provided by SetTransform(tWindBody) and is not subject to the same
49
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
51
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
56
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
58
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
60
#include "FGFDMExec.h"
61
#include "FGJSBBase.h"
62
#include "FGMatrix33.h"
63
#include "FGColumnVector3.h"
65
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
69
#define ID_FORCE "$Id: FGForce.h,v 1.6 2004/06/14 11:40:45 ehofman Exp $"
71
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
77
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
81
/** Utility class that aids in the conversion of forces between coordinate systems
82
and calculation of moments.
83
<br><h3>Resolution of Applied Forces into Moments and Body Axes Components</h3>
85
All forces acting on the aircraft that cannot be considered a change in weight
86
need to be resolved into body axis components so that the aircraft acceleration
87
vectors, both translational and rotational, can be computed. Furthermore, the
88
moments produced by each force that does not act at a location corresponding to
89
the center of gravity also need to be computed. Unfortunately, the math required
90
to do this can be a bit messy and errors are easily introduced so the class
91
FGForce was created to provide these services in a consistent and reusable
96
<p>FGForce requires that its users supply it with the location of the applied
97
force vector in JSBSim structural coordinates, the sense of each axis in that
98
coordinate system relative to the body system, the orientation of the vector
99
also relative to body coordinates and, of course, the force vector itself. With
100
this information it will compute both the body axis force components and the
101
resulting moments. Any moments inherently produced by the native system can be
102
supplied as well and they will be summed with those computed.</p>
104
<p>A good example for demonstrating the use of this class are the aerodynamic
105
forces: lift, drag, and side force and the aerodynamic moments about the pitch,
106
roll and yaw axes. These "native" forces and moments are computed and stored
107
in the FGColumnVector objects vFs and vMoments. Their native coordinate system
108
is often referred to as the wind system and is defined as a right-handed system
109
having its x-axis aligned with the relative velocity vector and pointing towards
110
the rear of the aircraft , the y-axis extending out the right wing, and the
111
z-axis directed upwards. This is different than body axes; they are defined such
112
that the x-axis is lies on the aircraft's roll axis and positive forward, the
113
y-axis is positive out the right wing, and the z-axis is positive downwards. In
114
this instance, JSBSim already provides the needed transform and FGForce can make
115
use of it by calling SetTransformType() once an object is created:</p>
117
<p><tt>FGForce fgf(FDMExec);</tt><br>
118
<tt>fgf.SetTransformType(tWindBody);</tt><br><br>
120
This call need only be made once for each object. The available transforms are
121
defined in the enumerated type TransformType and are tWindBody, tLocalBody,
122
tCustom, and tNone. The local-to-body transform, like the wind-to-body, also
123
makes use of that already available in JSBSim. tNone sets FGForce to do no
124
angular transform at all, and tCustom allows for modeling force vectors at
125
arbitrary angles relative to the body system such as that produced by propulsion
126
systems. Setting up and using a custom transform is covered in more detail below.
127
Continuing with the example, the point of application of the aerodynamic forces,
128
the aerodynamic reference point in JSBSim, also needs to be set:</p>
130
fgf.SetLocation(x, y, z)</tt></p>
132
<p>where x, y, and z are in JSBSim structural coordinates.</p>
134
<p>Initialization is complete and the FGForce object is ready to do its job. As
135
stated above, the lift, drag, and side force are computed and stored in the
136
vector vFs and need to be passed to FGForce:</p>
138
<p><tt>fgf.SetNativeForces(vFs);</tt> </p>
140
<p>The same applies to the aerodynamic pitching, rolling and yawing moments:</p>
142
<p><tt>fgf.SetNativeMoments(vMoments);</tt></p>
144
<p>Note that storing the native forces and moments outside of this class is not
145
strictly necessary, overloaded SetNativeForces() and SetNativeMoments() methods
146
which each accept three doubles (rather than a vector) are provided and can be
147
repeatedly called without incurring undue overhead. The body axes force vector
148
can now be retrieved by calling:</p>
150
<p><tt>vFb=fgf.GetBodyForces();</tt></p>
152
<p>This method is where the bulk of the work gets done so calling it more than
153
once for the same set of native forces and moments should probably be avoided.
154
Note that the moment calculations are done here as well so they should not be
155
retrieved after calling the GetBodyForces() method:</p>
157
<p><tt>vM=fgf.GetMoments();</tt> </p>
159
<p>As an aside, the native moments are not needed to perform the computations
160
correctly so, if the FGForce object is not being used to store them then an
161
alternate approach is to avoid the SetNativeMoments call and perform the sum</p>
163
<p><tt>vMoments+=fgf.GetMoments();</tt> <br><br>
165
after the forces have been retrieved. </p>
167
<h4>Use of the Custom Transform Type</h4>
169
<p>In cases where the native force vector is not aligned with the body, wind, or
170
local coordinate systems a custom transform type is provided. A vectorable engine
171
nozzle will be used to demonstrate its usage. Initialization is much the same:</p>
173
<p><tt>FGForce fgf(FDMExec);</tt> <br>
174
<tt>fgf.SetTransformType(tCustom);</tt> <br>
175
<tt>fgf.SetLocation(x,y,z);</tt> </p>
177
<p>Except that here the tCustom transform type is specified and the location of
178
the thrust vector is used rather than the aerodynamic reference point. Thrust is
179
typically considered to be positive when directed aft while the body x-axis is
180
positive forward and, if the native system is right handed, the z-axis will be
181
reversed as well. These differences in sense need to be specified using by the
184
<p><tt>fgf.SetSense(-1,1,-1);</tt></p>
186
<p>The angles are specified by calling the method: </p>
188
<p><tt>fgf.SetAnglesToBody(pitch, roll, yaw);</tt> </p>
190
<p>in which the transform matrix is computed. Note that these angles should be
191
taken relative to the body system and not the local as the names might suggest.
192
For an aircraft with vectorable thrust, this method will need to be called
193
every time the nozzle angle changes, a fixed engine/nozzle installation, on the
194
other hand, will require it to be be called only once.</p>
196
<p>Retrieval of the computed forces and moments is done as detailed above.</p>
199
<p><i>CAVEAT: If the custom system is used to compute
200
the wind-to-body transform, then the sign of the sideslip
201
angle must be reversed when calling SetAnglesToBody().
202
This is true because sideslip angle does not follow the right
203
hand rule. Using the custom transform type this way
204
should not be necessary, as it is already provided as a built
205
in type (and the sign differences are correctly accounted for).</i>
209
<h4>Use as a Base Type</h4>
211
<p>For use as a base type, the native force and moment vector data members are
212
defined as protected. In this case the SetNativeForces() and SetNativeMoments()
213
methods need not be used and, instead, the assignments to vFn, the force vector,
214
and vMn, the moments, can be made directly. Otherwise, the usage is similar.<br>
218
@version $Id: FGForce.h,v 1.6 2004/06/14 11:40:45 ehofman Exp $
221
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
223
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
225
class FGForce : public FGJSBBase
229
FGForce(FGFDMExec *FDMExec);
233
enum TransformType { tNone, tWindBody, tLocalBody, tCustom } ttype;
235
inline void SetNativeForces(double Fnx, double Fny, double Fnz) {
240
inline void SetNativeForces(FGColumnVector3 vv) { vFn = vv; };
242
inline void SetNativeMoments(double Ln,double Mn, double Nn) {
247
inline void SetNativeMoments(FGColumnVector3 vv) { vMn = vv; }
249
inline FGColumnVector3& GetNativeForces(void) { return vFn; }
250
inline FGColumnVector3& GetNativeMoments(void) { return vMn; }
252
FGColumnVector3& GetBodyForces(void);
254
inline FGColumnVector3& GetMoments(void) { return vM; }
256
// Normal point of application, JSBsim structural coords
257
// (inches, x +back, y +right, z +up)
258
inline void SetLocation(double x, double y, double z) {
262
SetActingLocation(x, y, z);
265
/** Acting point of application.
266
JSBsim structural coords used (inches, x +back, y +right, z +up).
267
This function sets the point at which the force acts - this may
268
not be the same as where the object resides. One area where this
269
is true is P-Factor modeling.
270
@param x acting location of force
271
@param y acting location of force
272
@param z acting location of force */
273
inline void SetActingLocation(double x, double y, double z) {
278
inline void SetLocationX(double x) {vXYZn(eX) = x; vActingXYZn(eX) = x;}
279
inline void SetLocationY(double y) {vXYZn(eY) = y; vActingXYZn(eY) = y;}
280
inline void SetLocationZ(double z) {vXYZn(eZ) = z; vActingXYZn(eZ) = z;}
281
inline double SetActingLocationX(double x) {vActingXYZn(eX) = x; return x;}
282
inline double SetActingLocationY(double y) {vActingXYZn(eY) = y; return y;}
283
inline double SetActingLocationZ(double z) {vActingXYZn(eZ) = z; return z;}
284
inline void SetLocation(FGColumnVector3 vv) { vXYZn = vv; SetActingLocation(vv);}
285
inline void SetActingLocation(FGColumnVector3 vv) { vActingXYZn = vv; }
287
inline double GetLocationX( void ) { return vXYZn(eX);}
288
inline double GetLocationY( void ) { return vXYZn(eY);}
289
inline double GetLocationZ( void ) { return vXYZn(eZ);}
290
inline double GetActingLocationX( void ) { return vActingXYZn(eX);}
291
inline double GetActingLocationY( void ) { return vActingXYZn(eY);}
292
inline double GetActingLocationZ( void ) { return vActingXYZn(eZ);}
293
FGColumnVector3& GetLocation(void) { return vXYZn; }
294
FGColumnVector3& GetActingLocation(void) { return vActingXYZn; }
296
//these angles are relative to body axes, not earth!!!!!
297
//I'm using these because pitch, roll, and yaw are easy to visualize,
298
//there's no equivalent to roll in wind axes i.e. alpha, ? , beta
299
//making up new names or using these is a toss-up: either way people
300
//are going to get confused.
301
//They are in radians.
303
void SetAnglesToBody(double broll, double bpitch, double byaw);
304
inline void SetAnglesToBody(FGColumnVector3 vv) {
305
SetAnglesToBody(vv(eRoll), vv(ePitch), vv(eYaw));
308
inline void SetSense(double x, double y, double z) { vSense(eX)=x, vSense(eY)=y, vSense(eZ)=z; }
309
inline void SetSense(FGColumnVector3 vv) { vSense=vv; }
311
inline FGColumnVector3& GetSense(void) { return vSense; }
313
inline void SetTransformType(TransformType ii) { ttype=ii; }
314
inline TransformType GetTransformType(void) { return ttype; }
316
FGMatrix33 Transform(void);
327
FGColumnVector3 vXYZn;
328
FGColumnVector3 vActingXYZn;
329
FGColumnVector3 vDXYZ;
330
FGColumnVector3 vSense;
334
void Debug(int from);