// The gear might have moved. Change their aerodynamics.
updateGearState();
- _model.iterate(dt);
+ _model.iterate();
}
void Airplane::consumeFuel(float dt)
return wgt;
}
-float Airplane::compileRotor(Rotor* w)
+float Airplane::compileRotor(Rotor* r)
{
- /* todo contact points
- // The tip of the wing is a contact point
- float tip[3];
- w->getTip(tip);
- addContactPoint(tip);
- if(w->isMirrored()) {
- tip[1] *= -1;
- addContactPoint(tip);
- }
- */
-
- // Make sure it's initialized. The surfaces will pop out with
- // total drag coefficients equal to their areas, which is what we
- // want.
- w->compile();
- _model.addRotor(w);
+ // Todo: add rotor to model!!!
+ // Todo: calc and add mass!!!
+ r->compile();
+ _model.addRotor(r);
float wgt = 0;
int i;
- /* Todo: add rotor to model!!!
- Todo: calc and add mass!!!
- */
- for(i=0; i<w->numRotorparts(); i++) {
- Rotorpart* s = (Rotorpart*)w->getRotorpart(i);
-
- //float td = s->getTotalDrag();
- //s->setTotalDrag(td);
+ for(i=0; i<r->numRotorparts(); i++) {
+ Rotorpart* s = (Rotorpart*)r->getRotorpart(i);
_model.addRotorpart(s);
-
float mass = s->getWeight();
mass = mass * Math::sqrt(mass);
s->getPosition(pos);
_model.getBody()->addMass(mass, pos);
wgt += mass;
-
}
- for(i=0; i<w->numRotorblades(); i++) {
- Rotorblade* s = (Rotorblade*)w->getRotorblade(i);
-
- //float td = s->getTotalDrag();
- //s->setTotalDrag(td);
-
- _model.addRotorblade(s);
+ for(i=0; i<r->numRotorblades(); i++) {
+ Rotorblade* b = (Rotorblade*)r->getRotorblade(i);
+ _model.addRotorblade(b);
- float mass = s->getWeight();
+ float mass = b->getWeight();
mass = mass * Math::sqrt(mass);
float pos[3];
- s->getPosition(pos);
+ b->getPosition(pos);
_model.getBody()->addMass(mass, pos);
wgt += mass;
-
}
-
return wgt;
}
if (_tail)
aeroWgt += compileWing(_tail);
int i;
- for(i=0; i<_vstabs.size(); i++) {
+ for(i=0; i<_vstabs.size(); i++)
aeroWgt += compileWing((Wing*)_vstabs.get(i));
- }
- for(i=0; i<_rotors.size(); i++) {
+ for(i=0; i<_rotors.size(); i++)
aeroWgt += compileRotor((Rotor*)_rotors.get(i));
- }
// The fuselage(s)
- for(i=0; i<_fuselages.size(); i++) {
+ for(i=0; i<_fuselages.size(); i++)
aeroWgt += compileFuselage((Fuselage*)_fuselages.get(i));
- }
// Count up the absolute weight we have
float nonAeroWgt = _ballast;
// Ground effect
float gepos[3];
- float gespan;
+ float gespan = 0;
if(_wing)
gespan = _wing->getGroundEffect(gepos);
- else
- gespan=0;
_model.setGroundEffect(gepos, gespan, 0.15f);
solveGear();
-
- solve();
+ if(_wing && _tail) solve();
+ else solveHelicopter();
// Do this after solveGear, because it creates "gear" objects that
// we don't want to affect.
// Precompute thrust in the model, and calculate aerodynamic forces
_model.getBody()->recalc();
_model.getBody()->reset();
- _model.initIteration(.01);//hier parameter egal
+ _model.initIteration();
_model.calcForces(&_cruiseState);
}
// Precompute thrust in the model, and calculate aerodynamic forces
_model.getBody()->recalc();
_model.getBody()->reset();
- _model.initIteration(.01);//hier parameter egal
+ _model.initIteration();
_model.calcForces(&_approachState);
}
float tmp[3];
_solutionIterations = 0;
_failureMsg = 0;
- if((_wing)&&(_tail))
- {
- while(1) {
-#if 0
- printf("%d %f %f %f %f %f\n", //DEBUG
- _solutionIterations,
- 1000*_dragFactor,
- _liftRatio,
- _cruiseAoA,
- _tailIncidence,
- _approachElevator.val);
-#endif
+ while(1) {
if(_solutionIterations++ > 10000) {
_failureMsg = "Solution failed to converge after 10000 iterations";
return;
_failureMsg = "Tail incidence > 10 degrees";
return;
}
- }
- else
- {
- applyDragFactor(Math::pow(15.7/1000, 1/SOLVE_TWEAK));
- applyLiftRatio(Math::pow(104, 1/SOLVE_TWEAK));
- setupState(0,0, &_cruiseState);
- _model.setState(&_cruiseState);
- _controls.reset();
- _model.getBody()->reset();
-
-
- }
+}
- return;
+void Airplane::solveHelicopter()
+{
+ applyDragFactor(Math::pow(15.7/1000, 1/SOLVE_TWEAK));
+ applyLiftRatio(Math::pow(104, 1/SOLVE_TWEAK));
+ setupState(0,0, &_cruiseState);
+ _model.setState(&_cruiseState);
+ _controls.reset();
+ _model.getBody()->reset();
}
+
}; // namespace yasim
void setupState(float aoa, float speed, State* s);
void solveGear();
void solve();
+ void solveHelicopter();
float compileWing(Wing* w);
float compileRotor(Rotor* w);
float compileFuselage(Fuselage* f);
_airplane.setWing(parseWing(a, name));
} else if(eq(name, "hstab")) {
_airplane.setTail(parseWing(a, name));
- } else if(eq(name, "vstab")) {
- _airplane.addVStab(parseWing(a, name));
- } else if(eq(name, "mstab")) {
+ } else if(eq(name, "vstab") || eq(name, "mstab")) {
_airplane.addVStab(parseWing(a, name));
} else if(eq(name, "propeller")) {
parsePropeller(a);
for(i=0; i<_airplane.getNumRotors(); i++) {
Rotor*r=(Rotor*)_airplane.getRotor(i);
- int j=0;
+ int j = 0;
float f;
char b[256];
- while(j=r->getValueforFGSet(j,b,&f))
- {
- if (b[0])
- {
- fgSetFloat(b,f);
- }
- }
+ while(j = r->getValueforFGSet(j, b, &f))
+ if(b[0]) fgSetFloat(b,f);
- for(j=0; j<r->numRotorparts(); j++) {
+ for(j=0; j < r->numRotorparts(); j++) {
Rotorpart* s = (Rotorpart*)r->getRotorpart(j);
char *b;
int k;
- for (k=0;k<2;k++)
- {
- b=s->getAlphaoutput(k);
- if (b[0])
- {
- fgSetFloat(b,s->getAlpha(k));
- //printf("setting [%s]\n",b);
- }
+ for(k=0; k<2; k++) {
+ b=s->getAlphaoutput(k);
+ if(b[0]) fgSetFloat(b, s->getAlpha(k));
}
}
- for(j=0; j<r->numRotorblades(); j++) {
+ for(j=0; j < r->numRotorblades(); j++) {
Rotorblade* s = (Rotorblade*)r->getRotorblade(j);
char *b;
int k;
- for (k=0;k<2;k++)
- {
- b=s->getAlphaoutput(k);
- if (b[0])
- {
- fgSetFloat(b,s->getAlpha(k));
- }
+ for (k=0; k<2; k++) {
+ b = s->getAlphaoutput(k);
+ if(b[0]) fgSetFloat(b, s->getAlpha(k));
}
}
- }
-
+ }
for(i=0; i<_thrusters.size(); i++) {
EngRec* er = (EngRec*)_thrusters.get(i);
_currObj = w;
return w;
}
+
Rotor* FGFDM::parseRotor(XMLAttributes* a, const char* type)
{
Rotor* w = new Rotor();
forward[2] = attrf(a, "fz");
w->setForward(forward);
-
-
w->setMaxCyclicail(attrf(a, "maxcyclicail", 7.6));
w->setMaxCyclicele(attrf(a, "maxcyclicele", 4.94));
w->setMinCyclicail(attrf(a, "mincyclicail", -7.6));
void setAlphamax(float f);
void setAlpha0factor(float f);
- if(attristrue(a,"ccw"))
+ if(attrb(a,"ccw"))
w->setCcw(1);
if(a->hasAttribute("name"))
w->setForceAtPitchA(attrf(a, "forceatpitch_a", 3000));
w->setPowerAtPitch0(attrf(a, "poweratpitch_0", 300));
w->setPowerAtPitchB(attrf(a, "poweratpitch_b", 3000));
- if(attristrue(a,"notorque"))
+ if(attrb(a,"notorque"))
w->setNotorque(1);
- if(attristrue(a,"simblades"))
+ if(attrb(a,"simblades"))
w->setSimBlades(1);
-
-
-
-
_currObj = w;
return w;
}
else return (float)atof(val);
}
-bool FGFDM::attristrue(XMLAttributes* atts, char* attr)
+// ACK: the dreaded ambiguous string boolean. Remind me to shoot Maik
+// when I have a chance. :). Unless you have a parser that can check
+// symbol constants (we don't), this kind of coding is just a Bad
+// Idea. This implementation, for example, silently returns a boolean
+// falsehood for values of "1", "yes", "True", and "TRUE". Which is
+// especially annoying preexisting boolean attributes in the same
+// parser want to see "1" and will choke on a "true"...
+//
+// Unfortunately, this usage creeped into existing configuration files
+// while I wasn't active, and it's going to be hard to remove. Issue
+// a warning to nag people into changing their ways for now...
+bool FGFDM::attrb(XMLAttributes* atts, char* attr)
{
const char* val = atts->getValue(attr);
if(val == 0) return false;
- else return eq(val,"true");
+
+ if(eq(val,"true")) {
+ SG_LOG(SG_FLIGHT, SG_ALERT, "Warning: " <<
+ "deprecated 'true' boolean in YASim configuration file. " <<
+ "Use numeric booleans (attribute=\"1\") instead");
+ return true;
+ }
+ return attri(atts, attr, 0) ? true : false;
}
}; // namespace yasim
int attri(XMLAttributes* atts, char* attr, int def);
float attrf(XMLAttributes* atts, char* attr);
float attrf(XMLAttributes* atts, char* attr, float def);
- bool attristrue(XMLAttributes* atts, char* attr);
+ bool attrb(XMLAttributes* atts, char* attr);
// The core Airplane object we manage.
Airplane _airplane;
{
return (float)::sqrt(f);
}
-float Math::sqr(float f)
-{
- return f*f;
-}
float Math::ceil(float f)
{
return sqrt(dot3(v, v));
}
-
void Math::unit3(float* v, float* out)
{
- float mag=mag3(v);
- float imag;
- if (mag!=0)
- imag= 1/mag;
- else
- imag=1;
+ float imag = 1/mag3(v);
mul3(imag, v, out);
}
// Simple wrappers around library routines
static float abs(float f);
static float sqrt(float f);
- static float sqr(float f);
static float ceil(float f);
static float sin(float f);
static float cos(float f);
-#include <stdio.h>
-
#include "Atmosphere.hpp"
#include "Thruster.hpp"
#include "Math.hpp"
#include "Model.hpp"
namespace yasim {
+#if 0
void printState(State* s)
{
State tmp = *s;
printf("rot: %6.2f %6.2f %6.2f\n", tmp.rot[0], tmp.rot[1], tmp.rot[2]);
printf("rac: %6.2f %6.2f %6.2f\n", tmp.racc[0], tmp.racc[1], tmp.racc[2]);
}
+#endif
Model::Model()
{
}
}
-void Model::initIteration(float dt)
+void Model::initIteration()
{
// Precompute torque and angular momentum for the thrusters
int i;
t->getGyro(v);
Math::add3(v, _gyro, _gyro);
}
+}
-
-
-
+// FIXME: This method looks to me like it's doing *integration*, not
+// initialization. Integration code should ideally go into
+// calcForces. Only very "unstiff" problems can be solved well like
+// this (see the engine code for an example); I don't know if rotor
+// dynamics qualify or not.
+// -Andy
+void Model::initRotorIteration()
+{
+ int i;
+ float dt = _integrator.getInterval();
float lrot[3];
Math::vmul33(_s->orient, _s->rot, lrot);
Math::mul3(dt,lrot,lrot);
Rotorblade* rp = (Rotorblade*)_rotorblades.get(i);
rp->inititeration(dt,lrot);
}
-
}
-void Model::iterate(float dt)
+void Model::iterate()
{
- initIteration(dt);
+ initIteration();
+ initRotorIteration();
_body.recalc(); // FIXME: amortize this, somehow
_integrator.calcNewInterval();
}
return _s;
}
-void Model::resetState()
-{
- //_s->resetState();
-}
-
-
void Model::setState(State* s)
{
_integrator.setState(s);
// velocity), and are therefore constant across the four calls to
// calcForces. They get computed before we begin the integration
// step.
- //printf("f");
_body.setGyro(_gyro);
_body.addTorque(_torque);
int i;
sf->calcForce(vs, _rho, force, torque);
Math::add3(faero, force, faero);
-
-
_body.addForce(pos, force);
_body.addTorque(torque);
}
_body.addForce(pos, force);
_body.addTorque(torque);
}
- /*
- {
- float cg[3];
- _body.getCG(cg);
- //printf("cg: %5.3lf %5.3lf %5.3lf ",cg[0],cg[1],cg[2]);
- }
- */
// Get a ground plane in local coordinates. The first three
// elements are the normal vector, the final one is the distance
{
_s = s;
- //printState(s);
-
// Some simple collision detection
float min = 1e8;
float ground[4], pos[3], cmpr[3];
State* getState();
void setState(State* s);
- void resetState();
bool isCrashed();
void setCrashed(bool crashed);
float getAGL();
- void iterate(float dt);
+ void iterate();
// Externally-managed subcomponents
int addThruster(Thruster* t);
int numThrusters();
Thruster* getThruster(int handle);
void setThruster(int handle, Thruster* t);
- void initIteration(float dt);
+ void initIteration();
void getThrust(float* out);
//
virtual void newState(State* s);
private:
+ void initRotorIteration();
void calcGearForce(Gear* g, float* v, float* rot, float* ground);
float gearFriction(float wgt, float v, Gear* g);
float localGround(State* s, float* out);
const float pi=3.14159;
+static inline float sqr(float a) { return a * a; }
+
Rotor::Rotor()
{
_alpha0=-.05;
rk=l-p;
rl=1-rk;
/*
- rl=Math::sqr(Math::sin(rl*pi/2));
- rk=Math::sqr(Math::sin(rk*pi/2));
+ rl=sqr(Math::sin(rl*pi/2));
+ rk=sqr(Math::sin(rk*pi/2));
*/
if(w==2) {k+=2;l+=2;}
else
float phi=Math::atan2(2*omega*_delta,omega0*omega0-omega*omega);
//float relamp=omega*omega/(2*_delta*Math::sqrt(omega0*omega0-_delta*_delta));
- float relamp=omega*omega/(2*_delta*Math::sqrt(Math::sqr(omega0*omega0-omega*omega)+4*_delta*_delta*omega*omega));
+ float relamp=omega*omega/(2*_delta*Math::sqrt(sqr(omega0*omega0-omega*omega)+4*_delta*_delta*omega*omega));
if (!_no_torque)
{
torque0=_power_at_pitch_0/4*1000/omega;
_delta*=maxpitchforce/(_max_pitch*omega*lentocenter*2*_weight_per_blade*.453);
float phi=Math::atan2(2*omega*_delta,omega0*omega0-omega*omega);
float phi2=Math::abs(omega0-omega)<.000000001?pi/2:Math::atan(2*omega*_delta/(omega0*omega0-omega*omega));
- float relamp=omega*omega/(2*_delta*Math::sqrt(Math::sqr(omega0*omega0-omega*omega)+4*_delta*_delta*omega*omega));
+ float relamp=omega*omega/(2*_delta*Math::sqrt(sqr(omega0*omega0-omega*omega)+4*_delta*_delta*omega*omega));
if (!_no_torque)
{
torque0=_power_at_pitch_0/_number_of_blades*1000/omega;
sprintf(buf, "/engines/engine[%d]/mp-osi", i); fgUntie(buf);
sprintf(buf, "/engines/engine[%d]/egt-degf", i); fgUntie(buf);
}
-
}
void YASim::init()
// Superclass hook
common_init();
+
m->setCrashed(false);
// Figure out the initial speed type