1
0
Fork 0
flightgear/src/FDM/YASim/Surface.cpp
2001-12-07 20:00:59 +00:00

258 lines
5.8 KiB
C++

#include "Math.hpp"
#include "Surface.hpp"
namespace yasim {
Surface::Surface()
{
// Start in a "sane" mode, so unset stuff doesn't freak us out
_c0 = 1;
_cx = _cy = _cz = 1;
_cz0 = 0;
_peaks[0] = _peaks[1] = 1;
int i;
for(i=0; i<4; i++)
_stalls[i] = _widths[i] = 0;
_orient[0] = 1; _orient[1] = 0; _orient[2] = 0;
_orient[3] = 0; _orient[4] = 1; _orient[5] = 0;
_orient[6] = 0; _orient[7] = 0; _orient[8] = 1;
_incidence = 0;
_slatPos = _spoilerPos = _flapPos = 0;
_slatDrag = _spoilerDrag = _flapDrag = 1;
_flapLift = 0;
_slatAlpha = 0;
_spoilerLift = 1;
}
void Surface::setPosition(float* p)
{
int i;
for(i=0; i<3; i++) _pos[i] = p[i];
}
void Surface::getPosition(float* out)
{
int i;
for(i=0; i<3; i++) out[i] = _pos[i];
}
void Surface::setChord(float chord)
{
_chord = chord;
}
void Surface::setTotalDrag(float c0)
{
_c0 = c0;
}
float Surface::getTotalDrag()
{
return _c0;
}
void Surface::setXDrag(float cx)
{
_cx = cx;
}
void Surface::setYDrag(float cy)
{
_cy = cy;
}
void Surface::setZDrag(float cz)
{
_cz = cz;
}
void Surface::setBaseZDrag(float cz0)
{
_cz0 = cz0;
}
void Surface::setStallPeak(int i, float peak)
{
_peaks[i] = peak;
}
void Surface::setStall(int i, float alpha)
{
_stalls[i] = alpha;
}
void Surface::setStallWidth(int i, float width)
{
_widths[i] = width;
}
void Surface::setOrientation(float* o)
{
int i;
for(i=0; i<9; i++)
_orient[i] = o[i];
}
void Surface::setIncidence(float angle)
{
_incidence = angle;
}
void Surface::setSlatParams(float stallDelta, float dragPenalty)
{
_slatAlpha = stallDelta;
_slatDrag = dragPenalty;
}
void Surface::setFlapParams(float liftAdd, float dragPenalty)
{
_flapLift = liftAdd;
_flapDrag = dragPenalty;
}
void Surface::setSpoilerParams(float liftPenalty, float dragPenalty)
{
_spoilerLift = liftPenalty;
_spoilerDrag = dragPenalty;
}
void Surface::setFlap(float pos)
{
_flapPos = pos;
}
void Surface::setSlat(float pos)
{
_slatPos = pos;
}
void Surface::setSpoiler(float pos)
{
_spoilerPos = pos;
}
// Calculate the aerodynamic force given a wind vector v (in the
// aircraft's "local" coordinates) and an air density rho. Returns a
// torque about the Y axis, too.
void Surface::calcForce(float* v, float rho, float* out, float* torque)
{
// Split v into magnitude and direction:
float vel = Math::mag3(v);
// Handle the blowup condition. Zero velocity means zero force by
// definition.
if(vel == 0) {
int i;
for(i=0; i<3; i++) out[i] = torque[i] = 0;
return;
}
Math::mul3(1/vel, v, out);
// Convert to the surface's coordinates
Math::vmul33(_orient, out, out);
// "Rotate" by the incidence angle. Assume small angles, so we
// need to diddle only the Z component, X is relatively unchanged
// by small rotations.
out[2] += _incidence * out[0]; // z' = z + incidence * x
// Diddle the Z force according to our configuration
float stallMul = stallFunc(out);
stallMul *= 1 + _spoilerPos * (_spoilerLift - 1);
float stallLift = (stallMul - 1) * _cz * out[2];
float flapLift = _cz * _flapPos * (_flapLift-1);
out[2] *= _cz; // scaling factor
out[2] += _cz*_cz0; // zero-alpha lift
out[2] += stallLift;
out[2] += flapLift;
// Airfoil lift (pre-stall and zero-alpha) torques "up" (negative
// torque) around the Y axis, while flap lift pushes down. Both
// forces are considered to act at one third chord from the
// center. Convert to local (i.e. airplane) coordiantes and store
// into "torque".
torque[0] = 0;
torque[1] = 0.33 * _chord * (flapLift - (_cz*_cz0 + stallLift));
torque[2] = 0;
Math::tmul33(_orient, torque, torque);
// Diddle X (drag) and Y (side force) in the same manner
out[0] *= _cx * controlDrag();
out[1] *= _cy;
// Reverse the incidence rotation to get back to surface
// coordinates.
out[2] -= _incidence * out[0];
// Convert back to external coordinates
Math::tmul33(_orient, out, out);
// Add in the units to make a real force:
float scale = 0.5*rho*vel*vel*_c0;
Math::mul3(scale, out, out);
Math::mul3(scale, torque, torque);
}
// Returns a multiplier for the "plain" force equations that
// approximates an airfoil's lift/stall curve.
float Surface::stallFunc(float* v)
{
// Sanity check to treat FPU psychopathology
if(v[0] == 0) return 1;
float alpha = Math::abs(v[2]/v[0]);
// Wacky use of indexing, see setStall*() methods.
int fwdBak = v[0] > 0; // set if this is "backward motion"
int posNeg = v[2] < 0; // set if the lift is toward -z
int i = (fwdBak<<1) | posNeg;
float stallAlpha = _stalls[i];
if(stallAlpha == 0)
return 1;
if(i == 0)
stallAlpha += _slatAlpha;
// Beyond the stall
if(alpha > stallAlpha+_widths[i])
return 1;
// (note mask: we want to use the "positive" stall angle here)
float scale = 0.5*_peaks[fwdBak]/_stalls[i&2];
// Before the stall
if(alpha <= stallAlpha)
return scale;
// Inside the stall. Compute a cubic interpolation between the
// pre-stall "scale" value and the post-stall unity.
float frac = (alpha - stallAlpha) / _widths[i];
frac = frac*frac*(3-2*frac);
return scale*(1-frac) + frac;
}
float Surface::controlDrag()
{
float d = 1;
d *= 1 + _spoilerPos * (_spoilerDrag - 1);
d *= 1 + _slatPos * (_slatDrag - 1);
// Negative flap deflections don't affect drag until their lift
// multiplier exceeds the "camber" (cz0) of the surface.
float fp = _flapPos;
if(fp < 0) {
fp = -fp;
fp -= _cz0/(_flapLift-1);
if(fp < 0) fp = 0;
}
d *= 1 + fp * (_flapDrag - 1);
return d;
}
}; // namespace yasim