7 // Start in a "sane" mode, so unset stuff doesn't freak us out
11 _peaks[0] = _peaks[1] = 1;
12 for(int i=0; i<4; i++)
13 _stalls[i] = _widths[i] = 0;
14 _orient[0] = 1; _orient[1] = 0; _orient[2] = 0;
15 _orient[3] = 0; _orient[4] = 1; _orient[5] = 0;
16 _orient[6] = 0; _orient[7] = 0; _orient[8] = 1;
19 _slatPos = _spoilerPos = _flapPos = 0;
20 _slatDrag = _spoilerDrag = _flapDrag = 1;
26 void Surface::setPosition(float* p)
28 for(int i=0; i<3; i++) _pos[i] = p[i];
31 void Surface::getPosition(float* out)
33 for(int i=0; i<3; i++) out[i] = _pos[i];
36 void Surface::setChord(float chord)
41 void Surface::setTotalDrag(float c0)
46 float Surface::getTotalDrag()
51 void Surface::setXDrag(float cx)
56 void Surface::setYDrag(float cy)
61 void Surface::setZDrag(float cz)
66 void Surface::setBaseZDrag(float cz0)
71 void Surface::setStallPeak(int i, float peak)
76 void Surface::setStall(int i, float alpha)
81 void Surface::setStallWidth(int i, float width)
86 void Surface::setOrientation(float* o)
88 for(int i=0; i<9; i++)
92 void Surface::setIncidence(float angle)
97 void Surface::setSlatParams(float stallDelta, float dragPenalty)
99 _slatAlpha = stallDelta;
100 _slatDrag = dragPenalty;
103 void Surface::setFlapParams(float liftAdd, float dragPenalty)
106 _flapDrag = dragPenalty;
109 void Surface::setSpoilerParams(float liftPenalty, float dragPenalty)
111 _spoilerLift = liftPenalty;
112 _spoilerDrag = dragPenalty;
115 void Surface::setFlap(float pos)
120 void Surface::setSlat(float pos)
125 void Surface::setSpoiler(float pos)
130 // Calculate the aerodynamic force given a wind vector v (in the
131 // aircraft's "local" coordinates) and an air density rho. Returns a
132 // torque about the Y axis, too.
133 void Surface::calcForce(float* v, float rho, float* out, float* torque)
135 // Split v into magnitude and direction:
136 float vel = Math::mag3(v);
138 // Handle the blowup condition. Zero velocity means zero force by
141 for(int i=0; i<3; i++) out[i] = torque[i] = 0;
145 Math::mul3(1/vel, v, out);
147 // Convert to the surface's coordinates
148 Math::vmul33(_orient, out, out);
150 // "Rotate" by the incidence angle. Assume small angles, so we
151 // need to diddle only the Z component, X is relatively unchanged
152 // by small rotations.
153 out[2] += _incidence * out[0]; // z' = z + incidence * x
155 // Diddle the Z force according to our configuration
156 float stallMul = stallFunc(out);
157 stallMul *= 1 + _spoilerPos * (_spoilerLift - 1);
158 float stallLift = (stallMul - 1) * _cz * out[2];
159 float flapLift = _cz * _flapPos * (_flapLift-1);
161 out[2] *= _cz; // scaling factor
162 out[2] += _cz*_cz0; // zero-alpha lift
166 // Airfoil lift (pre-stall and zero-alpha) torques "up" (negative
167 // torque) around the Y axis, while flap lift pushes down. Both
168 // forces are considered to act at one third chord from the
169 // center. Convert to local (i.e. airplane) coordiantes and store
172 torque[1] = 0.33 * _chord * (flapLift - (_cz*_cz0 + stallLift));
174 Math::tmul33(_orient, torque, torque);
176 // Diddle X (drag) and Y (side force) in the same manner
177 out[0] *= _cx * controlDrag();
180 // Reverse the incidence rotation to get back to surface
182 out[2] -= _incidence * out[0];
184 // Convert back to external coordinates
185 Math::tmul33(_orient, out, out);
187 // Add in the units to make a real force:
188 float scale = 0.5*rho*vel*vel*_c0;
189 Math::mul3(scale, out, out);
190 Math::mul3(scale, torque, torque);
193 // Returns a multiplier for the "plain" force equations that
194 // approximates an airfoil's lift/stall curve.
195 float Surface::stallFunc(float* v)
197 // Sanity check to treat FPU psychopathology
198 if(v[0] == 0) return 1;
200 float alpha = Math::abs(v[2]/v[0]);
202 // Wacky use of indexing, see setStall*() methods.
203 int fwdBak = v[0] > 0; // set if this is "backward motion"
204 int posNeg = v[2] < 0; // set if the lift is toward -z
205 int i = (fwdBak<<1) | posNeg;
207 float stallAlpha = _stalls[i];
212 stallAlpha += _slatAlpha;
215 if(alpha > stallAlpha+_widths[i])
218 // (note mask: we want to use the "positive" stall angle here)
219 float scale = 0.5*_peaks[fwdBak]/_stalls[i&2];
222 if(alpha <= stallAlpha)
225 // Inside the stall. Compute a cubic interpolation between the
226 // pre-stall "scale" value and the post-stall unity.
227 float frac = (alpha - stallAlpha) / _widths[i];
228 frac = frac*frac*(3-2*frac);
230 return scale*(1-frac) + frac;
233 float Surface::controlDrag()
236 d *= 1 + _spoilerPos * (_spoilerDrag - 1);
237 d *= 1 + _slatPos * (_slatDrag - 1);
239 // FIXME: flaps should REDUCE drag when the reduce lift!
240 d *= 1 + Math::abs(_flapPos) * (_flapDrag - 1);
245 }; // namespace yasim