6#include <simgear/props/props.hxx>
7#include <simgear/xml/easyxml.hxx>
8#include <simgear/misc/sg_path.hxx>
10#include "yasim-common.hpp"
12#include "Atmosphere.hpp"
13#include "RigidBody.hpp"
14#include "Airplane.hpp"
24SGPropertyNode*
fgGetNode (
const char * path,
bool create) {
return 0; }
25SGPropertyNode*
fgGetNode (
const char * path,
int i,
bool create) {
return 0; }
33 Model* m = a->getModel();
36 case Airplane::APPROACH:
37 fprintf(stderr,
"Setting approach controls.\n");
38 a->setApproachControls();
40 case Airplane::CRUISE:
41 fprintf(stderr,
"Setting cruise controls.\n");
42 a->setCruiseControls();
47 m->getBody()->recalc();
52 Model* m = a->getModel();
54 s.setupState(aoa_rad, speed_mps, 0);
55 m->getBody()->reset();
58 m->getBody()->getAccel(output);
59 s.localToGlobal(output, output);
75void yasim_graph(Airplane* a,
const float alt,
const float kts, Airplane::Configuration cfgID)
78 float speed = kts * KTS2MPS;
80 float cl_max = 0, cd_min = 1e6, ld_max = 0;
81 int cl_max_deg = 0, cd_min_deg = 0, ld_max_deg = 0;
83 printf(
"aoa\tlift\tdrag\n");
84 for(
int deg=-15; deg<=90; deg++) {
87 float drag = acc[0] * (-1/9.8);
88 float lift = 1 + acc[2] * (1/9.8);
103 printf(
"%2d\t%.4f\t%.4f\n", deg, lift, drag);
105 printf(
"# cl_max %.4f at %d deg\n", cl_max, cl_max_deg);
106 printf(
"# cd_min %.4f at %d deg\n", cd_min, cd_min_deg);
107 printf(
"# ld_max %.4f at %d deg\n", ld_max, ld_max_deg);
112 RigidBody* body = a->getModel()->getBody();
113 int N = body->numMasses();
116 printf(
"id\tposx\tposy\tposz\tmass\n");
117 for (
int i = 0;
i <
N;
i++)
119 body->getMassPosition(
i, pos);
120 m = body->getMass(
i);
121 printf(
"%d\t%.3f\t%.3f\t%.3f\t%.3f\n",
i, pos[0], pos[1], pos[2], m);
124 printf(
"Total mass: %g", mass);
127void yasim_drag(Airplane* a,
const float aoa,
const float alt, Airplane::Configuration cfgID)
133 float acc[3] {0,0,0};
135 printf(
"#kts, drag\n");
136 for(
int kts=15; kts<=150; kts++) {
138 float drag = acc[0] * (-1/9.8);
143 printf(
"%d %g\n", kts, drag);
145 printf(
"# cd_min %g at %d kts\n", cd_min, cd_min_kts);
153 float aoa_deg_delta = 10;
158 if (lift > 0) aoa_deg -= aoa_deg_delta;
159 if (lift < 0) aoa_deg += aoa_deg_delta;
161 if (aoa_deg_delta < 0.001)
break;
170 bool verbose,
float& o_best_speed_kts,
float& o_best_drag,
float& o_best_aoa_deg)
172 o_best_speed_kts = 0;
174 o_best_aoa_deg = 0.0f;
178 for (
float kts = 50; kts < 600; kts += 1) {
182 float drag = acc[0] / -9.8;
183 float idrag = 9.8 * tan(aoa);
184 float drag_total = drag + idrag;
187 printf(
"acc=(% 10.4f % 10.2g % 10.4f)."
188 " alt=% 10.4f kts=% 10.4f: aoa_deg=% 10.4f drag=% 10.4f"
189 " idrag=% 10.4f drag_total=% 10.4f\n",
190 acc[0], acc[1], acc[2],
191 alt, kts, aoa_deg, drag,
195 if (drag_total < o_best_drag) {
196 o_best_speed_kts = kts;
197 o_best_drag = drag_total;
198 o_best_aoa_deg = aoa_deg;
206 for (
int alt_ft=0; alt_ft < 50*1000; alt_ft += 1000) {
207 float alt_m = alt_ft * 12.0 * 2.54 / 100.0;
208 float best_speed_kts;
213 best_speed_kts, best_drag, best_aoa_deg);
215 printf(
"altitude=% 6ift: best_speed=%gkts best_aoa=%.2fdeg drag=%g\n",
216 alt_ft, best_speed_kts, best_aoa_deg, best_drag);
223 a->addControlSetting(Airplane::CRUISE,
"/controls/flight/elevator-trim", 0.7f);
224 _setup(a, Airplane::CRUISE, alt);
227 printf(
"aoa\tknots\tlift\n");
228 for(
int deg=0; deg<=20; deg++) {
230 for(
int kts=15; kts<=180; kts++) {
234 printf(
"%d\t%d\t%f\n", deg, kts, lift);
256 float speed = kts * KTS2MPS;
257 float acc[3] {0,0,0};
258 float cl_max = 0, cd_min = 1e6, ld_max = 0;
261 printf(
"aoa\tlift\tdrag\tLD\n");
262 for(
float deg=-2.0; deg<=25.0 ; deg+= 0.10 ) {
265 float drag = acc[0] * (-1/9.8);
266 float lift = 1 + acc[2] * (1/9.8);
267 float ld = lift/drag;
281 printf(
"%-2.1f\t%-2.3f\t%-2.3f\t%-2.3f\n", deg, lift, drag, ld);
294 float acc[3] {0,0,0};
296 printf(
"knots\tdrag\n");
297 for(
float kts=0; kts<=100; kts += 0.1) {
299 float drag = acc[0] * (-1/9.8);
304 printf(
"%-2.3f\t%-2.3f\n", kts, drag);
311 a->addControlSetting(Airplane::CRUISE,
"/controls/flight/elevator-trim", 0.7f);
312 _setup(a, Airplane::CRUISE, alt);
315 printf(
"aoa\tknots\tlift\n");
316 for(
float deg=-2; deg<=25.0; deg+=0.10) {
318 for(
float kts = 0; kts <= 180.0; kts += 0.1) {
322 printf(
"%-2.1f \t %-2.3f \t %-2.3f\n", deg, kts, ( 100 + 100 * lift));
331 printf(
"==========================\n");
332 printf(
"= YASim solution results =\n");
333 printf(
"==========================\n");
334 float aoa = a->getCruiseAoA() * RAD2DEG;
335 float tailIncidence = a->getTailIncidence() * RAD2DEG;
336 float drag = 1000 * a->getDragCoefficient();
338 a->getModel()->getBody()->getCG(cg);
339 a->getModel()->getBody()->recalc();
342 a->getModel()->getBody()->getInertiaMatrix(SI_inertia);
343 float MAC = 0, MACx = 0, MACy = 0;
344 float sweepMin = 0, sweepMax = 0;
345 Wing* wing {
nullptr};
346 Wing* tail {
nullptr};
351 printf(
"Iterations : %d\n", a->getSolutionIterations());
352 printf(
"Drag Coefficient : %.3f\n", drag);
353 printf(
"Lift Ratio : %.3f\n", a->getLiftRatio());
354 printf(
"Cruise AoA : %.2f deg\n", aoa);
355 printf(
"Tail Incidence : %.2f deg\n", tailIncidence);
356 printf(
"Approach Elevator : %.3f\n\n", a->getApproachElevator());
357 printf(
"CG : x:%.3f, y:%.3f, z:%.3f\n", cg[0], cg[1], cg[2]);
359 MAC = wing->getMACLength();
360 MACx = wing->getMACx();
361 MACy = wing->getMACy();
362 sweepMin = wing->getSweepLEMin() * RAD2DEG;
363 sweepMax = wing->getSweepLEMax() * RAD2DEG;
364 printf(
"Wing MAC : (x:%.3f, y:%.3f), length:%.3f \n", MACx, MACy, MAC);
365 printf(
"hard limit CG-x : %.3f m\n", a->getCGHardLimitXMax());
366 printf(
"soft limit CG-x : %.3f m\n", a->getCGSoftLimitXMax());
367 printf(
"CG-x : %.3f m\n", cg[0]);
368 printf(
"CG-x rel. MAC : %3.0f%%\n", a->getCGMAC()*100);
369 printf(
"soft limit CG-x : %.3f m\n", a->getCGSoftLimitXMin());
370 printf(
"hard limit CG-x : %.3f m\n", a->getCGHardLimitXMin());
372 printf(
"wing lever : %.3f m\n", a->getWingLever());
373 printf(
"tail lever : %.3f m\n", a->getTailLever());
375 printf(
"max thrust : %.2f kN\n", a->getMaxThrust()/1000);
376 printf(
"thrust/empty : %.2f\n", a->getThrust2WeightEmpty());
377 printf(
"thrust/mtow : %.2f\n", a->getThrust2WeightMTOW());
379 printf(
"wing span : %.2f m\n", a->getWingSpan());
380 printf(
"sweep lead. edge : %.1f .. %.1f deg\n", sweepMin, sweepMax);
381 printf(
"wing area : %.2f m^2\n", a->getWingArea());
382 printf(
"wing load empty : %.2f kg/m^2 (Empty %.0f kg)\n", a->getWingLoadEmpty(), a->getEmptyWeight());
383 printf(
"wing load MTOW : %.2f kg/m^2 (MTOW %.0f kg)\n", a->getWingLoadMTOW(), a->getMTOW());
385 printf(
"tail span : %.3f m\n", tail->getSpan());
386 printf(
"tail area : %.3f m^2\n", tail->getArea());
388 wing->printSectionInfo();
390 printf(
"\nInertia Tensor [kg*m^2], ( Angular Moments ) Origo at CG:\n\n");
391 printf(
" Effect on Axis\n");
392 printf(
" x Roll y Pitch z Yaw\n");
393 printf(
"Impulse x Roll %7.0f %7.0f %7.0f\n", SI_inertia[0], SI_inertia[1], SI_inertia[2]);
394 printf(
" on y Pitch %7.0f %7.0f %7.0f\n", SI_inertia[3], SI_inertia[4], SI_inertia[5]);
395 printf(
" Axis z Yaw %7.0f %7.0f %7.0f\n", SI_inertia[6], SI_inertia[7], SI_inertia[8]);
400 fprintf(stderr,
"Usage: \n");
401 fprintf(stderr,
" yasim <aircraft.xml> [-g [-a meters] [-s kts] [-approach | -cruise] ]\n");
402 fprintf(stderr,
" yasim <aircraft.xml> [-d [-a meters] [-approach | -cruise] ]\n");
403 fprintf(stderr,
" yasim <aircraft.xml> [-m] [-h] [--min-speed]\n");
404 fprintf(stderr,
" yasim <aircraft.xml> [-test] [-a meters] [-s kts] [-approach | -cruise] ]\n");
405 fprintf(stderr,
" -g print lift/drag table: aoa, lift, drag, lift/drag \n");
406 fprintf(stderr,
" -d print drag over TAS: kts, drag\n");
407 fprintf(stderr,
" -D print kts at lowest drag at specified altitude\n");
408 fprintf(stderr,
" --aD print kts at lowest drag at different altitudes\n");
409 fprintf(stderr,
" -a set altitude in meters!\n");
410 fprintf(stderr,
" -s set speed in knots\n");
411 fprintf(stderr,
" -m print mass distribution table: id, x, y, z, mass \n");
412 fprintf(stderr,
" Options to generate LD curve and greater detailed plotting\n");
413 fprintf(stderr,
" yasim <aircraft.xml> [--detailed-graph] [--detailed-drag]\n");
414 fprintf(stderr,
" yasim <aircraft.xml> [--detailed-min-speed -approach]\n");
415 fprintf(stderr,
" yasim <aircraft.xml> [--detailed-min-speed -cruise]\n");
416 fprintf(stderr,
" -test print summary and output like -g -m \n");
423 FGFDM* fdm =
new FGFDM();
424 Airplane* a = fdm->getAirplane();
426 if (argc < 2 || !strcmp(argv[1],
"-h") || !strcmp(argv[1],
"--help")) {
431 string file = argv[1];
432 readXML(SGPath(file), *fdm);
434 catch (
const sg_exception &e) {
435 printf(
"XML parse error: %s (%s)\n", e.getFormattedMessage().c_str(), e.getOrigin());
438 bool verbose {
false};
439 if (argc > 2 && strcmp(argv[2],
"-v") == 0) {
442 if ((argc == 4) && (strcmp(argv[2],
"--tweak") == 0)) {
443 float tweak = std::atof(argv[3]);
444 a->setSolverTweak(tweak);
445 a->setSolverMaxIterations(2000);
449 if(a->getFailureMsg()) {
450 printf(
"SOLUTION FAILURE: %s\n", a->getFailureMsg());
452 if(!a->getFailureMsg() && argc > 2 ) {
453 bool test = (strcmp(argv[2],
"-test") == 0);
454 Airplane::Configuration cfg = Airplane::NONE;
455 float alt = 5000, kts = 100;
458 if((strcmp(argv[2],
"--detailed-graph") == 0) || test) {
459 for(
int i=3;
i<argc;
i++) {
460 if (std::strcmp(argv[
i],
"-a") == 0) {
461 if (
i+1 < argc) alt = std::atof(argv[++
i]);
463 else if(std::strcmp(argv[
i],
"-s") == 0) {
464 if(
i+1 < argc) kts = std::atof(argv[++
i]);
466 else if(std::strcmp(argv[
i],
"-approach") == 0) cfg = Airplane::APPROACH;
467 else if(std::strcmp(argv[
i],
"-cruise") == 0) cfg = Airplane::CRUISE;
472 printf(
"\n#-- lift, drag at altitude %.0f meters, %.0f knots, Config %d --\n", alt, kts, cfg);
476 printf(
"\n#-- mass distribution --\n");
480 else if(strcmp(argv[2],
"--detailed-drag") == 0) {
481 float alt = 2000, aoa = a->getCruiseAoA();
482 for(
int i=3;
i<argc;
i++) {
483 if (std::strcmp(argv[
i],
"-a") == 0) {
484 if (
i+1 < argc) alt = std::atof(argv[++
i]);
486 else if(std::strcmp(argv[
i],
"-approach") == 0) cfg = Airplane::APPROACH;
487 else if(std::strcmp(argv[
i],
"-cruise") == 0) cfg = Airplane::CRUISE;
492 else if(strcmp(argv[2],
"--detailed-min-speed") == 0) {
494 for(
int i=3;
i<argc;
i++) {
495 if (std::strcmp(argv[
i],
"-a") == 0) {
496 if (
i+1 < argc) alt = std::atof(argv[++
i]);
498 else if(std::strcmp(argv[
i],
"-approach") == 0) cfg = Airplane::APPROACH;
499 else if(std::strcmp(argv[
i],
"-cruise") == 0) cfg = Airplane::CRUISE;
504 else if((strcmp(argv[2],
"-g") == 0) || test) {
505 for(
int i=3;
i<argc;
i++) {
506 if (std::strcmp(argv[
i],
"-a") == 0) {
507 if (
i+1 < argc) alt = std::atof(argv[++
i]);
509 else if(std::strcmp(argv[
i],
"-s") == 0) {
510 if(
i+1 < argc) kts = std::atof(argv[++
i]);
512 else if(std::strcmp(argv[
i],
"-approach") == 0) cfg = Airplane::APPROACH;
513 else if(std::strcmp(argv[
i],
"-cruise") == 0) cfg = Airplane::CRUISE;
518 printf(
"\n#-- lift, drag at altitude %.0f meters, %.0f knots, Config %d --\n", alt, kts, cfg);
522 printf(
"\n#-- mass distribution --\n");
526 else if(!strcmp(argv[2],
"-d") || !strcmp(argv[2],
"-D") || !strcmp(argv[2],
"--aD")) {
528 for(
int i=3;
i<argc;
i++) {
529 if (std::strcmp(argv[
i],
"-a") == 0) {
530 if (
i+1 < argc) alt = std::atof(argv[++
i]);
532 else if(std::strcmp(argv[
i],
"-approach") == 0) cfg = Airplane::APPROACH;
533 else if(std::strcmp(argv[
i],
"-cruise") == 0) cfg = Airplane::CRUISE;
536 if (strcmp(argv[2],
"-d") == 0) {
537 float aoa = a->getCruiseAoA();
540 else if (!strcmp(argv[2],
"-D")) {
541 float best_speed_kts;
545 printf(
"altitude=%gm: best speed=%g best_aoa_deg=%g drag=%g\n", alt, best_speed_kts, best_aoa_deg, best_drag);
547 else if (!strcmp(argv[2],
"--aD")) {
551 else if(strcmp(argv[2],
"-m") == 0) {
554 else if(strcmp(argv[2],
"--min-speed") == 0) {
556 for(
int i=3;
i<argc;
i++) {
557 if (std::strcmp(argv[
i],
"-a") == 0) {
558 if (
i+1 < argc) alt = std::atof(argv[++
i]);
560 else if(std::strcmp(argv[
i],
"-approach") == 0) cfg = Airplane::APPROACH;
561 else if(std::strcmp(argv[
i],
"-cruise") == 0) cfg = Airplane::CRUISE;
static const float DEG2RAD
void yasim_masses(Airplane *a)
void findMinSpeedDetailed(Airplane *a, float alt)
void yasim_drag_detailed(Airplane *a, const float aoa, const float alt, Airplane::Configuration cfgID)
double fgGetDouble(const char *name, double defaultValue=0.0)
Get a double value for a property.
void yasim_graph_detailed(Airplane *a, const float alt, const float kts, Airplane::Configuration cfgID)
bool fgGetBool(char const *name, bool def)
Get a bool value for a property.
bool fgSetBool(char const *name, bool val)
Set a bool value for a property.
void yasim_graph(Airplane *a, const float alt, const float kts, Airplane::Configuration cfgID)
void yasim_best_speed_at_height(Airplane *a, const float alt, Airplane::Configuration cfgID, bool verbose, float &o_best_speed_kts, float &o_best_drag, float &o_best_aoa_deg)
bool fgSetDouble(const char *name, double defaultValue=0.0)
Set a double value for a property.
float yasim_find_zero_lift_aoa(Airplane *a, const float alt, float kts, Airplane::Configuration cfgID, float *acc)
bool fgSetString(char const *name, char const *str)
Set a string value for a property.
void _setup(Airplane *a, Airplane::Configuration cfgID, float altitude)
void yasim_drag(Airplane *a, const float aoa, const float alt, Airplane::Configuration cfgID)
void yasim_show_best_speed_at_heights(Airplane *a, Airplane::Configuration cfgID)
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
float fgGetFloat(const char *name, float defaultValue)
Get a float value for a property.
bool fgSetFloat(const char *name, float val)
Set a float value for a property.
void _calculateAcceleration(Airplane *a, float aoa_rad, float speed_mps, float *output)
void findMinSpeed(Airplane *a, float alt)