first commit
This commit is contained in:
102
src/FDM/AIWake/AIWakeGroup.cxx
Normal file
102
src/FDM/AIWake/AIWakeGroup.cxx
Normal file
@@ -0,0 +1,102 @@
|
||||
// AIWakeGroup.hxx -- Group of AI wake meshes for the computation of the induced
|
||||
// wake.
|
||||
//
|
||||
// Written by Bertrand Coconnier, started April 2017.
|
||||
//
|
||||
// Copyright (C) 2017 Bertrand Coconnier - bcoconni@users.sf.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation; either version 2 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
// Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include <simgear/math/SGVec3.hxx>
|
||||
#include <simgear/math/SGGeod.hxx>
|
||||
#include <simgear/math/SGGeoc.hxx>
|
||||
#include <simgear/math/SGQuat.hxx>
|
||||
#include "Main/globals.hxx"
|
||||
#include "AIModel/performancedata.hxx"
|
||||
#include "AIModel/AIAircraft.hxx"
|
||||
#include "FDM/AIWake/AIWakeGroup.hxx"
|
||||
|
||||
AIWakeGroup::AIWakeGroup(void)
|
||||
{
|
||||
SGPropertyNode* _props = globals->get_props();
|
||||
_density_slugft = _props->getNode("environment/density-slugft3", true);
|
||||
}
|
||||
|
||||
void AIWakeGroup::AddAI(FGAIAircraft* ai)
|
||||
{
|
||||
int id = ai->getID();
|
||||
PerformanceData* perfData = ai->getPerformance();
|
||||
|
||||
if (_aiWakeData.find(id) == _aiWakeData.end()) {
|
||||
double span = perfData->wingSpan();
|
||||
double chord = perfData->wingChord();
|
||||
_aiWakeData[id] = AIWakeData(new WakeMesh(span, chord,
|
||||
std::string("AI:") + ai->_getName()));
|
||||
|
||||
SG_LOG(SG_FLIGHT, SG_DEV_ALERT,
|
||||
"Created mesh for " << ai->_getName() << " ID: #" << id);
|
||||
}
|
||||
|
||||
AIWakeData& data = _aiWakeData[id];
|
||||
data.visited = true;
|
||||
|
||||
data.position = ai->getCartPos() * SG_METER_TO_FEET;
|
||||
SGGeoc geoc = SGGeoc::fromCart(data.position);
|
||||
SGQuatd Te2l = SGQuatd::fromLonLatRad(geoc.getLongitudeRad(),
|
||||
geoc.getLatitudeRad());
|
||||
data.Te2b = Te2l * SGQuatd::fromYawPitchRollDeg(ai->_getHeading(),
|
||||
ai->getPitch(), 0.0);
|
||||
|
||||
double hVel = ai->getSpeed()*SG_KT_TO_FPS;
|
||||
double vVel = ai->getVerticalSpeedFPM()/60;
|
||||
double gamma = atan2(vVel, hVel);
|
||||
double vel = sqrt(hVel*hVel + vVel*vVel);
|
||||
double weight = perfData->weight();
|
||||
_aiWakeData[id].mesh->computeAoA(vel, _density_slugft->getDoubleValue(),
|
||||
weight*cos(gamma));
|
||||
}
|
||||
|
||||
SGVec3d AIWakeGroup::getInducedVelocityAt(const SGVec3d& pt) const
|
||||
{
|
||||
SGVec3d vi(0.,0.,0.);
|
||||
for (auto item : _aiWakeData) {
|
||||
AIWakeData& data = item.second;
|
||||
if (!data.visited) continue;
|
||||
|
||||
SGVec3d at = data.Te2b.transform(pt - data.position);
|
||||
vi += data.Te2b.backTransform(data.mesh->getInducedVelocityAt(at));
|
||||
}
|
||||
return vi;
|
||||
}
|
||||
|
||||
void AIWakeGroup::gc(void)
|
||||
{
|
||||
for (auto it=_aiWakeData.begin(); it != _aiWakeData.end(); ++it) {
|
||||
if (!(*it).second.visited) {
|
||||
SG_LOG(SG_FLIGHT, SG_DEV_ALERT, "Deleted mesh for aircraft #"
|
||||
<< (*it).first);
|
||||
_aiWakeData.erase(it);
|
||||
break; // erase has invalidated the iterator, other dead meshes (if
|
||||
// any) will be erased at the next time steps.
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &item : _aiWakeData) item.second.visited = false;
|
||||
}
|
||||
57
src/FDM/AIWake/AIWakeGroup.hxx
Normal file
57
src/FDM/AIWake/AIWakeGroup.hxx
Normal file
@@ -0,0 +1,57 @@
|
||||
// AIWakeGroup.hxx -- Group of AI wake meshes for the computation of the induced
|
||||
// wake.
|
||||
//
|
||||
// Written by Bertrand Coconnier, started April 2017.
|
||||
//
|
||||
// Copyright (C) 2017 Bertrand Coconnier - bcoconni@users.sf.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation; either version 2 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
// Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef _FG_AIWAKEGROUP_HXX
|
||||
#define _FG_AIWAKEGROUP_HXX
|
||||
|
||||
#include <simgear/props/propsfwd.hxx>
|
||||
|
||||
#include "FDM/AIWake/WakeMesh.hxx"
|
||||
|
||||
namespace FGTestApi { namespace PrivateAccessor { namespace FDM { class Accessor; } } }
|
||||
class FGAIAircraft;
|
||||
|
||||
class AIWakeGroup {
|
||||
friend class FGTestApi::PrivateAccessor::FDM::Accessor;
|
||||
|
||||
struct AIWakeData {
|
||||
explicit AIWakeData(WakeMesh* m = nullptr) : mesh(m) {}
|
||||
|
||||
SGVec3d position {SGVec3d::zeros()};
|
||||
SGQuatd Te2b {SGQuatd::unit()};
|
||||
bool visited {false};
|
||||
WakeMesh_ptr mesh;
|
||||
};
|
||||
|
||||
std::map<int, AIWakeData> _aiWakeData;
|
||||
SGPropertyNode_ptr _density_slugft;
|
||||
|
||||
public:
|
||||
AIWakeGroup(void);
|
||||
void AddAI(FGAIAircraft* ai);
|
||||
SGVec3d getInducedVelocityAt(const SGVec3d& pt) const;
|
||||
// Garbage collection
|
||||
void gc(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
82
src/FDM/AIWake/AeroElement.cxx
Normal file
82
src/FDM/AIWake/AeroElement.cxx
Normal file
@@ -0,0 +1,82 @@
|
||||
// AeroElement.cxx -- Mesh element for the computation of a wing wake.
|
||||
//
|
||||
// Written by Bertrand Coconnier, started March 2017.
|
||||
//
|
||||
// Copyright (C) 2017 Bertrand Coconnier - bcoconni@users.sf.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation; either version 2 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
// Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include <simgear/math/SGVec3.hxx>
|
||||
#include "AeroElement.hxx"
|
||||
|
||||
AeroElement::AeroElement(const SGVec3d& n1, const SGVec3d& n2,
|
||||
const SGVec3d& n3, const SGVec3d& n4)
|
||||
{
|
||||
p1 = 0.75*n2 + 0.25*n1;
|
||||
p2 = 0.75*n3 + 0.25*n4;
|
||||
normal = normalize(cross(n3 - n1, n2 - n4));
|
||||
collocationPt = 0.375*(n1 + n4) + 0.125*(n2 + n3);
|
||||
}
|
||||
|
||||
SGVec3d AeroElement::vortexInducedVel(const SGVec3d& p, const SGVec3d& n1,
|
||||
const SGVec3d& n2) const
|
||||
{
|
||||
SGVec3d r0 = n2-n1, r1 = p-n1, r2 = p-n2;
|
||||
SGVec3d v = cross(r1, r2);
|
||||
double vSqrNorm = dot(v, v);
|
||||
double r1SqrNorm = dot(r1, r1);
|
||||
double r2SqrNorm = dot(r2, r2);
|
||||
|
||||
if ((vSqrNorm < 1E-6) || (r1SqrNorm < 1E-6) || (r2SqrNorm < 1E-6))
|
||||
return SGVec3d::zeros();
|
||||
|
||||
r1 /= sqrt(r1SqrNorm);
|
||||
r2 /= sqrt(r2SqrNorm);
|
||||
v *= dot(r0, r1-r2) / (4.0*M_PI*vSqrNorm);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
SGVec3d AeroElement::semiInfVortexInducedVel(const SGVec3d& point,
|
||||
const SGVec3d& vEnd,
|
||||
const SGVec3d& vDir) const
|
||||
{
|
||||
SGVec3d r = point-vEnd;
|
||||
double rSqrNorm = dot(r, r);
|
||||
double denom = rSqrNorm - dot(r, vDir)*sqrt(rSqrNorm);
|
||||
|
||||
if (fabs(denom) < 1E-6)
|
||||
return SGVec3d::zeros();
|
||||
|
||||
SGVec3d v = cross(r, vDir);
|
||||
v /= 4*M_PI*denom;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
SGVec3d AeroElement::getInducedVelocity(const SGVec3d& p) const
|
||||
{
|
||||
const SGVec3d w(-1.,0.,0.);
|
||||
SGVec3d v = semiInfVortexInducedVel(p, p1, w);
|
||||
v -= semiInfVortexInducedVel(p, p2, w);
|
||||
v += vortexInducedVel(p, p1, p2);
|
||||
|
||||
return v;
|
||||
}
|
||||
48
src/FDM/AIWake/AeroElement.hxx
Normal file
48
src/FDM/AIWake/AeroElement.hxx
Normal file
@@ -0,0 +1,48 @@
|
||||
// AeroElement.hxx -- Mesh element for the computation of a wing wake.
|
||||
//
|
||||
// Written by Bertrand Coconnier, started March 2017.
|
||||
//
|
||||
// Copyright (C) 2017 Bertrand Coconnier - bcoconni@users.sf.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation; either version 2 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
// Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef _FG_AEROELEMENT_HXX
|
||||
#define _FG_AEROELEMENT_HXX
|
||||
|
||||
#include <simgear/math/SGMathFwd.hxx>
|
||||
|
||||
|
||||
class AeroElement : public SGReferenced {
|
||||
public:
|
||||
AeroElement(const SGVec3d& n1, const SGVec3d& n2, const SGVec3d& n3,
|
||||
const SGVec3d& n4);
|
||||
const SGVec3d& getNormal(void) const { return normal; }
|
||||
const SGVec3d& getCollocationPoint(void) const { return collocationPt; }
|
||||
SGVec3d getBoundVortex(void) const { return p2 - p1; }
|
||||
SGVec3d getBoundVortexMidPoint(void) const { return 0.5*(p1+p2); }
|
||||
SGVec3d getInducedVelocity(const SGVec3d& p) const;
|
||||
private:
|
||||
SGVec3d vortexInducedVel(const SGVec3d& p, const SGVec3d& n1,
|
||||
const SGVec3d& n2) const;
|
||||
SGVec3d semiInfVortexInducedVel(const SGVec3d& point, const SGVec3d& vEnd,
|
||||
const SGVec3d& vDir) const;
|
||||
SGVec3d p1, p2, normal, collocationPt;
|
||||
};
|
||||
|
||||
typedef SGSharedPtr<AeroElement> AeroElement_ptr;
|
||||
|
||||
#endif
|
||||
96
src/FDM/AIWake/AircraftMesh.cxx
Normal file
96
src/FDM/AIWake/AircraftMesh.cxx
Normal file
@@ -0,0 +1,96 @@
|
||||
// AircraftMesh.cxx -- Mesh for the computation of the wake induced force and
|
||||
// moment on an aircraft.
|
||||
|
||||
// Written by Bertrand Coconnier, started March 2017.
|
||||
//
|
||||
// Copyright (C) 2017 Bertrand Coconnier - bcoconni@users.sf.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation; either version 2 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
// Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include <simgear/math/SGVec3.hxx>
|
||||
#include <simgear/math/SGGeoc.hxx>
|
||||
#include <simgear/math/SGGeod.hxx>
|
||||
#include <simgear/math/SGQuat.hxx>
|
||||
#include "AircraftMesh.hxx"
|
||||
#include <FDM/flight.hxx>
|
||||
#include "AIWakeGroup.hxx"
|
||||
#include "AIModel/AIAircraft.hxx"
|
||||
extern "C" {
|
||||
#include "../LaRCsim/ls_matrix.h"
|
||||
}
|
||||
|
||||
AircraftMesh::AircraftMesh(double _span, double _chord, const std::string& name)
|
||||
: WakeMesh(_span, _chord, name)
|
||||
{
|
||||
collPt.resize(nelm, SGVec3d::zeros());
|
||||
midPt.resize(nelm, SGVec3d::zeros());
|
||||
}
|
||||
|
||||
void AircraftMesh::setPosition(const SGVec3d& _pos, const SGQuatd& orient)
|
||||
{
|
||||
SGVec3d pos = _pos * SG_METER_TO_FEET;
|
||||
SGGeoc geoc = SGGeoc::fromCart(pos);
|
||||
SGQuatd Te2l = SGQuatd::fromLonLatRad(geoc.getLongitudeRad(),
|
||||
geoc.getLatitudeRad());
|
||||
Te2b = Te2l * orient;
|
||||
|
||||
for (int i=0; i<nelm; ++i) {
|
||||
SGVec3d pt = elements[i]->getCollocationPoint();
|
||||
collPt[i] = pos + Te2b.backTransform(pt);
|
||||
pt = elements[i]->getBoundVortexMidPoint();
|
||||
midPt[i] = pos + Te2b.backTransform(pt);
|
||||
}
|
||||
}
|
||||
|
||||
SGVec3d AircraftMesh::GetForce(const AIWakeGroup& wg, const SGVec3d& vel,
|
||||
double rho)
|
||||
{
|
||||
std::vector<double> rhs;
|
||||
rhs.resize(nelm, 0.0);
|
||||
|
||||
for (int i=0; i<nelm; ++i)
|
||||
rhs[i] = dot(elements[i]->getNormal(),
|
||||
Te2b.transform(wg.getInducedVelocityAt(collPt[i])));
|
||||
|
||||
for (int i=1; i<=nelm; ++i) {
|
||||
Gamma[i][1] = 0.0;
|
||||
for (int k=1; k<=nelm; ++k)
|
||||
Gamma[i][1] += influenceMtx[i][k]*rhs[k-1];
|
||||
}
|
||||
|
||||
SGVec3d f(0.,0.,0.);
|
||||
moment = SGVec3d::zeros();
|
||||
|
||||
for (int i=0; i<nelm; ++i) {
|
||||
SGVec3d mp = elements[i]->getBoundVortexMidPoint();
|
||||
SGVec3d v = Te2b.transform(wg.getInducedVelocityAt(midPt[i]));
|
||||
v += getInducedVelocityAt(mp);
|
||||
|
||||
// The minus sign before vel to transform the aircraft velocity from the
|
||||
// body frame to wind frame.
|
||||
SGVec3d Fi = rho*Gamma[i+1][1]*cross(v-vel,
|
||||
elements[i]->getBoundVortex());
|
||||
f += Fi;
|
||||
moment += cross(mp, Fi);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
50
src/FDM/AIWake/AircraftMesh.hxx
Normal file
50
src/FDM/AIWake/AircraftMesh.hxx
Normal file
@@ -0,0 +1,50 @@
|
||||
// AircraftMesh.hxx -- Mesh for the computation of the wake induced force and
|
||||
// moment on an aircraft.
|
||||
//
|
||||
// Written by Bertrand Coconnier, started March 2017.
|
||||
//
|
||||
// Copyright (C) 2017 Bertrand Coconnier - bcoconni@users.sf.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation; either version 2 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
// Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef _FG_AEROMESH_HXX
|
||||
#define _FG_AEROMESH_HXX
|
||||
|
||||
#include "WakeMesh.hxx"
|
||||
|
||||
namespace FGTestApi { namespace PrivateAccessor { namespace FDM { class Accessor; } } }
|
||||
class FGAIAircraft;
|
||||
class AIWakeGroup;
|
||||
|
||||
class AircraftMesh : public WakeMesh {
|
||||
public:
|
||||
AircraftMesh(double _span, double _chord, const std::string& name);
|
||||
void setPosition(const SGVec3d& pos, const SGQuatd& orient);
|
||||
SGVec3d GetForce(const AIWakeGroup& wg, const SGVec3d& vel, double rho);
|
||||
const SGVec3d& GetMoment(void) const { return moment; };
|
||||
|
||||
private:
|
||||
friend class FGTestApi::PrivateAccessor::FDM::Accessor;
|
||||
|
||||
std::vector<SGVec3d> collPt, midPt;
|
||||
SGQuatd Te2b;
|
||||
SGVec3d moment;
|
||||
};
|
||||
|
||||
typedef SGSharedPtr<AircraftMesh> AircraftMesh_ptr;
|
||||
|
||||
#endif
|
||||
120
src/FDM/AIWake/WakeMesh.cxx
Normal file
120
src/FDM/AIWake/WakeMesh.cxx
Normal file
@@ -0,0 +1,120 @@
|
||||
// WakeMesh.cxx -- Mesh for the computation of a wing wake.
|
||||
//
|
||||
// Written by Bertrand Coconnier, started March 2017.
|
||||
//
|
||||
// Copyright (C) 2017 Bertrand Coconnier - bcoconni@users.sf.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation; either version 2 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
// Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include <simgear/math/SGVec3.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include "WakeMesh.hxx"
|
||||
extern "C" {
|
||||
#include "../LaRCsim/ls_matrix.h"
|
||||
}
|
||||
|
||||
WakeMesh::WakeMesh(double _span, double _chord, const std::string& aircraft_name)
|
||||
: nelm(10), span(_span), chord(_chord)
|
||||
{
|
||||
double y1 = -0.5*span;
|
||||
double ds = span / nelm;
|
||||
|
||||
for(int i=0; i<nelm; i++) {
|
||||
double y2 = y1 + ds;
|
||||
elements.push_back(new AeroElement(SGVec3d(-chord, y1, 0.),
|
||||
SGVec3d(0., y1, 0.),
|
||||
SGVec3d(0., y2, 0.),
|
||||
SGVec3d(-chord, y2, 0.)));
|
||||
y1 = y2;
|
||||
}
|
||||
|
||||
influenceMtx = nr_matrix(1, nelm, 1, nelm);
|
||||
Gamma = nr_matrix(1, nelm, 1, 1);
|
||||
|
||||
for (int i=0; i < nelm; ++i) {
|
||||
SGVec3d normal = elements[i]->getNormal();
|
||||
SGVec3d collPt = elements[i]->getCollocationPoint();
|
||||
|
||||
for (int j=0; j < nelm; ++j)
|
||||
influenceMtx[i+1][j+1] = dot(elements[j]->getInducedVelocity(collPt),
|
||||
normal);
|
||||
}
|
||||
|
||||
// Compute the inverse matrix with the Gauss-Jordan algorithm
|
||||
int ret = nr_gaussj(influenceMtx, nelm, nullptr, 0);
|
||||
if (ret) {
|
||||
// Something went wrong with the matrix inversion.
|
||||
|
||||
// 1. Nullify the influence matrix to disable the current aircraft wake.
|
||||
for (int i=0; i < nelm; ++i) {
|
||||
for (int j=0; j < nelm; ++j)
|
||||
influenceMtx[i+1][j+1] = 0.0;
|
||||
}
|
||||
// 2. Report the issue in the log.
|
||||
SG_LOG(SG_FLIGHT, SG_WARN,
|
||||
"Failed to build wake mesh. " << aircraft_name << " ( span:"
|
||||
<< _span << ", chord:" << _chord << ") wake will be ignored.");
|
||||
}
|
||||
}
|
||||
|
||||
WakeMesh::~WakeMesh()
|
||||
{
|
||||
nr_free_matrix(influenceMtx, 1, nelm, 1, nelm);
|
||||
nr_free_matrix(Gamma, 1, nelm, 1, 1);
|
||||
}
|
||||
|
||||
double WakeMesh::computeAoA(double vel, double rho, double weight)
|
||||
{
|
||||
for (int i=1; i<=nelm; ++i) {
|
||||
Gamma[i][1] = 0.0;
|
||||
for (int k=1; k<=nelm; ++k)
|
||||
Gamma[i][1] -= influenceMtx[i][k];
|
||||
Gamma[i][1] *= vel;
|
||||
}
|
||||
|
||||
// Compute the lift only. Velocities in the z direction are discarded
|
||||
// because they only produce drag. This include the vertical component
|
||||
// vel*sin(alpha) and the induced velocities on the bound vortex.
|
||||
// This assumption is only valid for small angles.
|
||||
SGVec3d f(0.,0.,0.);
|
||||
SGVec3d v(-vel, 0.0, 0.0);
|
||||
|
||||
for (int i=0; i<nelm; ++i)
|
||||
f += rho*Gamma[i+1][1]*cross(v, elements[i]->getBoundVortex());
|
||||
|
||||
double sinAlpha = -weight/f[2];
|
||||
|
||||
for (int i=1; i<=nelm; ++i)
|
||||
Gamma[i][1] *= sinAlpha;
|
||||
|
||||
return asin(sinAlpha);
|
||||
}
|
||||
|
||||
SGVec3d WakeMesh::getInducedVelocityAt(const SGVec3d& at) const
|
||||
{
|
||||
SGVec3d v(0., 0., 0.);
|
||||
|
||||
for (int i=0; i<nelm; ++i)
|
||||
v += Gamma[i+1][1] * elements[i]->getInducedVelocity(at);
|
||||
|
||||
return v;
|
||||
}
|
||||
51
src/FDM/AIWake/WakeMesh.hxx
Normal file
51
src/FDM/AIWake/WakeMesh.hxx
Normal file
@@ -0,0 +1,51 @@
|
||||
// WakeMesh.hxx -- Mesh for the computation of a wing wake.
|
||||
//
|
||||
// Written by Bertrand Coconnier, started March 2017.
|
||||
//
|
||||
// Copyright (C) 2017 Bertrand Coconnier - bcoconni@users.sf.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation; either version 2 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
// Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef _FG_WAKEMESH_HXX
|
||||
#define _FG_WAKEMESH_HXX
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "AeroElement.hxx"
|
||||
|
||||
namespace FGTestApi { namespace PrivateAccessor { namespace FDM { class Accessor; } } }
|
||||
|
||||
|
||||
class WakeMesh : public SGReferenced {
|
||||
public:
|
||||
WakeMesh(double _span, double _chord, const std::string& aircraft_name);
|
||||
virtual ~WakeMesh();
|
||||
double computeAoA(double vel, double rho, double weight);
|
||||
SGVec3d getInducedVelocityAt(const SGVec3d& at) const;
|
||||
|
||||
protected:
|
||||
friend class FGTestApi::PrivateAccessor::FDM::Accessor;
|
||||
|
||||
int nelm;
|
||||
double span, chord;
|
||||
std::vector<AeroElement_ptr> elements;
|
||||
double **influenceMtx, **Gamma;
|
||||
};
|
||||
|
||||
typedef SGSharedPtr<WakeMesh> WakeMesh_ptr;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user