1
0
Fork 0

Merge branch 'next' into comm-subsystem

Conflicts:
	src/ATC/trafficcontrol.cxx
	src/ATC/trafficcontrol.hxx
	src/Instrumentation/CMakeLists.txt
This commit is contained in:
adrian 2011-10-06 15:18:44 +03:00
commit 312447c565
210 changed files with 10719 additions and 5866 deletions

3
.gitignore vendored
View file

@ -22,4 +22,5 @@ CPackConfig.cmake
CPackSourceConfig.cmake
cmake_uninstall.cmake
CTestTestfile.cmake
.kdev4
*.kdev4

View file

@ -1,4 +1,4 @@
cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.6.4)
include (CheckFunctionExists)
include (CheckCSourceCompiles)
@ -10,14 +10,20 @@ project(FlightGear)
set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "add a postfix, usually d on windows")
set(CMAKE_RELEASE_POSTFIX "" CACHE STRING "add a postfix, usually empty on windows")
set(CMAKE_RELWITHDEBINFO_POSTFIX "rd" CACHE STRING "add a postfix, usually empty on windows")
set(CMAKE_MINSIZEREL_POSTFIX "s" CACHE STRING "add a postfix, usually empty on windows")
set(CMAKE_RELWITHDEBINFO_POSTFIX "" CACHE STRING "add a postfix, usually empty on windows")
set(CMAKE_MINSIZEREL_POSTFIX "" CACHE STRING "add a postfix, usually empty on windows")
# read 'version' file into a variable (stripping any newlines or spaces)
file(READ version versionFile)
string(STRIP ${versionFile} FLIGHTGEAR_VERSION)
#packaging
# split version string into components, note CMAKE_MATCH_0 is the entire regexp match
string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" CPACK_PACKAGE_VERSION ${FLIGHTGEAR_VERSION} )
set(CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
set(CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2})
set(CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3})
SET(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/COPYING")
SET(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README")
@ -27,6 +33,13 @@ set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules;${CMAKE_MODULE_PATH}")
# autoconf compatibility
set(PKGLIBDIR "foo")
# Change the default build type to something fast
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
FORCE)
endif(NOT CMAKE_BUILD_TYPE)
if($ENV{BUILD_ID})
set(HUDSON_BUILD_ID $ENV{BUILD_ID})
set(HUDSON_BUILD_NUMBER $ENV{BUILD_NUMBER})
@ -36,6 +49,13 @@ else()
set(HUDSON_BUILD_ID "none")
endif()
IF(APPLE)
set(EVENT_INPUT_DEFAULT 1)
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
# disabled while DBus / HAL / udev issues are decided
#set(EVENT_INPUT_DEFAULT 1)
endif()
find_package(Git)
if (GIT_FOUND)
execute_process(COMMAND git --git-dir ${PROJECT_SOURCE_DIR}/.git rev-parse HEAD
@ -54,11 +74,27 @@ option(ENABLE_LARCSIM "Set to ON to build FlightGear with LaRCsim FDM" ON)
option(ENABLE_YASIM "Set to ON to build FlightGear with YASIM FDM" ON)
option(ENABLE_JSBSIM "Set to ON to build FlightGear with JSBSim FDM" ON)
option(ENABLE_FGADMIN "Set to ON to build FlightGear with FGADMIN" ON)
option(EVENT_INPUT "Set to ON to build FlightGear with event-based Input support" OFF)
option(EVENT_INPUT "Set to ON to build FlightGear with event-based Input support" ${EVENT_INPUT_DEFAULT})
option(ENABLE_LIBSVN "Set to ON to build FlightGear/terrasync with libsvnclient support" ON)
option(ENABLE_RTI "Set to ON to build SimGear with RTI support" OFF)
option(WITH_FGPANEL "Set to ON to build the fgpanel application" ON)
set(MSVC_3RDPARTY_ROOT NOT_FOUND CACHE PATH "Location where the third-party dependencies are extracted")
if (MSVC)
GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_SOURCE_DIR} PATH)
if (CMAKE_CL_64)
SET(TEST_3RDPARTY_DIR "${PARENT_DIR}/3rdparty.x64")
else (CMAKE_CL_64)
SET(TEST_3RDPARTY_DIR "${PARENT_DIR}/3rdparty")
endif (CMAKE_CL_64)
if (EXISTS ${TEST_3RDPARTY_DIR})
set(MSVC_3RDPARTY_ROOT ${PARENT_DIR} CACHE PATH "Location where the third-party dependencies are extracted")
else (EXISTS ${TEST_3RDPARTY_DIR})
set(MSVC_3RDPARTY_ROOT NOT_FOUND CACHE PATH "Location where the third-party dependencies are extracted")
endif (EXISTS ${TEST_3RDPARTY_DIR})
else (MSVC)
set(MSVC_3RDPARTY_ROOT NOT_FOUND CACHE PATH "Location where the third-party dependencies are extracted")
endif (MSVC)
if(LOGGING)
# nothing
@ -70,20 +106,6 @@ if(SP_FDMS)
set(ENABLE_SP_FDM 1)
endif()
if(EVENT_INPUT)
message(STATUS "checking event-based Input")
find_package(DBus)
IF(APPLE)
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
else()
message(WARNING "event input is not supported on this platform yet")
endif()
else(EVENT_INPUT)
set(ENABLE_PLIB_JOYSTICK 1)
endif(EVENT_INPUT)
if (MSVC AND MSVC_3RDPARTY_ROOT)
message(STATUS "3rdparty files located in ${MSVC_3RDPARTY_ROOT}")
set( OSG_MSVC "msvc" )
@ -107,6 +129,24 @@ if (MSVC AND MSVC_3RDPARTY_ROOT)
set (OPENAL_LIBRARY_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/lib)
endif (MSVC AND MSVC_3RDPARTY_ROOT)
if(EVENT_INPUT)
message(STATUS "checking event-based Input")
IF(APPLE)
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
find_package(DBus)
if(NOT DBUS_FOUND)
message(WARNING "DBus not found, event input will be disabled")
set(EVENT_INPUT 0)
endif()
else()
message(WARNING "event input is not supported on this platform yet")
endif()
else(EVENT_INPUT)
set(ENABLE_PLIB_JOYSTICK 1)
endif(EVENT_INPUT)
# check required dependencies
find_package(Boost REQUIRED)
@ -151,37 +191,12 @@ check_cxx_source_compiles(
"
HAVE_CULLSETTINGS_CLEAR_MASK)
# library required by simgear
# XXX This should go in a module and only run if simgear is not shared.
if(HAVE_UNISTD_H)
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_INCLUDE_PATH})
check_cxx_source_compiles(
"#include <unistd.h>
#if !defined(_POSIX_TIMERS) || (0 >= _POSIX_TIMERS)
#error clock_gettime is not supported
#endif
int main() { return 0; }
"
HAVE_CLOCK_GETTIME)
endif(HAVE_UNISTD_H)
set(RT_LIBRARY "")
if(HAVE_CLOCK_GETTIME)
check_function_exists(clock_gettime CLOCK_GETTIME_IN_LIBC)
if(NOT CLOCK_GETTIME_IN_LIBC)
check_library_exists(rt clock_gettime "" HAVE_RT)
if(HAVE_RT)
set(RT_LIBRARY rt)
endif(HAVE_RT)
endif(NOT CLOCK_GETTIME_IN_LIBC)
endif(HAVE_CLOCK_GETTIME)
find_package(RTI)
if(RTI_FOUND)
set(FG_HAVE_HLA 1)
endif()
if(ENABLE_RTI)
find_package(RTI)
if(RTI_FOUND)
set(FG_HAVE_HLA 1)
endif(RTI_FOUND)
endif(ENABLE_RTI)
if(CMAKE_COMPILER_IS_GNUCXX)
set(WARNING_FLAGS -Wall)
@ -202,7 +217,6 @@ if(WIN32)
endif(MSVC)
set(NOMINMAX 1)
set( WINSOCK_LIBRARY "ws2_32.lib" )
endif(WIN32)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} ${MSVC_FLAGS} -D_REENTRANT")
@ -210,9 +224,9 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS} ${MSVC_FLAGS} -D_REENTR
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}")
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIR}
${ALUT_INCLUDE_DIR}
${ALUT_INCLUDE_DIR}
${OPENAL_INCLUDE_DIR}
${SIMGEAR_INCLUDE_DIR}
${PLIB_INCLUDE_DIR} )

View file

@ -161,7 +161,7 @@ if(${haveJs} GREATER -1)
find_library(CF_LIBRARY CoreFoundation)
set(JS_LIBS ${IOKIT_LIBRARY} ${CF_LIBRARY})
elseif(WIN32)
find_library(WINMM_LIBRARY winmm)
set(WINMM_LIBRARY winmm)
set(JS_LIBS ${WINMM_LIBRARY})
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
# anything needed here?

View file

@ -1,7 +1,7 @@
# Locate SimGear
# This module defines
# SIMGEAR_LIBRARIES
# SIMGEAR_FOUND, if false, do not try to link to SimGear
# SIMGEAR_FOUND, if false, do not try to link to SimGear
# SIMGEAR_INCLUDE_DIR, where to find the headers
#
# $SIMGEAR_DIR is an environment variable that would
@ -30,7 +30,7 @@
# /System/Library/Frameworks/SimGear.framework/Headers
#
# On OS X, this will prefer the Framework version (if found) over others.
# People will have to manually change the cache values of
# People will have to manually change the cache values of
# SimGear_LIBRARIES to override this selection or set the CMake environment
# CMAKE_INCLUDE_PATH to modify the search paths.
@ -38,7 +38,7 @@ include(SelectLibraryConfigurations)
FIND_PATH(SIMGEAR_INCLUDE_DIR simgear/math/SGMath.hxx
HINTS $ENV{SIMGEAR_DIR}
PATH_SUFFIXES include
PATH_SUFFIXES include
PATHS
~/Library/Frameworks
/Library/Frameworks
@ -63,6 +63,10 @@ FIND_LIBRARY(SIMGEAR_LIBRARIES
/opt
)
# dependent packages
find_package(ZLIB REQUIRED)
find_package(Threads REQUIRED)
macro(find_sg_component comp libs)
set(compLib "sg${comp}")
string(TOUPPER "SIMGEAR_${comp}" compLibBase)
@ -103,33 +107,22 @@ macro(find_sg_component comp libs)
endmacro()
if(${SIMGEAR_LIBRARIES} STREQUAL "SIMGEAR_LIBRARIES-NOTFOUND")
if(${SIMGEAR_LIBRARIES} STREQUAL "SIMGEAR_LIBRARIES-NOTFOUND")
set(SIMGEAR_LIBRARIES "") # clear value
set(SIMGEAR_CORE_LIBRARIES "") # clear value
if(NOT MSVC)
# Olaf indicates that linking the threads libs causes failures
# on MSVC builds
set(thread_lib threads)
endif(NOT MSVC)
# note the order here affects the order Simgear libraries are
# linked in, and hence ability to link when using a traditional
# linker such as GNU ld on Linux
set(comps
ephem
set(comps
tsync
environment
nasal
sky
material
tgdb
model
screen
bucket
bvh
util route
util
route
timing
${thread_lib}
io
serial
sound
@ -137,13 +130,49 @@ if(${SIMGEAR_LIBRARIES} STREQUAL "SIMGEAR_LIBRARIES-NOTFOUND")
props
xml
misc
debug
threads
debug
magvar
math)
set(scene_comps
ephem
sky
material
tgdb
model
screen)
foreach(component ${comps})
find_sg_component(${component} SIMGEAR_CORE_LIBRARIES)
endforeach()
foreach(component ${scene_comps})
find_sg_component(${component} SIMGEAR_LIBRARIES)
endforeach()
# again link order matters - scene libraires depend on core ones
list(APPEND SIMGEAR_LIBRARIES ${SIMGEAR_CORE_LIBRARIES})
set(SIMGEAR_CORE_LIBRARY_DEPENDENCIES
${CMAKE_THREAD_LIBS_INIT}
${ZLIB_LIBRARY})
if(WIN32)
list(APPEND SIMGEAR_CORE_LIBRARY_DEPENDENCIES ws2_32.lib)
endif(WIN32)
if(NOT MSVC)
# basic timing routines on non windows systems, may be also cygwin?!
check_function_exists(clock_gettime clock_gettime_in_libc)
if(NOT clock_gettime_in_libc)
check_library_exists(rt clock_gettime "" have_rt)
if(have_rt)
list(APPEND SIMGEAR_CORE_LIBRARY_DEPENDENCIES rt)
endif(have_rt)
endif(NOT clock_gettime_in_libc)
endif(NOT MSVC)
endif()
# now we've found SimGear, check its version
@ -157,14 +186,14 @@ SET(CMAKE_REQUIRED_INCLUDES ${SIMGEAR_INCLUDE_DIR})
check_cxx_source_runs(
"#include <cstdio>
#include \"simgear/version.h\"
#define xstr(s) str(s)
#define str(s) #s
#define MIN_MAJOR ${SimGear_FIND_VERSION_MAJOR}
#define MIN_MINOR ${SimGear_FIND_VERSION_MINOR}
#define MIN_MICRO ${SimGear_FIND_VERSION_PATCH}
int main() {
int major, minor, micro;
@ -185,6 +214,6 @@ check_cxx_source_runs(
SIMGEAR_VERSION_OK)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SimGear DEFAULT_MSG
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SimGear DEFAULT_MSG
SIMGEAR_LIBRARIES SIMGEAR_INCLUDE_DIR SIMGEAR_VERSION_OK)

View file

@ -3,6 +3,31 @@
include (CheckFunctionExists)
include (CheckIncludeFile)
include (CheckLibraryExists)
macro(find_static_component comp libs)
# account for alternative Windows svn distribution naming
if(MSVC)
set(compLib "lib${comp}")
else(MSVC)
set(compLib "${comp}")
endif(MSVC)
string(TOUPPER "${comp}" compLibBase)
set( compLibName ${compLibBase}_LIBRARY )
FIND_LIBRARY(${compLibName}
NAMES ${compLib}
HINTS $ENV{PLIBDIR}
PATH_SUFFIXES lib64 lib libs64 libs libs/Win32 libs/Win64
PATHS
/usr/local
/usr
/opt
)
list(APPEND ${libs} ${${compLibName}})
endmacro()
find_program(HAVE_APR_CONFIG apr-1-config)
if(HAVE_APR_CONFIG)
@ -16,13 +41,13 @@ if(HAVE_APR_CONFIG)
OUTPUT_STRIP_TRAILING_WHITESPACE)
# clean up some vars, or other CMake pieces complain
string(STRIP ${RAW_APR_LIBS} APR_LIBS)
string(STRIP "${RAW_APR_LIBS}" APR_LIBS)
else(HAVE_APR_CONFIG)
message(STATUS "apr-1-config not found, implement manual search for APR")
endif(HAVE_APR_CONFIG)
if(HAVE_APR_CONFIG)
if(HAVE_APR_CONFIG OR MSVC)
find_path(LIBSVN_INCLUDE_DIR svn_client.h
HINTS
$ENV{LIBSVN_DIR}
@ -32,19 +57,20 @@ if(HAVE_APR_CONFIG)
/usr
/opt
)
check_library_exists(svn_client-1 svn_client_checkout "" HAVE_LIB_SVNCLIENT)
check_library_exists(svn_subr-1 svn_cmdline_init "" HAVE_LIB_SVNSUBR)
check_library_exists(svn_ra-1 svn_ra_initialize "" HAVE_LIB_SVNRA)
set(LIBSVN_LIBRARIES "")
if (MSVC)
find_static_component("apr-1" LIBSVN_LIBRARIES)
else (MSVC)
list(APPEND LIBSVN_LIBRARIES ${APR_LIBS})
endif (MSVC)
find_static_component("svn_client-1" LIBSVN_LIBRARIES)
find_static_component("svn_subr-1" LIBSVN_LIBRARIES)
find_static_component("svn_ra-1" LIBSVN_LIBRARIES)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBSVN DEFAULT_MSG
HAVE_LIB_SVNSUBR
HAVE_LIB_SVNCLIENT
HAVE_LIB_SVNRA
LIBSVN_INCLUDE_DIR)
if(LIBSVN_FOUND)
set(LIBSVN_LIBRARIES "svn_client-1" "svn_subr-1" "svn_ra-1" ${APR_LIBS})
endif(LIBSVN_FOUND)
endif(HAVE_APR_CONFIG)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBSVN DEFAULT_MSG LIBSVN_LIBRARIES LIBSVN_INCLUDE_DIR)
if(NOT LIBSVN_FOUND)
set(LIBSVN_LIBRARIES "")
endif(NOT LIBSVN_FOUND)
endif(HAVE_APR_CONFIG OR MSVC)

View file

@ -530,7 +530,7 @@ case "${host}" in
esac
if test "$OPENAL_OK" == "no"; then
if test "$OPENAL_OK" = "no"; then
echo
echo "You *must* have the openal library installed on your system to build"
echo "SimGear!"
@ -541,7 +541,7 @@ if test "$OPENAL_OK" == "no"; then
exit
fi
if test "$ALUT_OK" == "no"; then
if test "$ALUT_OK" = "no"; then
echo
echo "You *must* have the alut library installed on your system to build"
echo "SimGear!"

View file

@ -0,0 +1,153 @@
!include "MUI.nsh"
!system 'osgversion --so-number > %TEMP%\osg-so-number.txt'
!system 'osgversion --version-number > %TEMP%\osg-version.txt'
!define /file OSGSoNumber $%TEMP%\osg-so-number.txt
!define /file OSGVersion $%TEMP%\osg-version.txt
!define /file FGVersion flightgear\version
!echo "osg-so is ${OSGSoNumber}"
Name "FlightGear Nightly vs2010"
OutFile fgfs_win32_vs2010_nightly_${FGVersion}.exe
; use LZMA for best compression
SetCompressor /FINAL /SOLID lzma
SetCompressorDictSize 64
InstallDir $PROGRAMFILES\FlightGear-nightly-2010
; Request admin privileges for Windows Vista
RequestExecutionLevel highest
; don't hang around
AutoCloseWindow true
!define UninstallKey "Software\Microsoft\Windows\CurrentVersion\Uninstall\FlightGear-nightly-2010"
!define FGBinDir "install\msvc100\FlightGear\bin"
!define FGRunDir "install\msvc100\fgrun"
!define OSGInstallDir "install\msvc100\OpenSceneGraph"
!define OSGPluginsDir "${OSGInstallDir}\bin\osgPlugins-${OSGVersion}"
!define ThirdPartyBinDir "3rdParty\bin"
!define MUI_ICON "flightgear\projects\VC90\flightgear.ico"
!define MUI_UNICON "flightgear\projects\VC90\flightgear.ico"
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_RIGHT
!define MUI_HEADERIMAGE_BITMAP "flightgear\package\Win-NSIS\fg-install-header.bmp" ; optional
;!define MUI_WELCOMEFINISHPAGE_BITMAP "welcome.bmp"
;!define MUI_UNWELCOMEFINISHPAGE_BITMAP "welcome.bmp"
!insertmacro MUI_PAGE_WELCOME
; include GPL license page
!insertmacro MUI_PAGE_LICENSE "flightgear\Copying"
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!define MUI_FINISHPAGE_RUN $INSTDIR\fgrun.exe
!define MUI_FINISHPAGE_RUN_TEXT "Run FlightGear now"
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
; The stuff to install
Section "" ;No components page, name is not important
SetShellVarContext all
; Set output path to the installation directory.
SetOutPath $INSTDIR
File ${FGBinDir}\fgfs.exe
File ${FGBinDir}\fgjs.exe
File ${FGBinDir}\terrasync.exe
File ${FGRunDir}\bin\fgrun.exe
File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osg.dll
File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osgDB.dll
File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osgGA.dll
File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osgParticle.dll
File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osgText.dll
File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osgUtil.dll
File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osgViewer.dll
File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osgSim.dll
File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osgFX.dll
File ${OSGInstallDir}\bin\ot12-OpenThreads.dll
File ${ThirdPartyBinDir}\*.dll
; VC runtime redistributables
File "$%VCINSTALLDIR%\redist\x86\Microsoft.VC100.CRT\*.dll"
File /r ${FGRunDir}\share
SetOutPath $INSTDIR\osgPlugins-${OSGVersion}
File ${OSGPluginsDir}\osgdb_ac.dll
File ${OSGPluginsDir}\osgdb_osg.dll
File ${OSGPluginsDir}\osgdb_osga.dll
File ${OSGPluginsDir}\osgdb_3ds.dll
File ${OSGPluginsDir}\osgdb_mdl.dll
File ${OSGPluginsDir}\osgdb_jpeg.dll
File ${OSGPluginsDir}\osgdb_rgb.dll
File ${OSGPluginsDir}\osgdb_png.dll
File ${OSGPluginsDir}\osgdb_dds.dll
File ${OSGPluginsDir}\osgdb_txf.dll
File ${OSGPluginsDir}\osgdb_serializers_osg.dll
File ${OSGPluginsDir}\osgdb_serializers_osganimation.dll
File ${OSGPluginsDir}\osgdb_serializers_osgfx.dll
File ${OSGPluginsDir}\osgdb_serializers_osgmanipulator.dll
File ${OSGPluginsDir}\osgdb_serializers_osgparticle.dll
File ${OSGPluginsDir}\osgdb_serializers_osgshadow.dll
File ${OSGPluginsDir}\osgdb_serializers_osgsim.dll
File ${OSGPluginsDir}\osgdb_serializers_osgterrain.dll
File ${OSGPluginsDir}\osgdb_serializers_osgtext.dll
File ${OSGPluginsDir}\osgdb_serializers_osgvolume.dll
File ${OSGPluginsDir}\osgdb_deprecated_osg.dll
File ${OSGPluginsDir}\osgdb_deprecated_osgparticle.dll
Exec '"$INSTDIR\fgrun.exe" --silent --fg-exe="$INSTDIR\fgfs.exe" --ts-exe="$INSTDIR\terrasync.exe" '
CreateDirectory "$SMPROGRAMS\FlightGear"
CreateShortCut "$SMPROGRAMS\FlightGear\FlightGear-nightly-2010.lnk" "$INSTDIR\fgrun.exe"
WriteUninstaller "$INSTDIR\FlightGear_Uninstall.exe"
WriteRegStr HKLM ${UninstallKey} "DisplayName" "FlightGear Nightly (vs2010 build)"
WriteRegStr HKLM ${UninstallKey} "DisplayVersion" "${FGVersion}"
WriteRegStr HKLM ${UninstallKey} "UninstallString" "$INSTDIR\FlightGear_Uninstall.exe"
WriteRegStr HKLM ${UninstallKey} "UninstallPath" "$INSTDIR\FlightGear_Uninstall.exe"
WriteRegDWORD HKLM ${UninstallKey} "NoModify" 1
WriteRegDWORD HKLM ${UninstallKey} "NoRepair" 1
WriteRegStr HKLM ${UninstallKey} "URLInfoAbout" "http://www.flightgear.org/"
SectionEnd
Section "Uninstall"
SetShellVarContext all
Delete "$SMPROGRAMS\FlightGear\FlightGear-nightly-2010.lnk"
; only delete the FlightGear group if it's empty
RMDir "$SMPROGRAMS\FlightGear"
RMDir /r "$INSTDIR"
DeleteRegKey HKLM ${UninstallKey}
SectionEnd

View file

@ -36,7 +36,7 @@ DefaultGroupName=FlightGear {#FGVER}
LicenseFile=X:\data\COPYING
Uninstallable=yes
SetupIconFile=x:\flightgear.ico
VersionInfoVersion=2.0.0.0
VersionInfoVersion=2.5.0.0
WizardImageFile=X:\setupimg.bmp
WizardImageStretch=No
WizardSmallImageFile=X:\setupsmall.bmp

View file

@ -393,6 +393,14 @@
RelativePath="..\..\..\src\Aircraft\replay.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Aircraft\flightrecorder.cxx"
>
</File>
<File
RelativePath="..\..\..\src\Aircraft\flightrecorder.hxx"
>
</File>
</Filter>
<Filter
Name="Lib_Airports"
@ -836,6 +844,14 @@
<Filter
Name="models"
>
<File
RelativePath="..\..\..\src\FDM\JSBSim\models\FGAccelerations.cpp"
>
</File>
<File
RelativePath="..\..\..\src\FDM\JSBSim\models\FGAccelerations.h"
>
</File>
<File
RelativePath="..\..\..\src\Fdm\JSBSim\models\FGAerodynamics.cpp"
>
@ -1023,6 +1039,22 @@
RelativePath="..\..\..\src\Fdm\JSBSim\models\atmosphere\FGMSISData.cpp"
>
</File>
<File
RelativePath="..\..\..\src\FDM\JSBSim\models\atmosphere\FGStandardAtmosphere.cpp"
>
</File>
<File
RelativePath="..\..\..\src\FDM\JSBSim\models\atmosphere\FGStandardAtmosphere.h"
>
</File>
<File
RelativePath="..\..\..\src\FDM\JSBSim\models\atmosphere\FGWinds.cpp"
>
</File>
<File
RelativePath="..\..\..\src\FDM\JSBSim\models\atmosphere\FGWinds.h"
>
</File>
</Filter>
<Filter
Name="flight_control"
@ -1083,14 +1115,6 @@
RelativePath="..\..\..\src\Fdm\JSBSim\models\flight_control\FGGain.h"
>
</File>
<File
RelativePath="..\..\..\src\Fdm\JSBSim\models\flight_control\FGGradient.cpp"
>
</File>
<File
RelativePath="..\..\..\src\Fdm\JSBSim\models\flight_control\FGGradient.h"
>
</File>
<File
RelativePath="..\..\..\src\Fdm\JSBSim\models\flight_control\FGKinemat.cpp"
>
@ -3181,6 +3205,14 @@
<Filter
Name="Lib_Sound"
>
<File
RelativePath="..\..\..\src\Sound\audioident.cxx"
>
</File>
<File
RelativePath="..\..\..\src\Sound\audioident.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Sound\beacon.cxx"
>
@ -3213,6 +3245,14 @@
RelativePath="..\..\..\src\Sound\sample_queue.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Sound\soundgenerator.cxx"
>
</File>
<File
RelativePath="..\..\..\src\Sound\soundgenerator.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Sound\voice.cxx"
>
@ -3721,6 +3761,14 @@
RelativePath="..\..\..\src\Instrumentation\navradio.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Instrumentation\newnavradio.cxx"
>
</File>
<File
RelativePath="..\..\..\src\Instrumentation\newnavradio.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Instrumentation\od_gauge.cxx"
>
@ -3729,6 +3777,14 @@
RelativePath="..\..\..\src\Instrumentation\od_gauge.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Instrumentation\NavDisplay.cxx"
>
</File>
<File
RelativePath="..\..\..\src\Instrumentation\NavDisplay.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Instrumentation\rad_alt.cxx"
>
@ -4309,14 +4365,6 @@
<Filter
Name="Lib_ATC"
>
<File
RelativePath="..\..\..\src\ATC\atcdialog.cxx"
>
</File>
<File
RelativePath="..\..\..\src\ATC\atcdialog.hxx"
>
</File>
<File
RelativePath="..\..\..\src\ATC\atc_mgr.cxx"
>
@ -4325,6 +4373,14 @@
RelativePath="..\..\..\src\ATC\atc_mgr.hxx"
>
</File>
<File
RelativePath="..\..\..\src\ATC\atcdialog.cxx"
>
</File>
<File
RelativePath="..\..\..\src\ATC\atcdialog.hxx"
>
</File>
<File
RelativePath="..\..\..\src\ATC\CommStation.cxx"
>

View file

@ -1,4 +1,4 @@
// FGAIAircraft - FGAIBase-derived class creates an AI airplane
// // FGAIAircraft - FGAIBase-derived class creates an AI airplane
//
// Written by David Culp, started October 2003.
//
@ -48,8 +48,6 @@ using std::string;
#include "performancedata.hxx"
#include "performancedb.hxx"
#define TGT_VS_CUTOFF 10000
//#include <Airports/trafficcontroller.hxx>
static string tempReg;
@ -157,7 +155,6 @@ void FGAIAircraft::setPerformance(const std::string& acclass) {
void FGAIAircraft::Run(double dt) {
FGAIAircraft::dt = dt;
bool outOfSight = false,
@ -358,14 +355,9 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) {
tgt_altitude_ft = prev->getAltitude();
if (curr->getCrossat() > -1000.0) {
use_perf_vs = false;
// tgt_vs = (curr->getCrossat() - altitude_ft) / (fp->getDistanceToGo(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr)
// / 6076.0 / speed*60.0);
// if (fabs(tgt_vs) > TGT_VS_CUTOFF) { SG_LOG(SG_GENERAL, SG_ALERT, "Rediculously high vertical speed caculated at " << SG_ORIGIN << ". Corresponding to " << (tgt_vs * .005) << "degrees of pitch angle" << prev->getName()); };
// if (tgt_vs < -1500)
// tgt_vs = -1500;
// if (tgt_vs > 1500)
// tgt_vs = 1500;
// checkTcas();
tgt_vs = (curr->getCrossat() - altitude_ft) / (fp->getDistanceToGo(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr)
/ 6076.0 / speed*60.0);
checkTcas();
tgt_altitude_ft = curr->getCrossat();
} else {
use_perf_vs = true;
@ -505,7 +497,6 @@ void FGAIAircraft::getGroundElev(double dt) {
void FGAIAircraft::doGroundAltitude() {
if ((fabs(altitude_ft - (tgt_altitude_ft+groundOffset)) > 1000.0)||
(isStationary()))
altitude_ft = (tgt_altitude_ft + groundOffset);
@ -685,11 +676,10 @@ void FGAIAircraft::handleFirstWaypoint() {
if (curr->getCrossat() > -1000.0) //use a calculated descent/climb rate
{
use_perf_vs = false;
/* tgt_vs = (curr->getCrossat() - prev->getAltitude())
tgt_vs = (curr->getCrossat() - prev->getAltitude())
/ (fp->getDistanceToGo(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr)
/ 6076.0 / prev->getSpeed()*60.0);
if (fabs(tgt_vs) > TGT_VS_CUTOFF) { SG_LOG(SG_GENERAL, SG_ALERT, "Rediculously high vertical speed caculated at " << SG_ORIGIN); };
checkTcas();*/
checkTcas();
tgt_altitude_ft = curr->getCrossat();
} else {
use_perf_vs = true;

View file

@ -179,6 +179,27 @@ void FGAIBase::update(double dt) {
ft_per_deg_lon = 365228.16 * cos(pos.getLatitudeRad());
}
/** update LOD properties of the model */
void FGAIBase::updateLOD()
{
double maxRangeDetail = fgGetDouble("/sim/rendering/static-lod/ai-detailed", 10000.0);
double maxRangeBare = fgGetDouble("/sim/rendering/static-lod/ai-bare", 20000.0);
if (_model.valid())
{
if( maxRangeDetail == 0.0 )
{
// disable LOD
_model->setRange(0, 0.0, FLT_MAX);
_model->setRange(1, FLT_MAX, FLT_MAX);
}
else
{
_model->setRange(0, 0.0, maxRangeDetail);
_model->setRange(1, maxRangeDetail,maxRangeBare);
}
}
}
void FGAIBase::Transform() {
if (!invisible) {
@ -226,23 +247,22 @@ bool FGAIBase::init(bool search_in_AI_path) {
_installed = true;
osg::Node * mdl = SGModelLib::loadPagedModel(f, props, new FGNasalModelData(props));
model = mdl;
double aiModelMaxRange = fgGetDouble("/sim/rendering/static-lod/ai", 0.0);
if( aiModelMaxRange > 0.0 ) {
osg::LOD * lod = new osg::LOD;
lod->setName("AI-model range animation node");
_model = new osg::LOD;
_model->setName("AI-model range animation node");
lod->addChild( mdl, 0, aiModelMaxRange );
lod->setCenterMode(osg::LOD::USE_BOUNDING_SPHERE_CENTER);
lod->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT);
model = lod;
}
_model->addChild( mdl, 0, FLT_MAX );
_model->setCenterMode(osg::LOD::USE_BOUNDING_SPHERE_CENTER);
_model->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT);
// We really need low-resolution versions of AI/MP aircraft.
// Or at least dummy "stubs" with some default silhouette.
// _model->addChild( SGModelLib::loadPagedModel(fgGetString("/sim/multiplay/default-model", default_model),
// props, new FGNasalModelData(props)), FLT_MAX, FLT_MAX);
updateLOD();
initModel(mdl);
if (model.valid() && _initialized == false) {
aip.init( model.get() );
if (_model.valid() && _initialized == false) {
aip.init( _model.get() );
aip.setVisible(true);
invisible = false;
globals->get_scenery()->get_scene_graph()->addChild(aip.getSceneGraph());
@ -260,7 +280,7 @@ bool FGAIBase::init(bool search_in_AI_path) {
void FGAIBase::initModel(osg::Node *node)
{
if (model.valid()) {
if (_model.valid()) {
if( _path != ""){
props->setStringValue("submodels/path", _path.c_str());
@ -523,7 +543,7 @@ SGVec3d FGAIBase::getCartPos() const {
bool FGAIBase::getGroundElevationM(const SGGeod& pos, double& elev,
const SGMaterial** material) const {
return globals->get_scenery()->get_elevation_m(pos, elev, material,
model.get());
_model.get());
}
double FGAIBase::_getCartPosX() const {

View file

@ -64,6 +64,7 @@ public:
virtual void unbind();
virtual void reinit() {}
void updateLOD();
void setManager(FGAIManager* mgr, SGPropertyNode* p);
void setPath( const char* model );
void setSMPath( const string& p );
@ -186,7 +187,6 @@ protected:
double ht_diff; // value used by radar display instrument
string model_path; //Path to the 3D model
osg::ref_ptr<osg::Node> model; //The 3D model object
SGModelPlacement aip;
bool delete_me;
@ -222,6 +222,7 @@ private:
int _refID;
object_type _otype;
bool _initialized;
osg::ref_ptr<osg::LOD> _model; //The 3D model LOD object
public:
object_type getType();

View file

@ -71,7 +71,6 @@ bool FGAIWaypoint::contains(string target) {
FGAIFlightPlan::FGAIFlightPlan()
{
rwy = 0;
sid = 0;
repeat = false;
distance_to_go = 0;

View file

@ -166,7 +166,6 @@ public:
FGAIWaypoint *getLastWaypoint() { return waypoints.back(); };
private:
FGRunway* rwy;
FGAIFlightPlan *sid;
typedef std::vector <FGAIWaypoint*> wpt_vector_type;
typedef wpt_vector_type::const_iterator wpt_vector_iterator;

View file

@ -62,6 +62,11 @@ bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
case 1:
retVal = createPushBack(ac, firstFlight, dep, latitude, longitude,
radius, fltType, aircraftType, airline);
// Pregenerate the
if (retVal) {
waypoints.back()->setName( waypoints.back()->getName() + string("legend"));
retVal = createTakeoffTaxi(ac, false, dep, radius, fltType, aircraftType, airline);
}
break;
case 2:
retVal = createTakeoffTaxi(ac, firstFlight, dep, radius, fltType,
@ -226,7 +231,8 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
depHeading);
}
rwy = apt->getRunwayByIdent(activeRunway);
FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
assert( rwy != NULL );
SGGeod runwayTakeoff = rwy->pointOnCenterline(5.0);
FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork();
@ -456,9 +462,8 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
heading);
}
rwy = apt->getRunwayByIdent(activeRunway);
FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
assert( rwy != NULL );
double airportElev = apt->getElevation();
@ -513,7 +518,6 @@ bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
double heading = ac->getTrafficRef()->getCourse();
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
heading);
rwy = apt->getRunwayByIdent(activeRunway);
}
if (sid) {
for (wpt_vector_iterator i = sid->getFirstWayPoint();
@ -522,6 +526,9 @@ bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
//cerr << " Cloning waypoint " << endl;
}
} else {
FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
assert( rwy != NULL );
SGGeod climb1 = rwy->pointOnCenterline(10 * SG_NM_TO_METER);
wpt = createInAir(ac, "10000ft climb", climb1, vClimb, 10000);
wpt->setGear_down(true);
@ -560,9 +567,8 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
double heading = ac->getTrafficRef()->getCourse();
apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway,
heading);
rwy = apt->getRunwayByIdent(activeRunway);
FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
assert( rwy != NULL );
// Create a slow descent path that ends 250 lateral to the runway.
double initialTurnRadius = getTurnRadius(vDescent, true);
@ -859,6 +865,9 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
char buffer[12];
for (int i = 1; i < 10; i++) {
snprintf(buffer, 12, "wpt%d", i);
FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
assert( rwy != NULL );
coord = rwy->pointOnCenterline(rwy->lengthM() * (i / 10.0));
wpt = createOnGround(ac, buffer, coord, aptElev, (vTouchdown / i));
wpt->setCrossat(apt->getElevation());

View file

@ -299,7 +299,8 @@ bool FGAIFlightPlan::createCruise(FGAIAircraft *ac, bool firstFlight, FGAirport
string rwyClass = getRunwayClassFromTrafficType(fltType);
double heading = ac->getTrafficRef()->getCourse();
arr->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
rwy = arr->getRunwayByIdent(activeRunway);
FGRunway* rwy = arr->getRunwayByIdent(activeRunway);
assert( rwy != NULL );
// begin descent 110km out
SGGeod beginDescentPoint = rwy->pointOnCenterline(0);
SGGeod secondaryDescentPoint = rwy->pointOnCenterline(-10000);

View file

@ -1,22 +1,22 @@
/****************************************************************************
* AIFlightPlanCreatePushBack.cxx
* Written by Durk Talsma, started August 1, 2007.
*
* 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.
*
**************************************************************************/
* AIFlightPlanCreatePushBack.cxx
* Written by Durk Talsma, started August 1, 2007.
*
* 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.
*
**************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
@ -38,13 +38,13 @@
// TODO: Use James Turner's createOnGround functions.
bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
bool firstFlight, FGAirport *dep,
double latitude,
double longitude,
double radius,
const string& fltType,
const string& aircraftType,
const string& airline)
bool firstFlight, FGAirport *dep,
double latitude,
double longitude,
double radius,
const string& fltType,
const string& aircraftType,
const string& airline)
{
double lat, lon, heading;
double vTaxi = ac->getPerformance()->vTaxi();
@ -57,72 +57,72 @@ bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
if (!(dep->getDynamics()->getGroundNetwork()->exists())) {
//cerr << "Push Back fallback" << endl;
createPushBackFallBack(ac, firstFlight, dep, latitude, longitude,
radius, fltType, aircraftType, airline);
createPushBackFallBack(ac, firstFlight, dep, latitude, longitude,
radius, fltType, aircraftType, airline);
} else {
if (firstFlight) {
if (!(dep->getDynamics()->getAvailableParking(&lat, &lon,
&heading, &gateId,
radius, fltType,
aircraftType, airline))) {
SG_LOG(SG_INPUT, SG_WARN, "Warning: Could not find parking for a " <<
aircraftType <<
" of flight type " << fltType <<
" of airline " << airline <<
" at airport " << dep->getId());
return false;
char buffer[10];
snprintf (buffer, 10, "%d", gateId);
SGGeod coord = coord.fromDeg(lon, lat);
//FGTaxiNode *tn = dep->getDynamics()->getGroundNetwork()->findNode(node);
FGAIWaypoint *wpt = createOnGround(ac, string(buffer), coord, dep->getElevation(), vTaxiBackward);
wpt->setRouteIndex(-1);
waypoints.push_back(wpt);
}
//cerr << "Success : GateId = " << gateId << endl;
SG_LOG(SG_INPUT, SG_WARN, "Warning: Succesfully found a parking for a " <<
aircraftType <<
" of flight type " << fltType <<
" of airline " << airline <<
" at airport " << dep->getId());
} else {
if (firstFlight) {
if (!(dep->getDynamics()->getAvailableParking(&lat, &lon,
&heading, &gateId,
radius, fltType,
aircraftType, airline))) {
SG_LOG(SG_INPUT, SG_WARN, "Warning: Could not find parking for a " <<
aircraftType <<
" of flight type " << fltType <<
" of airline " << airline <<
" at airport " << dep->getId());
return false;
char buffer[10];
snprintf (buffer, 10, "%d", gateId);
SGGeod coord = coord.fromDeg(lon, lat);
//FGTaxiNode *tn = dep->getDynamics()->getGroundNetwork()->findNode(node);
FGAIWaypoint *wpt = createOnGround(ac, string(buffer), coord, dep->getElevation(), vTaxiBackward);
wpt->setRouteIndex(-1);
waypoints.push_back(wpt);
}
//cerr << "Success : GateId = " << gateId << endl;
SG_LOG(SG_INPUT, SG_WARN, "Warning: Succesfully found a parking for a " <<
aircraftType <<
" of flight type " << fltType <<
" of airline " << airline <<
" at airport " << dep->getId());
} else {
//cerr << "Push Back follow-up Flight" << endl;
dep->getDynamics()->getParking(gateId, &lat, &lon, &heading);
}
if (gateId < 0) {
createPushBackFallBack(ac, firstFlight, dep, latitude, longitude,
radius, fltType, aircraftType, airline);
return true;
dep->getDynamics()->getParking(gateId, &lat, &lon, &heading);
}
if (gateId < 0) {
createPushBackFallBack(ac, firstFlight, dep, latitude, longitude,
radius, fltType, aircraftType, airline);
return true;
}
}
//cerr << "getting parking " << gateId;
//cerr << " for a " <<
// aircraftType <<
// " of flight type " << fltType <<
// " of airline " << airline <<
// " at airport " << dep->getId() << endl;
//cerr << " for a " <<
// aircraftType <<
// " of flight type " << fltType <<
// " of airline " << airline <<
// " at airport " << dep->getId() << endl;
FGParking *parking = dep->getDynamics()->getParking(gateId);
int pushBackNode = parking->getPushBackPoint();
int pushBackNode = parking->getPushBackPoint();
pushBackRoute = parking->getPushBackRoute();
if ((pushBackNode > 0) && (pushBackRoute == 0)) { // Load the already established route for this gate
int node, rte;
FGTaxiRoute route;
//cerr << "Creating push-back for " << gateId << " (" << parking->getName() << ") using push-back point " << pushBackNode << endl;
route = dep->getDynamics()->getGroundNetwork()->findShortestRoute(gateId, pushBackNode, false);
parking->setPushBackRoute(new FGTaxiRoute(route));
pushBackRoute = parking->getPushBackRoute();
if ((pushBackNode > 0) && (pushBackRoute == 0)) { // Load the already established route for this gate
int node, rte;
FGTaxiRoute route;
//cerr << "Creating push-back for " << gateId << " (" << parking->getName() << ") using push-back point " << pushBackNode << endl;
route = dep->getDynamics()->getGroundNetwork()->findShortestRoute(gateId, pushBackNode, false);
parking->setPushBackRoute(new FGTaxiRoute(route));
pushBackRoute = parking->getPushBackRoute();
int size = pushBackRoute->size();
if (size < 2) {
pushBackRoute = parking->getPushBackRoute();
int size = pushBackRoute->size();
if (size < 2) {
SG_LOG(SG_GENERAL, SG_WARN, "Push back route from gate " << gateId << " has only " << size << " nodes.");
SG_LOG(SG_GENERAL, SG_WARN, "Using " << pushBackNode);
}
pushBackRoute->first();
while(pushBackRoute->next(&node, &rte))
SG_LOG(SG_GENERAL, SG_WARN, "Using " << pushBackNode);
}
pushBackRoute->first();
while(pushBackRoute->next(&node, &rte))
{
//FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findSegment(node)->getEnd();
char buffer[10];
@ -130,70 +130,73 @@ bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
FGTaxiNode *tn = dep->getDynamics()->getGroundNetwork()->findNode(node);
//ids.pop_back();
//wpt = new waypoint;
SGGeod coord = coord.fromDeg(tn->getLongitude(), tn->getLatitude());
FGAIWaypoint *wpt = createOnGround(ac, string(buffer), coord, dep->getElevation(), vTaxiBackward);
SGGeod coord = coord.fromDeg(tn->getLongitude(), tn->getLatitude());
FGAIWaypoint *wpt = createOnGround(ac, string(buffer), coord, dep->getElevation(), vTaxiBackward);
wpt->setRouteIndex(rte);
waypoints.push_back(wpt);
}
// some special considerations for the last point:
waypoints.back()->setName(string("PushBackPoint"));
waypoints.back()->setSpeed(vTaxi);
ac->setTaxiClearanceRequest(true);
} else { // In case of a push forward departure...
ac->setTaxiClearanceRequest(false);
double lat2 = 0.0, lon2 = 0.0, az2 = 0.0;
// some special considerations for the last point:
waypoints.back()->setName(string("PushBackPoint"));
waypoints.back()->setSpeed(vTaxi);
ac->setTaxiClearanceRequest(true);
} else { // In case of a push forward departure...
ac->setTaxiClearanceRequest(false);
double lat2 = 0.0, lon2 = 0.0, az2 = 0.0;
//cerr << "Creating final push forward point for gate " << gateId << endl;
FGTaxiNode *tn = dep->getDynamics()->getGroundNetwork()->findNode(gateId);
FGTaxiSegmentVectorIterator ts = tn->getBeginRoute();
FGTaxiSegmentVectorIterator te = tn->getEndRoute();
if (ts == te) {
SG_LOG(SG_GENERAL, SG_ALERT, "Gate " << gateId << "doesn't seem to have routes associated with it.");
//exit(1);
}
tn = (*ts)->getEnd();
lastNodeVisited = tn->getIndex();
if (tn == NULL) {
SG_LOG(SG_GENERAL, SG_ALERT, "No valid taxinode found");
exit(1);
}
double distance = (*ts)->getLength();
//cerr << "Length of push forward route = " << distance << " and heading is " << heading << endl;
lat2 = tn->getLatitude();
lon2 = tn->getLongitude();
//cerr << "Creating final push forward point for gate " << gateId << endl;
FGTaxiNode *tn = dep->getDynamics()->getGroundNetwork()->findNode(gateId);
FGTaxiSegmentVectorIterator ts = tn->getBeginRoute();
FGTaxiSegmentVectorIterator te = tn->getEndRoute();
// if the starting node equals the ending node, then there aren't any routes for this parking.
// in cases like these we should flag the gate as being inoperative and return false
if (ts == te) {
SG_LOG(SG_GENERAL, SG_ALERT, "Gate " << gateId << "doesn't seem to have routes associated with it.");
parking->setAvailable(false);
return false;
}
tn = (*ts)->getEnd();
lastNodeVisited = tn->getIndex();
if (tn == NULL) {
SG_LOG(SG_GENERAL, SG_ALERT, "No valid taxinode found");
exit(1);
}
double distance = (*ts)->getLength();
//cerr << "Length of push forward route = " << distance << " and heading is " << heading << endl;
lat2 = tn->getLatitude();
lon2 = tn->getLongitude();
for (int i = 1; i < 10; i++) {
geo_direct_wgs_84 ( 0, lat, lon, heading,
((i / 10.0) * distance), &lat2, &lon2, &az2 );
char buffer[16];
snprintf(buffer, 16, "pushback-%02d", i);
SGGeod coord = coord.fromDeg(lon2, lat2);
//cerr << i << endl;
FGAIWaypoint *wpt = createOnGround(ac, string(buffer), coord, dep->getElevation(), vTaxiReduced);
for (int i = 1; i < 10; i++) {
geo_direct_wgs_84 ( 0, lat, lon, heading,
((i / 10.0) * distance), &lat2, &lon2, &az2 );
char buffer[16];
snprintf(buffer, 16, "pushback-%02d", i);
SGGeod coord = coord.fromDeg(lon2, lat2);
//cerr << i << endl;
FGAIWaypoint *wpt = createOnGround(ac, string(buffer), coord, dep->getElevation(), vTaxiReduced);
wpt->setRouteIndex((*ts)->getIndex());
waypoints.push_back(wpt);
}
// cerr << "Done " << endl;
waypoints.back()->setName(string("PushBackPoint"));
// cerr << "Done assinging new name" << endl;
}
wpt->setRouteIndex((*ts)->getIndex());
waypoints.push_back(wpt);
}
// cerr << "Done " << endl;
waypoints.back()->setName(string("PushBackPoint"));
// cerr << "Done assinging new name" << endl;
}
}
return true;
}
/*******************************************************************
* createPushBackFallBack
* This is the backup function for airports that don't have a
* network yet.
******************************************************************/
* createPushBackFallBack
* This is the backup function for airports that don't have a
* network yet.
******************************************************************/
void FGAIFlightPlan::createPushBackFallBack(FGAIAircraft *ac, bool firstFlight, FGAirport *dep,
double latitude,
double longitude,
double radius,
const string& fltType,
const string& aircraftType,
const string& airline)
double latitude,
double longitude,
double radius,
const string& fltType,
const string& aircraftType,
const string& airline)
{
double heading;
double lat;
@ -212,7 +215,7 @@ void FGAIFlightPlan::createPushBackFallBack(FGAIAircraft *ac, bool firstFlight,
heading += 180.0;
if (heading > 360)
heading -= 360;
heading -= 360;
SGGeod coord = coord.fromDeg(lon, lat);
FGAIWaypoint *wpt = createOnGround(ac, string("park"), coord, dep->getElevation(), vTaxiBackward);
@ -220,16 +223,16 @@ void FGAIFlightPlan::createPushBackFallBack(FGAIAircraft *ac, bool firstFlight,
waypoints.push_back(wpt);
geo_direct_wgs_84 ( 0, lat, lon, heading,
10,
&lat2, &lon2, &az2 );
10,
&lat2, &lon2, &az2 );
coord = coord.fromDeg(lon2, lat2);
wpt = createOnGround(ac, string("park2"), coord, dep->getElevation(), vTaxiBackward);
waypoints.push_back(wpt);
geo_direct_wgs_84 ( 0, lat, lon, heading,
2.2*radius,
&lat2, &lon2, &az2 );
2.2*radius,
&lat2, &lon2, &az2 );
coord = coord.fromDeg(lon2, lat2);
wpt = createOnGround(ac, string("taxiStart"), coord, dep->getElevation(), vTaxiReduced);
waypoints.push_back(wpt);

View file

@ -43,7 +43,12 @@
#include "AIGroundVehicle.hxx"
#include "AIEscort.hxx"
FGAIManager::FGAIManager() {
FGAIManager::FGAIManager() :
cb_ai_bare(SGPropertyChangeCallback<FGAIManager>(this,&FGAIManager::updateLOD,
fgGetNode("/sim/rendering/static-lod/ai-bare", true))),
cb_ai_detailed(SGPropertyChangeCallback<FGAIManager>(this,&FGAIManager::updateLOD,
fgGetNode("/sim/rendering/static-lod/ai-detailed", true)))
{
_dt = 0.0;
mNumAiModels = 0;
@ -181,6 +186,18 @@ FGAIManager::update(double dt) {
thermal_lift_node->setDoubleValue( strength ); // for thermals
}
/** update LOD settings of all AI/MP models */
void
FGAIManager::updateLOD(SGPropertyNode* node)
{
ai_list_iterator ai_list_itr = ai_list.begin();
while(ai_list_itr != ai_list.end())
{
(*ai_list_itr)->updateLOD();
++ai_list_itr;
}
}
void
FGAIManager::attach(FGAIBase *model)
{

View file

@ -27,6 +27,7 @@
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/props/props_io.hxx>
#include <Main/fg_props.hxx>
@ -66,6 +67,7 @@ public:
void bind();
void unbind();
void update(double dt);
void updateLOD(SGPropertyNode* node);
void attach(FGAIBase *model);
void destroyObject( int ID );
@ -135,6 +137,8 @@ private:
double strength;
void processThermal( FGAIThermal* thermal );
SGPropertyChangeCallback<FGAIManager> cb_ai_bare;
SGPropertyChangeCallback<FGAIManager> cb_ai_detailed;
};
#endif // _FG_AIMANAGER_HXX

View file

@ -6,5 +6,12 @@ set(SOURCES
trafficcontrol.cxx
CommStation.cxx
)
flightgear_component(ATC "${SOURCES}")
set(HEADERS
atc_mgr.hxx
atcdialog.hxx
trafficcontrol.hxx
CommStation.hxx
)
flightgear_component(ATC "${SOURCES}" "${HEADERS}")

View file

@ -37,6 +37,7 @@ FGATCManager::FGATCManager() {
controller = 0;
prevController = 0;
networkVisible = false;
initSucceeded = false;
}
FGATCManager::~FGATCManager() {
@ -45,8 +46,6 @@ FGATCManager::~FGATCManager() {
void FGATCManager::init() {
SGSubsystem::init();
currentATCDialog = new FGATCDialogNew;
currentATCDialog->init();
int leg = 0;
@ -110,7 +109,7 @@ void FGATCManager::init() {
if (park_index < 0) {
SG_LOG( SG_GENERAL, SG_ALERT,
"Failed to find parking position " << parking <<
" at airport " << airport );
" at airport " << airport << " at " << SG_ORIGIN);
}
if (parking.empty() || (park_index < 0)) {
controller = apt->getDynamics()->getTowerController();
@ -136,7 +135,7 @@ void FGATCManager::init() {
string aircraftType; // Unused.
string airline; // Currently used for gate selection, but a fallback mechanism will apply when not specified.
fp->setGate(park_index);
fp->createPushBack(&ai_ac,
if (!(fp->createPushBack(&ai_ac,
false,
apt,
latitude,
@ -144,7 +143,10 @@ void FGATCManager::init() {
aircraftRadius,
fltType,
aircraftType,
airline);
airline))) {
controller = 0;
return;
}
}
fp->getLastWaypoint()->setName( fp->getLastWaypoint()->getName() + string("legend"));
@ -170,6 +172,7 @@ void FGATCManager::init() {
//cerr << "Adding groundnetWork to the scenegraph::init" << endl;
//globals->get_scenery()->get_scene_graph()->addChild(node);
}
initSucceeded = true;
}
void FGATCManager::addController(FGATCController *controller) {
@ -214,7 +217,7 @@ void FGATCManager::update ( double time ) {
ai_ac.setSpeed(speed);
ai_ac.update(time);
controller = ai_ac.getATCController();
currentATCDialog->update(time);
FGATCDialogNew::instance()->update(time);
if (controller) {
//cerr << "name of previous waypoint : " << fp->getPreviousWaypoint()->getName() << endl;
@ -244,5 +247,7 @@ void FGATCManager::update ( double time ) {
//cerr << "Adding groundnetWork to the scenegraph::update" << endl;
prevController = controller;
}
//globals->get_scenery()->get_scene_graph()->addChild(node);
for (AtcVecIterator atc = activeStations.begin(); atc != activeStations.end(); atc++) {
(*atc)->update(time);
}
}

View file

@ -50,8 +50,8 @@ private:
AtcVec activeStations;
FGAIAircraft ai_ac;
FGATCController *controller, *prevController; // The ATC controller that is responsible for the user's aircraft.
//FGATCDialogNew dialog; // note that this variable should really replace the ugly global "currentATCDialog();
bool networkVisible;
bool initSucceeded;
public:
FGATCManager();
@ -59,7 +59,6 @@ public:
void init();
void addController(FGATCController *controller);
void update(double time);
FGATCDialogNew * getATCDialog() { return currentATCDialog; };
};
#endif // _ATC_MRG_HXX_

View file

@ -35,11 +35,12 @@
FGATCDialogNew *currentATCDialog;
static bool doATCDialog(const SGPropertyNode* arg) {
/*static bool doATCDialog(const SGPropertyNode* arg) {
//cerr << "Running doATCDialog" << endl;
currentATCDialog->PopupDialog();
return(true);
}
}*/
FGATCDialogNew * FGATCDialogNew::_instance = NULL;
FGATCDialogNew::FGATCDialogNew()
{
@ -54,7 +55,7 @@ FGATCDialogNew::~FGATCDialogNew()
void FGATCDialogNew::init() {
// Add ATC-dialog to the command list
globals->get_commands()->addCommand("ATC-dialog", doATCDialog);
globals->get_commands()->addCommand("ATC-dialog", FGATCDialogNew::popup );
// Add ATC-freq-search to the command list
//globals->get_commands()->addCommand("ATC-freq-search", do_ATC_freq_search);

View file

@ -43,13 +43,14 @@
typedef vector<string> StringVec;
typedef vector<string>:: iterator StringVecIterator;
static bool doATCDialog(const SGPropertyNode* arg);
class FGATCDialogNew {
private:
NewGUI *_gui;
bool dialogVisible;
StringVec commands;
static FGATCDialogNew *_instance;
public:
FGATCDialogNew();
@ -61,8 +62,19 @@ public:
void PopupDialog();
void addEntry(int, string);
void removeEntry(int);
static bool popup( const SGPropertyNode * ) {
instance()->PopupDialog();
return true;
}
inline static FGATCDialogNew * instance() {
if( _instance != NULL ) return _instance;
_instance = new FGATCDialogNew();
_instance->init();
return _instance;
}
};
extern FGATCDialogNew *currentATCDialog;
#endif // _ATC_DIALOG_HXX_

View file

@ -65,7 +65,7 @@ time_t ActiveRunway::requestTimeSlot(time_t eta)
TimeVectorIterator i = estimatedArrivalTimes.begin();
//cerr << "Checking eta slots " << eta << ": " << endl;
for (i = estimatedArrivalTimes.begin();
i != estimatedArrivalTimes.end(); i++) {
i != estimatedArrivalTimes.end(); i++) {
//cerr << "Stored time : " << (*i) << endl;
}
i = estimatedArrivalTimes.begin();
@ -144,18 +144,20 @@ time_t ActiveRunway::requestTimeSlot(time_t eta)
* FGTrafficRecord
**************************************************************************/
FGTrafficRecord::FGTrafficRecord():
id(0), waitsForId(0),
currentPos(0),
leg(0),
frequencyId(0),
state(0),
allowTransmission(true),
latitude(0), longitude(0), heading(0), speed(0), altitude(0), radius(0)
id(0), waitsForId(0),
currentPos(0),
leg(0),
frequencyId(0),
state(0),
allowTransmission(true),
allowPushback(true),
priority(0),
latitude(0), longitude(0), heading(0), speed(0), altitude(0), radius(0)
{
}
void FGTrafficRecord::setPositionAndIntentions(int pos,
FGAIFlightPlan * route)
FGAIFlightPlan * route)
{
currentPos = pos;
@ -166,7 +168,7 @@ void FGTrafficRecord::setPositionAndIntentions(int pos,
"Error in FGTrafficRecord::setPositionAndIntentions");
//cerr << "Pos : " << pos << " Curr " << *(intentions.begin()) << endl;
for (intVecIterator i = intentions.begin();
i != intentions.end(); i++) {
i != intentions.end(); i++) {
//cerr << (*i) << " ";
}
//cerr << endl;
@ -194,7 +196,7 @@ void FGTrafficRecord::setPositionAndIntentions(int pos,
//exit(1);
}
/**
* Check if another aircraft is ahead of the current one, and on the same
* Check if another aircraft is ahead of the current one, and on the same
* return true / false is the is/isn't the case.
*
****************************************************************************/
@ -207,10 +209,10 @@ bool FGTrafficRecord::checkPositionAndIntentions(FGTrafficRecord & other)
//cerr << callsign << ": Check Position and intentions: we are on the same taxiway" << other.callsign << "Index = " << currentPos << endl;
result = true;
}
// else if (other.intentions.size())
// else if (other.intentions.size())
// {
// cerr << "Start check 2" << endl;
// intVecIterator i = other.intentions.begin();
// intVecIterator i = other.intentions.begin();
// while (!((i == other.intentions.end()) || ((*i) == currentPos)))
// i++;
// if (i != other.intentions.end()) {
@ -237,8 +239,8 @@ bool FGTrafficRecord::checkPositionAndIntentions(FGTrafficRecord & other)
}
void FGTrafficRecord::setPositionAndHeading(double lat, double lon,
double hdg, double spd,
double alt)
double hdg, double spd,
double alt)
{
latitude = lat;
longitude = lon;
@ -251,12 +253,12 @@ int FGTrafficRecord::crosses(FGGroundNetwork * net,
FGTrafficRecord & other)
{
if (checkPositionAndIntentions(other)
|| (other.checkPositionAndIntentions(*this)))
|| (other.checkPositionAndIntentions(*this)))
return -1;
intVecIterator i, j;
int currentTargetNode = 0, otherTargetNode = 0;
if (currentPos > 0)
currentTargetNode = net->findSegment(currentPos)->getEnd()->getIndex(); // OKAY,...
currentTargetNode = net->findSegment(currentPos)->getEnd()->getIndex(); // OKAY,...
if (other.currentPos > 0)
otherTargetNode = net->findSegment(other.currentPos)->getEnd()->getIndex(); // OKAY,...
if ((currentTargetNode == otherTargetNode) && currentTargetNode > 0)
@ -265,7 +267,7 @@ int FGTrafficRecord::crosses(FGGroundNetwork * net,
for (i = intentions.begin(); i != intentions.end(); i++) {
if ((*i) > 0) {
if ((currentTargetNode ==
net->findSegment(*i)->getEnd()->getIndex())) {
net->findSegment(*i)->getEnd()->getIndex())) {
//cerr << "Current crosses at " << currentTargetNode <<endl;
return currentTargetNode;
}
@ -274,10 +276,10 @@ int FGTrafficRecord::crosses(FGGroundNetwork * net,
}
if (other.intentions.size()) {
for (i = other.intentions.begin(); i != other.intentions.end();
i++) {
i++) {
if ((*i) > 0) {
if (otherTargetNode ==
net->findSegment(*i)->getEnd()->getIndex()) {
net->findSegment(*i)->getEnd()->getIndex()) {
//cerr << "Other crosses at " << currentTargetNode <<endl;
return otherTargetNode;
}
@ -287,7 +289,7 @@ int FGTrafficRecord::crosses(FGGroundNetwork * net,
if (intentions.size() && other.intentions.size()) {
for (i = intentions.begin(); i != intentions.end(); i++) {
for (j = other.intentions.begin(); j != other.intentions.end();
j++) {
j++) {
//cerr << "finding segment " << *i << " and " << *j << endl;
if (((*i) > 0) && ((*j) > 0)) {
currentTargetNode =
@ -318,7 +320,7 @@ bool FGTrafficRecord::onRoute(FGGroundNetwork * net,
return true;
if (other.intentions.size()) {
for (intVecIterator i = other.intentions.begin();
i != other.intentions.end(); i++) {
i != other.intentions.end(); i++) {
if (*i > 0) {
othernode = net->findSegment(*i)->getEnd()->getIndex();
if ((node == othernode) && (node > -1))
@ -332,7 +334,7 @@ bool FGTrafficRecord::onRoute(FGGroundNetwork * net,
// {
// for (intVecIterator i = intentions.begin(); i != intentions.end(); i++)
// {
// if (*i > 0)
// if (*i > 0)
// {
// node = net->findSegment(*i)->getEnd()->getIndex();
// if ((node == othernode) && (node > -1))
@ -358,13 +360,13 @@ bool FGTrafficRecord::isOpposing(FGGroundNetwork * net,
}
for (intVecIterator i = intentions.begin(); i != intentions.end();
i++) {
i++) {
if ((opp = net->findSegment(other.currentPos)->opposite())) {
if ((*i) > 0)
if (opp->getIndex() ==
net->findSegment(*i)->getIndex()) {
net->findSegment(*i)->getIndex()) {
if (net->findSegment(*i)->getStart()->getIndex() ==
node) {
node) {
{
//cerr << "Found the node " << node << endl;
return true;
@ -374,17 +376,17 @@ bool FGTrafficRecord::isOpposing(FGGroundNetwork * net,
}
if (other.intentions.size()) {
for (intVecIterator j = other.intentions.begin();
j != other.intentions.end(); j++) {
j != other.intentions.end(); j++) {
// cerr << "Current segment 1 " << (*i) << endl;
if ((*i) > 0) {
if ((opp = net->findSegment(*i)->opposite())) {
if (opp->getIndex() ==
net->findSegment(*j)->getIndex()) {
net->findSegment(*j)->getIndex()) {
//cerr << "Nodes " << net->findSegment(*i)->getIndex()
// << " and " << net->findSegment(*j)->getIndex()
// << " are opposites " << endl;
if (net->findSegment(*i)->getStart()->
getIndex() == node) {
getIndex() == node) {
{
//cerr << "Found the node " << node << endl;
return true;
@ -400,6 +402,14 @@ bool FGTrafficRecord::isOpposing(FGGroundNetwork * net,
return false;
}
bool FGTrafficRecord::isActive(int margin)
{
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
time_t deptime = aircraft->getTrafficRef()->getDepartureTime();
return ((now + margin) > deptime);
}
void FGTrafficRecord::setSpeedAdjustment(double spd)
{
instruction.setChangeSpeed(true);
@ -414,31 +424,12 @@ void FGTrafficRecord::setHeadingAdjustment(double heading)
bool FGTrafficRecord::pushBackAllowed()
{
// With the user ATC / AI integration, checking whether the user's aircraft is near no longer works, because
// this will effectively block the user's aircraft itself from receiving pushback clearance.
// So, what can we do?
/*
double course, az2, dist;
SGGeod curr(SGGeod::fromDegM(getLongitude(),
getLatitude(), getAltitude()));
double userLatitude = fgGetDouble("/position/latitude-deg");
double userLongitude = fgGetDouble("/position/longitude-deg");
SGGeod user(SGGeod::fromDeg(userLongitude, userLatitude));
SGGeodesy::inverse(curr, user, course, az2, dist);
//cerr << "Distance to user : " << dist << endl;
return (dist > 250);
*/
// In essence, we should check whether the pusbback route itself, as well as the associcated
// taxiways near the pushback point are free of traffic.
// To do so, we need to
return true;
return allowPushback;
}
/***************************************************************************
* FGATCInstruction
*
@ -483,7 +474,7 @@ FGATCController::FGATCController()
FGATCController::~FGATCController()
{
//cerr << "running FGATController destructor" << endl;
//cerr << "running FGATController destructor" << endl;
}
string FGATCController::getGateName(FGAIAircraft * ref)
@ -491,9 +482,9 @@ string FGATCController::getGateName(FGAIAircraft * ref)
return ref->atGate();
}
bool FGATCController::isUserAircraft(FGAIAircraft* ac)
{
return (ac->getCallSign() == fgGetString("/sim/multiplay/callsign")) ? true : false;
bool FGATCController::isUserAircraft(FGAIAircraft* ac)
{
return (ac->getCallSign() == fgGetString("/sim/multiplay/callsign")) ? true : false;
};
void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent, AtcMsgId msgId,
@ -537,7 +528,7 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
taxiFreq =
rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
getDynamics()->getGroundFrequency(2);
towerFreq =
towerFreq =
rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
getDynamics()->getTowerFrequency(2);
receiver =
@ -587,11 +578,11 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
getRunwayClassFromTrafficType(fltType);
rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
heading);
getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
heading);
rec->getAircraft()->GetFlightPlan()->setRunway(activeRunway);
fp = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
getDynamics()->getSID(activeRunway, heading);
getDynamics()->getSID(activeRunway, heading);
rec->getAircraft()->GetFlightPlan()->setSID(fp);
if (fp) {
SID = fp->getName() + " departure";
@ -683,17 +674,17 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
case MSG_REPORT_RUNWAY_HOLD_SHORT:
activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
//activeRunway = "test";
text = receiver + ". Holding short runway "
+ activeRunway
+ ". " + sender;
text = receiver + ". Holding short runway "
+ activeRunway
+ ". " + sender;
//text = "test1";
//cerr << "1 Currently at leg " << rec->getLeg() << endl;
break;
case MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT:
activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
text = receiver + "Roger. Holding short runway "
// + activeRunway
+ ". " + sender;
text = receiver + "Roger. Holding short runway "
// + activeRunway
+ ". " + sender;
//text = "test2";
//cerr << "2 Currently at leg " << rec->getLeg() << endl;
break;
@ -728,17 +719,14 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
// Note that distance attenuation is currently not yet implemented
if ((onBoardRadioFreqI0 == stationFreq)
|| (onBoardRadioFreqI1 == stationFreq)) {
|| (onBoardRadioFreqI1 == stationFreq)) {
if (rec->allowTransmissions()) {
fgSetString("/sim/messages/atc", text.c_str());
}
}
} else {
FGATCManager *atc = (FGATCManager*) globals->get_subsystem("atc");
atc->getATCDialog()->addEntry(1, text);
FGATCDialogNew::instance()->addEntry(1, text);
}
}
@ -751,7 +739,7 @@ string FGATCController::formatATCFrequency3_2(int freq)
}
// TODO: Set transponder codes according to real-world routes.
// The current version just returns a random string of four octal numbers.
// The current version just returns a random string of four octal numbers.
string FGATCController::genTransponderCode(string fltRules)
{
if (fltRules == "VFR") {
@ -764,12 +752,12 @@ string FGATCController::genTransponderCode(string fltRules)
}
}
void FGATCController::init()
void FGATCController::init()
{
if (!initialized) {
FGATCManager *mgr = (FGATCManager*) globals->get_subsystem("ATC");
mgr->addController(this);
initialized = true;
if (!initialized) {
FGATCManager *mgr = (FGATCManager*) globals->get_subsystem("ATC");
mgr->addController(this);
initialized = true;
}
}
@ -778,19 +766,19 @@ void FGATCController::init()
*
**************************************************************************/
FGTowerController::FGTowerController(FGAirportDynamics *par) :
FGATCController()
FGATCController()
{
parent = par;
}
//
//
void FGTowerController::announcePosition(int id,
FGAIFlightPlan * intendedRoute,
int currentPosition, double lat,
double lon, double heading,
double speed, double alt,
double radius, int leg,
FGAIAircraft * ref)
FGAIFlightPlan * intendedRoute,
int currentPosition, double lat,
double lon, double heading,
double speed, double alt,
double radius, int leg,
FGAIAircraft * ref)
{
init();
TrafficVectorIterator i = activeTraffic.begin();
@ -817,7 +805,7 @@ void FGTowerController::announcePosition(int id,
rec.setRadius(radius);
rec.setAircraft(ref);
activeTraffic.push_back(rec);
// Don't just schedule the aircraft for the tower controller, also assign if to the correct active runway.
// Don't just schedule the aircraft for the tower controller, also assign if to the correct active runway.
ActiveRunwayVecIterator rwy = activeRunways.begin();
if (activeRunways.size()) {
while (rwy != activeRunways.end()) {
@ -843,8 +831,8 @@ void FGTowerController::announcePosition(int id,
}
void FGTowerController::updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt,
double dt)
double heading, double speed, double alt,
double dt)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search whether the current id has an entry
@ -871,7 +859,7 @@ void FGTowerController::updateAircraftInformation(int id, double lat, double lon
// see if we already have a clearance record for the currently active runway
// NOTE: dd. 2011-08-07: Because the active runway has been constructed in the announcePosition function, we may safely assume that is
// already exists here. So, we can simplify the current code.
// already exists here. So, we can simplify the current code.
ActiveRunwayVecIterator rwy = activeRunways.begin();
while (rwy != activeRunways.end()) {
if (rwy->getRunwayName() == current->getRunway()) {
@ -907,6 +895,8 @@ void FGTowerController::updateAircraftInformation(int id, double lat, double lon
rwy->setCleared(id);
}
}
} else {
}
}
@ -955,7 +945,7 @@ void FGTowerController::signOff(int id)
// NOTE:
// IF WE MAKE TRAFFICRECORD A MEMBER OF THE BASE CLASS
// THE FOLLOWING THREE FUNCTIONS: SIGNOFF, HAS INSTRUCTION AND GETINSTRUCTION CAN
// THE FOLLOWING THREE FUNCTIONS: SIGNOFF, HAS INSTRUCTION AND GETINSTRUCTION CAN
// BECOME DEVIRTUALIZED AND BE A MEMBER OF THE BASE ATCCONTROLLER CLASS
// WHICH WOULD SIMPLIFY CODE MAINTENANCE.
// Note that this function is probably obsolete
@ -1014,6 +1004,11 @@ string FGTowerController::getName() {
return string(parent->getId() + "-tower");
}
void FGTowerController::update(double dt)
{
}
/***************************************************************************
@ -1021,18 +1016,18 @@ string FGTowerController::getName() {
*
**************************************************************************/
FGStartupController::FGStartupController(FGAirportDynamics *par):
FGATCController()
FGATCController()
{
parent = par;
}
void FGStartupController::announcePosition(int id,
FGAIFlightPlan * intendedRoute,
int currentPosition, double lat,
double lon, double heading,
double speed, double alt,
double radius, int leg,
FGAIAircraft * ref)
FGAIFlightPlan * intendedRoute,
int currentPosition, double lat,
double lon, double heading,
double speed, double alt,
double radius, int leg,
FGAIAircraft * ref)
{
init();
TrafficVectorIterator i = activeTraffic.begin();
@ -1069,7 +1064,7 @@ void FGStartupController::announcePosition(int id,
// NOTE:
// IF WE MAKE TRAFFICRECORD A MEMBER OF THE BASE CLASS
// THE FOLLOWING THREE FUNCTIONS: SIGNOFF, HAS INSTRUCTION AND GETINSTRUCTION CAN
// THE FOLLOWING THREE FUNCTIONS: SIGNOFF, HAS INSTRUCTION AND GETINSTRUCTION CAN
// BECOME DEVIRTUALIZED AND BE A MEMBER OF THE BASE ATCCONTROLLER CLASS
// WHICH WOULD SIMPLIFY CODE MAINTENANCE.
// Note that this function is probably obsolete
@ -1144,21 +1139,20 @@ void FGStartupController::signOff(int id)
}
bool FGStartupController::checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId,
AtcMsgDir msgDir)
AtcMsgDir msgDir)
{
int state = i->getState();
if ((state == st) && available) {
if ((msgDir == ATC_AIR_TO_GROUND) && isUserAircraft(i->getAircraft())) {
//cerr << "Checking state " << st << " for " << i->getAircraft()->getCallSign() << endl;
static SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true);
int n = trans_num->getIntValue();
if (n == 0) {
trans_num->setIntValue(-1);
// PopupCallback(n);
//cerr << "Selected transmission message " << n << endl;
FGATCManager *atc = (FGATCManager*) globals->get_subsystem("atc");
atc->getATCDialog()->removeEntry(1);
// PopupCallback(n);
//cerr << "Selected transmission message " << n << endl;
FGATCDialogNew::instance()->removeEntry(1);
} else {
//cerr << "creading message for " << i->getAircraft()->getCallSign() << endl;
transmit(&(*i), &(*parent), msgId, msgDir, false);
@ -1178,8 +1172,8 @@ bool FGStartupController::checkTransmissionState(int st, time_t now, time_t star
}
void FGStartupController::updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt,
double dt)
double heading, double speed, double alt,
double dt)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id has an entry
@ -1207,11 +1201,11 @@ void FGStartupController::updateAircraftInformation(int id, double lat, double l
int state = i->getState();
// The user controlled aircraft should have crased here, because it doesn't have a traffic reference.
// The user controlled aircraft should have crased here, because it doesn't have a traffic reference.
// NOTE: if we create a traffic schedule for the user aircraft, we can use this to plan a flight.
time_t startTime = i->getAircraft()->getTrafficRef()->getDepartureTime();
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
//cerr << i->getAircraft()->getTrafficRef()->getCallSign()
//cerr << i->getAircraft()->getTrafficRef()->getCallSign()
// << " is scheduled to depart in " << startTime-now << " seconds. Available = " << available
// << " at parking " << getGateName(i->getAircraft()) << endl;
@ -1231,7 +1225,7 @@ void FGStartupController::updateAircraftInformation(int id, double lat, double l
checkTransmissionState(7, now, (startTime + 180), i, MSG_REQUEST_PUSHBACK_CLEARANCE, ATC_AIR_TO_GROUND);
if ((state == 8) && available) {
if (now > startTime + 200) {
if (i->pushBackAllowed()) {
@ -1278,10 +1272,10 @@ void FGStartupController::render(bool visible)
//while (group->getNumChildren()) {
// cerr << "Number of children: " << group->getNumChildren() << endl;
//simgear::EffectGeode* geode = (simgear::EffectGeode*) group->getChild(0);
//osg::MatrixTransform *obj_trans = (osg::MatrixTransform*) group->getChild(0);
//geode->releaseGLObjects();
//group->removeChild(geode);
//delete geode;
//osg::MatrixTransform *obj_trans = (osg::MatrixTransform*) group->getChild(0);
//geode->releaseGLObjects();
//group->removeChild(geode);
//delete geode;
group = 0;
}
if (visible) {
@ -1294,135 +1288,64 @@ void FGStartupController::render(bool visible)
//for ( FGTaxiSegmentVectorIterator i = segments.begin(); i != segments.end(); i++) {
double dx = 0;
for (TrafficVectorIterator i = activeTraffic.begin(); i != activeTraffic.end(); i++) {
// Handle start point
int pos = i->getCurrentPosition();
//cerr << "rendering for " << i->getAircraft()->getCallSign() << "pos = " << pos << endl;
if (pos > 0) {
FGTaxiSegment *segment = parent->getGroundNetwork()->findSegment(pos);
SGGeod start(SGGeod::fromDeg((i->getLongitude()), (i->getLatitude())));
SGGeod end (SGGeod::fromDeg(segment->getEnd()->getLongitude(), segment->getEnd()->getLatitude()));
if (i->isActive(300)) {
// Handle start point
int pos = i->getCurrentPosition();
//cerr << "rendering for " << i->getAircraft()->getCallSign() << "pos = " << pos << endl;
if (pos > 0) {
FGTaxiSegment *segment = parent->getGroundNetwork()->findSegment(pos);
SGGeod start(SGGeod::fromDeg((i->getLongitude()), (i->getLatitude())));
SGGeod end (SGGeod::fromDeg(segment->getEnd()->getLongitude(), segment->getEnd()->getLatitude()));
double length = SGGeodesy::distanceM(start, end);
//heading = SGGeodesy::headingDeg(start->getGeod(), end->getGeod());
double length = SGGeodesy::distanceM(start, end);
//heading = SGGeodesy::headingDeg(start->getGeod(), end->getGeod());
double az2, heading; //, distanceM;
SGGeodesy::inverse(start, end, heading, az2, length);
double coveredDistance = length * 0.5;
SGGeod center;
SGGeodesy::direct(start, heading, coveredDistance, center, az2);
//cerr << "Active Aircraft : Centerpoint = (" << center.getLatitudeDeg() << ", " << center.getLongitudeDeg() << "). Heading = " << heading << endl;
///////////////////////////////////////////////////////////////////////////////
// Make a helper function out of this
osg::Matrix obj_pos;
osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
obj_trans->setDataVariance(osg::Object::STATIC);
// Experimental: Calculate slope here, based on length, and the individual elevations
double elevationStart;
if (isUserAircraft((i)->getAircraft())) {
elevationStart = fgGetDouble("/position/ground-elev-m");
} else {
elevationStart = ((i)->getAircraft()->_getAltitude());
}
double elevationEnd = segment->getEnd()->getElevation();
if ((elevationEnd == 0) || (elevationEnd == parent->getElevation())) {
SGGeod center2 = end;
center2.setElevationM(SG_MAX_ELEVATION_M);
if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) {
elevation_feet = elevationEnd * SG_METER_TO_FEET + 0.5;
//elevation_meters += 0.5;
}
else {
elevationEnd = parent->getElevation();
}
segment->getEnd()->setElevation(elevationEnd);
}
double elevationMean = (elevationStart + elevationEnd) / 2.0;
double elevDiff = elevationEnd - elevationStart;
double slope = atan2(elevDiff, length) * SGD_RADIANS_TO_DEGREES;
//cerr << "1. Using mean elevation : " << elevationMean << " and " << slope << endl;
WorldCoordinate( obj_pos, center.getLatitudeDeg(), center.getLongitudeDeg(), elevationMean + 0.5, -(heading), slope );
;
obj_trans->setMatrix( obj_pos );
//osg::Vec3 center(0, 0, 0)
float width = length /2.0;
osg::Vec3 corner(-width, 0, 0.25f);
osg::Vec3 widthVec(2*width + 1, 0, 0);
osg::Vec3 heightVec(0, 1, 0);
osg::Geometry* geometry;
geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
simgear::EffectGeode* geode = new simgear::EffectGeode;
geode->setName("test");
geode->addDrawable(geometry);
//osg::Node *custom_obj;
SGMaterial *mat = matlib->find("UnidirectionalTaper");
if (mat)
geode->setEffect(mat->get_effect());
obj_trans->addChild(geode);
// wire as much of the scene graph together as we can
//->addChild( obj_trans );
group->addChild( obj_trans );
/////////////////////////////////////////////////////////////////////
} else {
//cerr << "BIG FAT WARNING: current position is here : " << pos << endl;
}
for(intVecIterator j = (i)->getIntentions().begin(); j != (i)->getIntentions().end(); j++) {
osg::Matrix obj_pos;
int k = (*j);
if (k > 0) {
//cerr << "rendering for " << i->getAircraft()->getCallSign() << "intention = " << k << endl;
double az2, heading; //, distanceM;
SGGeodesy::inverse(start, end, heading, az2, length);
double coveredDistance = length * 0.5;
SGGeod center;
SGGeodesy::direct(start, heading, coveredDistance, center, az2);
//cerr << "Active Aircraft : Centerpoint = (" << center.getLatitudeDeg() << ", " << center.getLongitudeDeg() << "). Heading = " << heading << endl;
///////////////////////////////////////////////////////////////////////////////
// Make a helper function out of this
osg::Matrix obj_pos;
osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
obj_trans->setDataVariance(osg::Object::STATIC);
FGTaxiSegment *segment = parent->getGroundNetwork()->findSegment(k);
double elevationStart = segment->getStart()->getElevation();
double elevationEnd = segment->getEnd ()->getElevation();
if ((elevationStart == 0) || (elevationStart == parent->getElevation())) {
SGGeod center2 = segment->getStart()->getGeod();
center2.setElevationM(SG_MAX_ELEVATION_M);
if (local_scenery->get_elevation_m( center2, elevationStart, NULL )) {
elevation_feet = elevationStart * SG_METER_TO_FEET + 0.5;
//elevation_meters += 0.5;
}
else {
elevationStart = parent->getElevation();
}
segment->getStart()->setElevation(elevationStart);
// Experimental: Calculate slope here, based on length, and the individual elevations
double elevationStart;
if (isUserAircraft((i)->getAircraft())) {
elevationStart = fgGetDouble("/position/ground-elev-m");
} else {
elevationStart = ((i)->getAircraft()->_getAltitude() * SG_FEET_TO_METER);
}
double elevationEnd = segment->getEnd()->getElevation();
if ((elevationEnd == 0) || (elevationEnd == parent->getElevation())) {
SGGeod center2 = segment->getEnd()->getGeod();
SGGeod center2 = end;
center2.setElevationM(SG_MAX_ELEVATION_M);
if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) {
elevation_feet = elevationEnd * SG_METER_TO_FEET + 0.5;
//elevation_meters += 0.5;
}
else {
else {
elevationEnd = parent->getElevation();
}
segment->getEnd()->setElevation(elevationEnd);
}
double elevationMean = (elevationStart + elevationEnd) / 2.0;
double elevDiff = elevationEnd - elevationStart;
double length = segment->getLength();
double slope = atan2(elevDiff, length) * SGD_RADIANS_TO_DEGREES;
//cerr << "2. Using mean elevation : " << elevationMean << " and " << slope << endl;
//cerr << "1. Using mean elevation : " << elevationMean << " and " << slope << endl;
WorldCoordinate( obj_pos, segment->getLatitude(), segment->getLongitude(), elevationMean + 0.5, -(segment->getHeading()), slope );
//WorldCoordinate( obj_pos, segment->getLatitude(), segment->getLongitude(), parent->getElevation()+8+dx, -(segment->getHeading()) );
WorldCoordinate( obj_pos, center.getLatitudeDeg(), center.getLongitudeDeg(), elevationMean + 0.5 + dx, -(heading), slope );
;
obj_trans->setMatrix( obj_pos );
//osg::Vec3 center(0, 0, 0)
float width = segment->getLength() /2.0;
float width = length /2.0;
osg::Vec3 corner(-width, 0, 0.25f);
osg::Vec3 widthVec(2*width + 1, 0, 0);
osg::Vec3 heightVec(0, 1, 0);
@ -1432,18 +1355,101 @@ void FGStartupController::render(bool visible)
geode->setName("test");
geode->addDrawable(geometry);
//osg::Node *custom_obj;
SGMaterial *mat = matlib->find("UnidirectionalTaper");
SGMaterial *mat;
if (segment->hasBlock()) {
mat = matlib->find("UnidirectionalTaperRed");
} else {
mat = matlib->find("UnidirectionalTaperGreen");
}
if (mat)
geode->setEffect(mat->get_effect());
obj_trans->addChild(geode);
// wire as much of the scene graph together as we can
//->addChild( obj_trans );
group->addChild( obj_trans );
/////////////////////////////////////////////////////////////////////
} else {
//cerr << "BIG FAT WARNING: k is here : " << pos << endl;
//cerr << "BIG FAT WARNING: current position is here : " << pos << endl;
}
for (intVecIterator j = (i)->getIntentions().begin(); j != (i)->getIntentions().end(); j++) {
osg::Matrix obj_pos;
int k = (*j);
if (k > 0) {
//cerr << "rendering for " << i->getAircraft()->getCallSign() << "intention = " << k << endl;
osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
obj_trans->setDataVariance(osg::Object::STATIC);
FGTaxiSegment *segment = parent->getGroundNetwork()->findSegment(k);
double elevationStart = segment->getStart()->getElevation();
double elevationEnd = segment->getEnd ()->getElevation();
if ((elevationStart == 0) || (elevationStart == parent->getElevation())) {
SGGeod center2 = segment->getStart()->getGeod();
center2.setElevationM(SG_MAX_ELEVATION_M);
if (local_scenery->get_elevation_m( center2, elevationStart, NULL )) {
elevation_feet = elevationStart * SG_METER_TO_FEET + 0.5;
//elevation_meters += 0.5;
}
else {
elevationStart = parent->getElevation();
}
segment->getStart()->setElevation(elevationStart);
}
if ((elevationEnd == 0) || (elevationEnd == parent->getElevation())) {
SGGeod center2 = segment->getEnd()->getGeod();
center2.setElevationM(SG_MAX_ELEVATION_M);
if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) {
elevation_feet = elevationEnd * SG_METER_TO_FEET + 0.5;
//elevation_meters += 0.5;
}
else {
elevationEnd = parent->getElevation();
}
segment->getEnd()->setElevation(elevationEnd);
}
double elevationMean = (elevationStart + elevationEnd) / 2.0;
double elevDiff = elevationEnd - elevationStart;
double length = segment->getLength();
double slope = atan2(elevDiff, length) * SGD_RADIANS_TO_DEGREES;
//cerr << "2. Using mean elevation : " << elevationMean << " and " << slope << endl;
WorldCoordinate( obj_pos, segment->getLatitude(), segment->getLongitude(), elevationMean + 0.5 + dx, -(segment->getHeading()), slope );
//WorldCoordinate( obj_pos, segment->getLatitude(), segment->getLongitude(), parent->getElevation()+8+dx, -(segment->getHeading()) );
obj_trans->setMatrix( obj_pos );
//osg::Vec3 center(0, 0, 0)
float width = segment->getLength() /2.0;
osg::Vec3 corner(-width, 0, 0.25f);
osg::Vec3 widthVec(2*width + 1, 0, 0);
osg::Vec3 heightVec(0, 1, 0);
osg::Geometry* geometry;
geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
simgear::EffectGeode* geode = new simgear::EffectGeode;
geode->setName("test");
geode->addDrawable(geometry);
//osg::Node *custom_obj;
SGMaterial *mat;
if (segment->hasBlock()) {
mat = matlib->find("UnidirectionalTaperRed");
} else {
mat = matlib->find("UnidirectionalTaperGreen");
}
if (mat)
geode->setEffect(mat->get_effect());
obj_trans->addChild(geode);
// wire as much of the scene graph together as we can
//->addChild( obj_trans );
group->addChild( obj_trans );
} else {
//cerr << "BIG FAT WARNING: k is here : " << pos << endl;
}
}
dx += 0.2;
}
//dx += 0.1;
}
globals->get_scenery()->get_scene_graph()->addChild(group);
}
@ -1453,25 +1459,31 @@ string FGStartupController::getName() {
return string(parent->getId() + "-startup");
}
void FGStartupController::update(double dt)
{
}
/***************************************************************************
* class FGApproachController
*
**************************************************************************/
FGApproachController::FGApproachController(FGAirportDynamics *par):
FGATCController()
FGATCController()
{
parent = par;
}
//
//
void FGApproachController::announcePosition(int id,
FGAIFlightPlan * intendedRoute,
int currentPosition,
double lat, double lon,
double heading, double speed,
double alt, double radius,
int leg, FGAIAircraft * ref)
FGAIFlightPlan * intendedRoute,
int currentPosition,
double lat, double lon,
double heading, double speed,
double alt, double radius,
int leg, FGAIAircraft * ref)
{
init();
TrafficVectorIterator i = activeTraffic.begin();
@ -1503,8 +1515,8 @@ void FGApproachController::announcePosition(int id,
}
void FGApproachController::updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt,
double dt)
double heading, double speed, double alt,
double dt)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id has an entry
@ -1576,6 +1588,10 @@ void FGApproachController::signOff(int id)
}
}
void FGApproachController::update(double dt)
{
}

View file

@ -38,11 +38,14 @@
#include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <string>
#include <vector>
#include <list>
using std::string;
using std::vector;
using std::list;
typedef vector<int> intVec;
@ -62,43 +65,79 @@ class FGAirportDynamics;
class FGATCInstruction
{
private:
bool holdPattern;
bool holdPosition;
bool changeSpeed;
bool changeHeading;
bool changeAltitude;
bool resolveCircularWait;
bool holdPattern;
bool holdPosition;
bool changeSpeed;
bool changeHeading;
bool changeAltitude;
bool resolveCircularWait;
double speed;
double heading;
double alt;
double speed;
double heading;
double alt;
public:
FGATCInstruction();
bool hasInstruction ();
bool getHoldPattern () { return holdPattern; };
bool getHoldPosition () { return holdPosition; };
bool getChangeSpeed () { return changeSpeed; };
bool getChangeHeading () { return changeHeading; };
bool getChangeAltitude() { return changeAltitude; };
FGATCInstruction();
bool hasInstruction ();
bool getHoldPattern () {
return holdPattern;
};
bool getHoldPosition () {
return holdPosition;
};
bool getChangeSpeed () {
return changeSpeed;
};
bool getChangeHeading () {
return changeHeading;
};
bool getChangeAltitude() {
return changeAltitude;
};
double getSpeed () { return speed; };
double getHeading () { return heading; };
double getAlt () { return alt; };
double getSpeed () {
return speed;
};
double getHeading () {
return heading;
};
double getAlt () {
return alt;
};
bool getCheckForCircularWait() { return resolveCircularWait; };
bool getCheckForCircularWait() {
return resolveCircularWait;
};
void setHoldPattern (bool val) { holdPattern = val; };
void setHoldPosition (bool val) { holdPosition = val; };
void setChangeSpeed (bool val) { changeSpeed = val; };
void setChangeHeading (bool val) { changeHeading = val; };
void setChangeAltitude(bool val) { changeAltitude = val; };
void setHoldPattern (bool val) {
holdPattern = val;
};
void setHoldPosition (bool val) {
holdPosition = val;
};
void setChangeSpeed (bool val) {
changeSpeed = val;
};
void setChangeHeading (bool val) {
changeHeading = val;
};
void setChangeAltitude(bool val) {
changeAltitude = val;
};
void setResolveCircularWait (bool val) { resolveCircularWait = val; };
void setResolveCircularWait (bool val) {
resolveCircularWait = val;
};
void setSpeed (double val) { speed = val; };
void setHeading (double val) { heading = val; };
void setAlt (double val) { alt = val; };
void setSpeed (double val) {
speed = val;
};
void setHeading (double val) {
heading = val;
};
void setAlt (double val) {
alt = val;
};
};
@ -111,88 +150,175 @@ public:
class FGTrafficRecord
{
private:
int id, waitsForId;
int currentPos;
int leg;
int frequencyId;
int state;
bool allowTransmission;
time_t timer;
intVec intentions;
FGATCInstruction instruction;
double latitude, longitude, heading, speed, altitude, radius;
string runway;
//FGAISchedule *trafficRef;
FGAIAircraft *aircraft;
int id, waitsForId;
int currentPos;
int leg;
int frequencyId;
int state;
bool allowTransmission;
bool allowPushback;
int priority;
time_t timer;
intVec intentions;
FGATCInstruction instruction;
double latitude, longitude, heading, speed, altitude, radius;
string runway;
//FGAISchedule *trafficRef;
FGAIAircraft *aircraft;
public:
FGTrafficRecord();
void setId(int val) { id = val; };
void setRadius(double rad) { radius = rad;};
void setPositionAndIntentions(int pos, FGAIFlightPlan *route);
void setRunway(string rwy) { runway = rwy;};
void setLeg(int lg) { leg = lg;};
int getId() { return id;};
int getState() { return state;};
void setState(int s) { state = s;}
FGATCInstruction getInstruction() { return instruction;};
bool hasInstruction() { return instruction.hasInstruction(); };
void setPositionAndHeading(double lat, double lon, double hdg, double spd, double alt);
bool checkPositionAndIntentions(FGTrafficRecord &other);
int crosses (FGGroundNetwork *, FGTrafficRecord &other);
bool isOpposing (FGGroundNetwork *, FGTrafficRecord &other, int node);
FGTrafficRecord();
bool onRoute(FGGroundNetwork *, FGTrafficRecord &other);
void setId(int val) {
id = val;
};
void setRadius(double rad) {
radius = rad;
};
void setPositionAndIntentions(int pos, FGAIFlightPlan *route);
void setRunway(string rwy) {
runway = rwy;
};
void setLeg(int lg) {
leg = lg;
};
int getId() {
return id;
};
int getState() {
return state;
};
void setState(int s) {
state = s;
}
FGATCInstruction getInstruction() {
return instruction;
};
bool hasInstruction() {
return instruction.hasInstruction();
};
void setPositionAndHeading(double lat, double lon, double hdg, double spd, double alt);
bool checkPositionAndIntentions(FGTrafficRecord &other);
int crosses (FGGroundNetwork *, FGTrafficRecord &other);
bool isOpposing (FGGroundNetwork *, FGTrafficRecord &other, int node);
bool isActive(int margin);
bool getSpeedAdjustment() { return instruction.getChangeSpeed(); };
double getLatitude () { return latitude ; };
double getLongitude() { return longitude; };
double getHeading () { return heading ; };
double getSpeed () { return speed ; };
double getAltitude () { return altitude ; };
double getRadius () { return radius ; };
bool onRoute(FGGroundNetwork *, FGTrafficRecord &other);
int getWaitsForId () { return waitsForId; };
bool getSpeedAdjustment() {
return instruction.getChangeSpeed();
};
void setSpeedAdjustment(double spd);
void setHeadingAdjustment(double heading);
void clearSpeedAdjustment () { instruction.setChangeSpeed (false); };
void clearHeadingAdjustment() { instruction.setChangeHeading(false); };
double getLatitude () {
return latitude ;
};
double getLongitude() {
return longitude;
};
double getHeading () {
return heading ;
};
double getSpeed () {
return speed ;
};
double getAltitude () {
return altitude ;
};
double getRadius () {
return radius ;
};
bool hasHeadingAdjustment() { return instruction.getChangeHeading(); };
bool hasHoldPosition() { return instruction.getHoldPosition(); };
void setHoldPosition (bool inst) { instruction.setHoldPosition(inst); };
int getWaitsForId () {
return waitsForId;
};
void setWaitsForId(int id) { waitsForId = id; };
void setSpeedAdjustment(double spd);
void setHeadingAdjustment(double heading);
void clearSpeedAdjustment () {
instruction.setChangeSpeed (false);
};
void clearHeadingAdjustment() {
instruction.setChangeHeading(false);
};
void setResolveCircularWait() { instruction.setResolveCircularWait(true); };
void clearResolveCircularWait() { instruction.setResolveCircularWait(false); };
bool hasHeadingAdjustment() {
return instruction.getChangeHeading();
};
bool hasHoldPosition() {
return instruction.getHoldPosition();
};
void setHoldPosition (bool inst) {
instruction.setHoldPosition(inst);
};
string getRunway() { return runway; };
//void setCallSign(string clsgn) { callsign = clsgn; };
void setAircraft(FGAIAircraft *ref) { aircraft = ref;};
void updateState() { state++; allowTransmission=true; };
//string getCallSign() { return callsign; };
FGAIAircraft *getAircraft() { return aircraft;};
int getTime() { return timer; };
int getLeg() { return leg; };
void setTime(time_t time) { timer = time; };
void setWaitsForId(int id) {
waitsForId = id;
};
bool pushBackAllowed();
bool allowTransmissions() { return allowTransmission; };
void suppressRepeatedTransmissions () { allowTransmission=false; };
void allowRepeatedTransmissions () { allowTransmission=true; };
void nextFrequency() { frequencyId++; };
int getNextFrequency() { return frequencyId; };
intVec& getIntentions() { return intentions; };
int getCurrentPosition() { return currentPos; };
void setResolveCircularWait() {
instruction.setResolveCircularWait(true);
};
void clearResolveCircularWait() {
instruction.setResolveCircularWait(false);
};
string getRunway() {
return runway;
};
//void setCallSign(string clsgn) { callsign = clsgn; };
void setAircraft(FGAIAircraft *ref) {
aircraft = ref;
};
void updateState() {
state++;
allowTransmission=true;
};
//string getCallSign() { return callsign; };
FGAIAircraft *getAircraft() {
return aircraft;
};
int getTime() {
return timer;
};
int getLeg() {
return leg;
};
void setTime(time_t time) {
timer = time;
};
bool pushBackAllowed();
bool allowTransmissions() {
return allowTransmission;
};
void allowPushBack() { allowPushback =true;};
void denyPushBack () { allowPushback = false;};
void suppressRepeatedTransmissions () {
allowTransmission=false;
};
void allowRepeatedTransmissions () {
allowTransmission=true;
};
void nextFrequency() {
frequencyId++;
};
int getNextFrequency() {
return frequencyId;
};
intVec& getIntentions() {
return intentions;
};
int getCurrentPosition() {
return currentPos;
};
void setPriority(int p) { priority = p; };
int getPriority() { return priority; };
};
typedef vector<FGTrafficRecord> TrafficVector;
typedef vector<FGTrafficRecord>::iterator TrafficVectorIterator;
typedef list<FGTrafficRecord> TrafficVector;
typedef list<FGTrafficRecord>::iterator TrafficVectorIterator;
typedef vector<time_t> TimeVector;
typedef vector<time_t>::iterator TimeVectorIterator;
@ -207,28 +333,48 @@ typedef vector<FGAIAircraft*>::iterator AircraftVecIterator;
class ActiveRunway
{
private:
string rwy;
int currentlyCleared;
double distanceToFinal;
TimeVector estimatedArrivalTimes;
AircraftVec departureCue;
string rwy;
int currentlyCleared;
double distanceToFinal;
TimeVector estimatedArrivalTimes;
AircraftVec departureCue;
public:
ActiveRunway(string r, int cc) { rwy = r; currentlyCleared = cc; distanceToFinal = 6.0 * SG_NM_TO_METER; };
string getRunwayName() { return rwy; };
int getCleared () { return currentlyCleared; };
double getApproachDistance() { return distanceToFinal; };
//time_t getEstApproachTime() { return estimatedArrival; };
ActiveRunway(string r, int cc) {
rwy = r;
currentlyCleared = cc;
distanceToFinal = 6.0 * SG_NM_TO_METER;
};
//void setEstApproachTime(time_t time) { estimatedArrival = time; };
void addToDepartureCue(FGAIAircraft *ac) { departureCue.push_back(ac); };
void setCleared(int number) { currentlyCleared = number; };
time_t requestTimeSlot(time_t eta);
string getRunwayName() {
return rwy;
};
int getCleared () {
return currentlyCleared;
};
double getApproachDistance() {
return distanceToFinal;
};
//time_t getEstApproachTime() { return estimatedArrival; };
int getDepartureCueSize() { return departureCue.size(); };
FGAIAircraft* getFirstAircraftInDepartureCue() { return departureCue.size() ? *(departureCue.begin()) : NULL; };
void updateDepartureCue() { departureCue.erase(departureCue.begin()); }
//void setEstApproachTime(time_t time) { estimatedArrival = time; };
void addToDepartureCue(FGAIAircraft *ac) {
departureCue.push_back(ac);
};
void setCleared(int number) {
currentlyCleared = number;
};
time_t requestTimeSlot(time_t eta);
int getDepartureCueSize() {
return departureCue.size();
};
FGAIAircraft* getFirstAircraftInDepartureCue() {
return departureCue.size() ? *(departureCue.begin()) : NULL;
};
void updateDepartureCue() {
departureCue.erase(departureCue.begin());
}
};
typedef vector<ActiveRunway> ActiveRunwayVec;
@ -236,78 +382,86 @@ typedef vector<ActiveRunway>::iterator ActiveRunwayVecIterator;
/**
* class FGATCController
* NOTE: this class serves as an abstraction layer for all sorts of ATC controllers.
* NOTE: this class serves as an abstraction layer for all sorts of ATC controllers.
*************************************************************************************/
class FGATCController
{
private:
protected:
bool initialized;
bool available;
time_t lastTransmission;
bool initialized;
bool available;
time_t lastTransmission;
double dt_count;
osg::Group* group;
double dt_count;
osg::Group* group;
string formatATCFrequency3_2(int );
string genTransponderCode(string fltRules);
bool isUserAircraft(FGAIAircraft*);
string formatATCFrequency3_2(int );
string genTransponderCode(string fltRules);
bool isUserAircraft(FGAIAircraft*);
public:
typedef enum {
MSG_ANNOUNCE_ENGINE_START,
MSG_REQUEST_ENGINE_START,
MSG_PERMIT_ENGINE_START,
MSG_DENY_ENGINE_START,
MSG_ACKNOWLEDGE_ENGINE_START,
MSG_REQUEST_PUSHBACK_CLEARANCE,
MSG_PERMIT_PUSHBACK_CLEARANCE,
MSG_HOLD_PUSHBACK_CLEARANCE,
MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY,
MSG_INITIATE_CONTACT,
MSG_ACKNOWLEDGE_INITIATE_CONTACT,
MSG_REQUEST_TAXI_CLEARANCE,
MSG_ISSUE_TAXI_CLEARANCE,
MSG_ACKNOWLEDGE_TAXI_CLEARANCE,
MSG_HOLD_POSITION,
MSG_ACKNOWLEDGE_HOLD_POSITION,
MSG_RESUME_TAXI,
MSG_ACKNOWLEDGE_RESUME_TAXI,
MSG_REPORT_RUNWAY_HOLD_SHORT,
MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT,
MSG_SWITCH_TOWER_FREQUENCY,
MSG_ACKNOWLEDGE_SWITCH_TOWER_FREQUENCY
} AtcMsgId;
typedef enum {
MSG_ANNOUNCE_ENGINE_START,
MSG_REQUEST_ENGINE_START,
MSG_PERMIT_ENGINE_START,
MSG_DENY_ENGINE_START,
MSG_ACKNOWLEDGE_ENGINE_START,
MSG_REQUEST_PUSHBACK_CLEARANCE,
MSG_PERMIT_PUSHBACK_CLEARANCE,
MSG_HOLD_PUSHBACK_CLEARANCE,
MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY,
MSG_INITIATE_CONTACT,
MSG_ACKNOWLEDGE_INITIATE_CONTACT,
MSG_REQUEST_TAXI_CLEARANCE,
MSG_ISSUE_TAXI_CLEARANCE,
MSG_ACKNOWLEDGE_TAXI_CLEARANCE,
MSG_HOLD_POSITION,
MSG_ACKNOWLEDGE_HOLD_POSITION,
MSG_RESUME_TAXI,
MSG_ACKNOWLEDGE_RESUME_TAXI,
MSG_REPORT_RUNWAY_HOLD_SHORT,
MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT,
MSG_SWITCH_TOWER_FREQUENCY,
MSG_ACKNOWLEDGE_SWITCH_TOWER_FREQUENCY
} AtcMsgId;
typedef enum {
ATC_AIR_TO_GROUND,
ATC_GROUND_TO_AIR } AtcMsgDir;
FGATCController();
virtual ~FGATCController();
void init();
typedef enum {
ATC_AIR_TO_GROUND,
ATC_GROUND_TO_AIR
} AtcMsgDir;
FGATCController();
virtual ~FGATCController();
void init();
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon,
double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft) = 0;
virtual void signOff(int id) = 0;
virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt) = 0;
virtual bool hasInstruction(int id) = 0;
virtual FGATCInstruction getInstruction(int id) = 0;
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon,
double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft) = 0;
virtual void signOff(int id) = 0;
virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt) = 0;
virtual bool hasInstruction(int id) = 0;
virtual FGATCInstruction getInstruction(int id) = 0;
double getDt() {
return dt_count;
};
void setDt(double dt) {
dt_count = dt;
};
void transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir msgDir, bool audible);
string getGateName(FGAIAircraft *aircraft);
virtual void render(bool) = 0;
virtual string getName() = 0;
virtual void update(double) = 0;
double getDt() { return dt_count; };
void setDt(double dt) { dt_count = dt;};
void transmit(FGTrafficRecord *rec, FGAirportDynamics *parent, AtcMsgId msgId, AtcMsgDir msgDir, bool audible);
string getGateName(FGAIAircraft *aircraft);
virtual void render(bool) = 0;
virtual string getName() = 0;
private:
AtcMsgDir lastTransmissionDirection;
AtcMsgDir lastTransmissionDirection;
};
/******************************************************************************
@ -316,65 +470,75 @@ private:
class FGTowerController : public FGATCController
{
private:
TrafficVector activeTraffic;
ActiveRunwayVec activeRunways;
FGAirportDynamics *parent;
public:
FGTowerController(FGAirportDynamics *parent);
virtual ~FGTowerController() {};
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon,
double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft);
virtual void signOff(int id);
virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
TrafficVector activeTraffic;
ActiveRunwayVec activeRunways;
FGAirportDynamics *parent;
virtual void render(bool);
virtual string getName();
bool hasActiveTraffic() { return activeTraffic.size() != 0; };
TrafficVector &getActiveTraffic() { return activeTraffic; };
public:
FGTowerController(FGAirportDynamics *parent);
virtual ~FGTowerController() {};
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon,
double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft);
virtual void signOff(int id);
virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
virtual void render(bool);
virtual string getName();
virtual void update(double dt);
bool hasActiveTraffic() {
return activeTraffic.size() != 0;
};
TrafficVector &getActiveTraffic() {
return activeTraffic;
};
};
/******************************************************************************
* class FGStartupController
* handle
* handle
*****************************************************************************/
class FGStartupController : public FGATCController
{
private:
TrafficVector activeTraffic;
//ActiveRunwayVec activeRunways;
FGAirportDynamics *parent;
TrafficVector activeTraffic;
//ActiveRunwayVec activeRunways;
FGAirportDynamics *parent;
public:
FGStartupController(FGAirportDynamics *parent);
virtual ~FGStartupController() {};
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon,
double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft);
virtual void signOff(int id);
virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
FGStartupController(FGAirportDynamics *parent);
virtual ~FGStartupController() {};
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon,
double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft);
virtual void signOff(int id);
virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
virtual void render(bool);
virtual string getName();
virtual void render(bool);
virtual string getName();
virtual void update(double dt);
bool hasActiveTraffic() { return activeTraffic.size() != 0; };
TrafficVector &getActiveTraffic() { return activeTraffic; };
bool hasActiveTraffic() {
return activeTraffic.size() != 0;
};
TrafficVector &getActiveTraffic() {
return activeTraffic;
};
// Hpoefully, we can move this function to the base class, but I need to verify what is needed for the other controllers before doing so.
bool checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId,
AtcMsgDir msgDir);
// Hpoefully, we can move this function to the base class, but I need to verify what is needed for the other controllers before doing so.
bool checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId,
AtcMsgDir msgDir);
};
};
/******************************************************************************
* class FGTowerControl
@ -382,30 +546,35 @@ public:
class FGApproachController : public FGATCController
{
private:
TrafficVector activeTraffic;
ActiveRunwayVec activeRunways;
FGAirportDynamics *parent;
TrafficVector activeTraffic;
ActiveRunwayVec activeRunways;
FGAirportDynamics *parent;
public:
FGApproachController(FGAirportDynamics * parent);
virtual ~FGApproachController() { };
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon,
double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft);
virtual void signOff(int id);
virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
FGApproachController(FGAirportDynamics * parent);
virtual ~FGApproachController() { };
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon,
double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft);
virtual void signOff(int id);
virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
virtual void render(bool);
virtual string getName();
virtual void render(bool);
virtual string getName();
virtual void update(double dt);
ActiveRunway* getRunway(string name);
ActiveRunway* getRunway(string name);
bool hasActiveTraffic() { return activeTraffic.size() != 0; };
TrafficVector &getActiveTraffic() { return activeTraffic; };
bool hasActiveTraffic() {
return activeTraffic.size() != 0;
};
TrafficVector &getActiveTraffic() {
return activeTraffic;
};
};

View file

@ -253,16 +253,26 @@ void FGATCMgr::FreqSearch(const string navcomm, const int unit) {
class RangeFilter : public CommStation::Filter {
public:
RangeFilter( const SGGeod & pos ) : CommStation::Filter(), _pos(pos) {}
virtual bool pass(FGPositioned* aPos) const {
RangeFilter( const SGGeod & pos ) :
CommStation::Filter(),
_cart(SGVec3d::fromGeod(pos)),
_pos(pos)
{}
virtual bool pass(FGPositioned* aPos) const
{
flightgear::CommStation * stn = dynamic_cast<flightgear::CommStation*>(aPos);
if( NULL == stn ) return false;
double dist = SGGeodesy::distanceNm( stn->geod(), _pos );
// if range is not configured, assume at least 10NM range
// TODO: maybe ramp down range with proximity to ground?
return dist <= SGMiscd::max( stn->rangeNm(), 10.0 );
// do the range check in cartesian space, since the distances are potentially
// large enough that the geodetic functions become unstable
// (eg, station on opposite side of the planet)
double rangeM = SGMiscd::max( stn->rangeNm(), 10.0 ) * SG_NM_TO_METER;
double d2 = distSqr( aPos->cart(), _cart);
return d2 <= (rangeM * rangeM);
}
private:
SGVec3d _cart;
SGGeod _pos;
};

View file

@ -9,5 +9,17 @@ set(SOURCES
ATCutils.cxx
ATCProjection.cxx
)
flightgear_component(ATCDCL "${SOURCES}")
set(HEADERS
ATC.hxx
atis.hxx
ATCDialogOld.hxx
ATCVoice.hxx
ATCmgr.hxx
ATCutils.hxx
ATCProjection.hxx
atis_lexicon.hxx
atis_remap.hxx
)
flightgear_component(ATCDCL "${SOURCES}" "${HEADERS}")

View file

@ -3,12 +3,14 @@ include(FlightGearComponent)
set(SOURCES
controls.cxx
replay.cxx
flightrecorder.cxx
)
set(HEADERS
controls.hxx
replay.hxx
flightrecorder.hxx
)
flightgear_component(Aircraft "${SOURCES}" "${HEADERS}")
flightgear_component(Aircraft "${SOURCES}" "${HEADERS}")

View file

@ -2,6 +2,7 @@ noinst_LIBRARIES = libAircraft.a
libAircraft_a_SOURCES = \
controls.cxx controls.hxx \
replay.cxx replay.hxx
replay.cxx replay.hxx \
flightrecorder.cxx flightrecorder.hxx
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src

View file

@ -0,0 +1,544 @@
// flightrecorder.cxx
//
// Written by Thorsten Brehm, started August 2011.
//
// Copyright (C) 2011 Thorsten Brehm - brehmt (at) gmail com
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
///////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/misc/ResourceManager.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/structure/exception.hxx>
#include <Main/fg_props.hxx>
#include "flightrecorder.hxx"
using namespace FlightRecorder;
FGFlightRecorder::FGFlightRecorder(const char* pConfigName) :
m_RecorderNode(fgGetNode("/sim/flight-recorder", true)),
m_TotalRecordSize(0),
m_ConfigName(pConfigName)
{
}
FGFlightRecorder::~FGFlightRecorder()
{
}
void
FGFlightRecorder::reinit(void)
{
m_ConfigNode = 0;
m_TotalRecordSize = 0;
m_CaptureDouble.clear();
m_CaptureFloat.clear();
m_CaptureInteger.clear();
m_CaptureInt16.clear();
m_CaptureInt8.clear();
m_CaptureBool.clear();
int Selected = m_RecorderNode->getIntValue(m_ConfigName, 0);
SG_LOG(SG_SYSTEMS, SG_INFO, "FlightRecorder: Recorder configuration #" << Selected);
if (Selected >= 0)
m_ConfigNode = m_RecorderNode->getChild("config", Selected);
if (!m_ConfigNode.valid())
initDefault();
if (!m_ConfigNode.valid())
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "FlightRecorder: Configuration is invalid. Flight recorder disabled.");
}
else
{
// set name of active flight recorder type
const char* pRecorderName =
m_ConfigNode->getStringValue("name",
"aircraft-specific flight recorder");
SG_LOG(SG_SYSTEMS, SG_INFO, "FlightRecorder: Using custom recorder configuration: " << pRecorderName);
m_RecorderNode->setStringValue("active-config-name", pRecorderName);
// get signals
initSignalList("double", m_CaptureDouble, m_ConfigNode );
initSignalList("float", m_CaptureFloat , m_ConfigNode );
initSignalList("int", m_CaptureInteger, m_ConfigNode );
initSignalList("int16", m_CaptureInt16 , m_ConfigNode );
initSignalList("int8", m_CaptureInt8 , m_ConfigNode );
initSignalList("bool", m_CaptureBool , m_ConfigNode );
}
// calculate size of a single record
m_TotalRecordSize = sizeof(double) * 1 /* sim time */ +
sizeof(double) * m_CaptureDouble.size() +
sizeof(float) * m_CaptureFloat.size() +
sizeof(int) * m_CaptureInteger.size() +
sizeof(short int) * m_CaptureInt16.size() +
sizeof(signed char) * m_CaptureInt8.size() +
sizeof(unsigned char) * ((m_CaptureBool.size()+7)/8); // 8 bools per byte
// expose size of actual flight recorder record
m_RecorderNode->setIntValue("record-size", m_TotalRecordSize);
SG_LOG(SG_SYSTEMS, SG_INFO, "FlightRecorder: record size is " << m_TotalRecordSize << " bytes");
}
/** Check if SignalList already contains the given property */
bool
FGFlightRecorder::haveProperty(FlightRecorder::TSignalList& SignalList,SGPropertyNode* pProperty)
{
unsigned int Count = SignalList.size();
for (unsigned int i=0; i<Count; i++)
{
if (SignalList[i].Signal.get() == pProperty)
{
return true;
}
}
return false;
}
/** Check if any signal list already contains the given property */
bool
FGFlightRecorder::haveProperty(SGPropertyNode* pProperty)
{
if (haveProperty(m_CaptureDouble, pProperty))
return true;
if (haveProperty(m_CaptureFloat, pProperty))
return true;
if (haveProperty(m_CaptureInteger, pProperty))
return true;
if (haveProperty(m_CaptureInt16, pProperty))
return true;
if (haveProperty(m_CaptureInt8, pProperty))
return true;
if (haveProperty(m_CaptureBool, pProperty))
return true;
return false;
}
/** Read default flight-recorder configuration.
* Default should match properties as hard coded for versions up to FG2.4.0. */
void
FGFlightRecorder::initDefault(void)
{
// set name of active flight recorder type
SG_LOG(SG_SYSTEMS, SG_INFO, "FlightRecorder: No custom configuration. Loading generic default recorder.");
const char* Path = m_RecorderNode->getStringValue("default-config",NULL);
if (!Path)
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "FlightRecorder: No default flight recorder specified! Check preferences.xml!");
}
else
{
SGPath path = globals->resolve_aircraft_path(Path);
if (path.isNull())
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "FlightRecorder: Cannot find file '" << Path << "'.");
}
else
{
try
{
readProperties(path.str(), m_RecorderNode->getChild("config", 0 ,true), 0);
m_ConfigNode = m_RecorderNode->getChild("config", 0 ,false);
} catch (sg_io_exception &e)
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "FlightRecorder: Error reading file '" <<
Path << ": " << e.getFormattedMessage());
}
}
}
}
/** Read signal list below given base node.
* Only process properties of given signal type and add all signals to the given list.
* This method is called for all supported signal types - properties of each type are
* kept in separate lists for efficiency reasons. */
void
FGFlightRecorder::initSignalList(const char* pSignalType, TSignalList& SignalList, SGPropertyNode_ptr BaseNode)
{
// clear old signals
SignalList.clear();
processSignalList(pSignalType, SignalList, BaseNode);
SG_LOG(SG_SYSTEMS, SG_DEBUG, "FlightRecorder: " << SignalList.size() << " signals of type " << pSignalType );
}
/** Process signal list below given base node.
* Only process properties of given signal type and add all signals to the given list.
* This method is called for all supported signal types - properties of each type are
* kept in separate lists for efficiency reasons. */
void
FGFlightRecorder::processSignalList(const char* pSignalType, TSignalList& SignalList, SGPropertyNode_ptr SignalListNode,
string PropPrefix, int Count)
{
// get the list of signal sources (property paths) for this signal type
SGPropertyNode_ptr SignalNode;
int Index=0;
Count = SignalListNode->getIntValue("count",Count);
PropPrefix = simgear::strutils::strip(SignalListNode->getStringValue("prefix",PropPrefix.c_str()));
if ((!PropPrefix.empty())&&(PropPrefix[PropPrefix.size()-1] != '/'))
PropPrefix += "/";
do
{
SignalNode = SignalListNode->getChild("signal",Index,false);
if (SignalNode.valid()&&
(0==strcmp(pSignalType, SignalNode->getStringValue("type","float"))))
{
string PropertyPath = SignalNode->getStringValue("property","");
if (!PropertyPath.empty())
{
PropertyPath = PropPrefix + PropertyPath;
const char* pInterpolation = SignalNode->getStringValue("interpolation","linear");
// Check if current signal has a "%i" place holder. Otherwise count is 1.
string::size_type IndexPos = PropertyPath.find("%i");
int SignalCount = Count;
if (IndexPos == string::npos)
SignalCount = 1;
for (int IndexValue=0;IndexValue<SignalCount;IndexValue++)
{
string PPath = PropertyPath;
if (IndexPos != string::npos)
{
char strbuf[20];
snprintf(strbuf, 20, "%d", IndexValue);
PPath = PPath.replace(IndexPos,2,strbuf);
}
TCapture Capture;
Capture.Signal = fgGetNode(PPath.c_str(),false);
if (!Capture.Signal.valid())
{
// warn user: we're maybe going to record useless data
// Or maybe the data is only initialized later. Warn anyway, so we can catch useless data.
SG_LOG(SG_SYSTEMS, SG_INFO, "FlightRecorder: Recording non-existent property '" << PPath << "'.");
Capture.Signal = fgGetNode(PPath.c_str(),true);
}
if (0==strcmp(pInterpolation,"discrete"))
Capture.Interpolation = discrete;
else
if ((0==strcmp(pInterpolation,"angular"))||
(0==strcmp(pInterpolation,"angular-rad")))
Capture.Interpolation = angular_rad;
else
if (0==strcmp(pInterpolation,"angular-deg"))
Capture.Interpolation = angular_deg;
else
if (0==strcmp(pInterpolation,"linear"))
Capture.Interpolation = linear;
else
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "FlightRecorder: Unsupported interpolation type '"
<< pInterpolation<< "' of signal '" << PPath << "'");
Capture.Interpolation = linear;
}
if (haveProperty(Capture.Signal))
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "FlightRecorder: Property '"
<< PPath << "' specified multiple times. Check flight recorder configuration.");
}
else
SignalList.push_back(Capture);
}
}
}
Index++;
} while (SignalNode.valid());
// allow recursive definition of signal lists
simgear::PropertyList Nodes = SignalListNode->getChildren("signals");
for (unsigned int i=0;i<Nodes.size();i++)
{
processSignalList(pSignalType, SignalList, Nodes[i], PropPrefix, Count);
}
}
/** Get an empty container for a single capture. */
FGReplayData*
FGFlightRecorder::createEmptyRecord(void)
{
if (!m_TotalRecordSize)
return NULL;
FGReplayData* p = (FGReplayData*) new unsigned char[m_TotalRecordSize];
return p;
}
/** Free given container with capture data. */
void
FGFlightRecorder::deleteRecord(FGReplayData* pRecord)
{
delete[] pRecord;
}
/** Capture data.
* When pBuffer==NULL new memory is allocated.
* If pBuffer!=NULL memory of given buffer is reused.
*/
FGReplayData*
FGFlightRecorder::capture(double SimTime, FGReplayData* pRecycledBuffer)
{
if (!pRecycledBuffer)
{
pRecycledBuffer = createEmptyRecord();
if (!pRecycledBuffer)
return NULL;
}
unsigned char* pBuffer = (unsigned char*) pRecycledBuffer;
int Offset = 0;
pRecycledBuffer->sim_time = SimTime;
Offset += sizeof(double);
// 64bit aligned data first!
{
// capture doubles
double* pDoubles = (double*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureDouble.size();
for (unsigned int i=0; i<SignalCount; i++)
{
pDoubles[i] = m_CaptureDouble[i].Signal->getDoubleValue();
}
Offset += SignalCount * sizeof(double);
}
// 32bit aligned data comes second...
{
// capture floats
float* pFloats = (float*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureFloat.size();
for (unsigned int i=0; i<SignalCount; i++)
{
pFloats[i] = m_CaptureFloat[i].Signal->getFloatValue();
}
Offset += SignalCount * sizeof(float);
}
{
// capture integers (32bit aligned)
int* pInt = (int*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureInteger.size();
for (unsigned int i=0; i<SignalCount; i++)
{
pInt[i] = m_CaptureInteger[i].Signal->getIntValue();
}
Offset += SignalCount * sizeof(int);
}
// 16bit aligned data is next...
{
// capture 16bit short integers
short int* pShortInt = (short int*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureInt16.size();
for (unsigned int i=0; i<SignalCount; i++)
{
pShortInt[i] = (short int) m_CaptureInt16[i].Signal->getIntValue();
}
Offset += SignalCount * sizeof(short int);
}
// finally: byte aligned data is last...
{
// capture 8bit chars
signed char* pChar = (signed char*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureInt8.size();
for (unsigned int i=0; i<SignalCount; i++)
{
pChar[i] = (signed char) m_CaptureInt8[i].Signal->getIntValue();
}
Offset += SignalCount * sizeof(signed char);
}
{
// capture 1bit booleans (8bit aligned)
unsigned char* pFlags = (unsigned char*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureBool.size();
int Size = (SignalCount+7)/8;
Offset += Size;
memset(pFlags,0,Size);
for (unsigned int i=0; i<SignalCount; i++)
{
if (m_CaptureBool[i].Signal->getBoolValue())
pFlags[i>>3] |= 1 << (i&7);
}
}
assert(Offset == m_TotalRecordSize);
return (FGReplayData*) pBuffer;
}
/** Do interpolation as defined by given interpolation type and weighting ratio. */
static double
weighting(TInterpolation interpolation, double ratio, double v1,double v2)
{
switch (interpolation)
{
case linear:
return v1 + ratio*(v2-v1);
case angular_deg:
{
// special handling of angular data
double tmp = v2 - v1;
if ( tmp > 180 )
tmp -= 360;
else if ( tmp < -180 )
tmp += 360;
return v1 + tmp * ratio;
}
case angular_rad:
{
// special handling of angular data
double tmp = v2 - v1;
if ( tmp > SGD_PI )
tmp -= SGD_2PI;
else if ( tmp < -SGD_PI )
tmp += SGD_2PI;
return v1 + tmp * ratio;
}
case discrete:
// fall through
default:
return v2;
}
}
/** Replay.
* Restore all properties with data from given buffer. */
void
FGFlightRecorder::replay(double SimTime, const FGReplayData* _pNextBuffer, const FGReplayData* _pLastBuffer)
{
const char* pLastBuffer = (const char*) _pLastBuffer;
const char* pBuffer = (const char*) _pNextBuffer;
if (!pBuffer)
return;
int Offset = 0;
double ratio;
if (pLastBuffer)
{
double NextSimTime = _pNextBuffer->sim_time;
double LastSimTime = _pLastBuffer->sim_time;
ratio = (SimTime - LastSimTime) / (NextSimTime - LastSimTime);
}
else
{
ratio = 1.0;
}
Offset += sizeof(double);
// 64bit aligned data first!
{
// restore doubles
const double* pDoubles = (const double*) &pBuffer[Offset];
const double* pLastDoubles = (const double*) &pLastBuffer[Offset];
unsigned int SignalCount = m_CaptureDouble.size();
for (unsigned int i=0; i<SignalCount; i++)
{
double v = pDoubles[i];
if (pLastBuffer)
{
v = weighting(m_CaptureDouble[i].Interpolation, ratio,
pLastDoubles[i], v);
}
m_CaptureDouble[i].Signal->setDoubleValue(v);
}
Offset += SignalCount * sizeof(double);
}
// 32bit aligned data comes second...
{
// restore floats
const float* pFloats = (const float*) &pBuffer[Offset];
const float* pLastFloats = (const float*) &pLastBuffer[Offset];
unsigned int SignalCount = m_CaptureFloat.size();
for (unsigned int i=0; i<SignalCount; i++)
{
float v = pFloats[i];
if (pLastBuffer)
{
v = weighting(m_CaptureFloat[i].Interpolation, ratio,
pLastFloats[i], v);
}
m_CaptureFloat[i].Signal->setDoubleValue(v);//setFloatValue
}
Offset += SignalCount * sizeof(float);
}
{
// restore integers (32bit aligned)
const int* pInt = (const int*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureInteger.size();
for (unsigned int i=0; i<SignalCount; i++)
{
m_CaptureInteger[i].Signal->setIntValue(pInt[i]);
}
Offset += SignalCount * sizeof(int);
}
// 16bit aligned data is next...
{
// restore 16bit short integers
const short int* pShortInt = (const short int*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureInt16.size();
for (unsigned int i=0; i<SignalCount; i++)
{
m_CaptureInt16[i].Signal->setIntValue(pShortInt[i]);
}
Offset += SignalCount * sizeof(short int);
}
// finally: byte aligned data is last...
{
// restore 8bit chars
const signed char* pChar = (const signed char*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureInt8.size();
for (unsigned int i=0; i<SignalCount; i++)
{
m_CaptureInt8[i].Signal->setIntValue(pChar[i]);
}
Offset += SignalCount * sizeof(signed char);
}
{
// restore 1bit booleans (8bit aligned)
const unsigned char* pFlags = (const unsigned char*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureBool.size();
int Size = (SignalCount+7)/8;
Offset += Size;
for (unsigned int i=0; i<SignalCount; i++)
{
m_CaptureBool[i].Signal->setBoolValue(0 != (pFlags[i>>3] & (1 << (i&7))));
}
}
}

View file

@ -0,0 +1,89 @@
// flightrecorder.hxx
//
// Written by Thorsten Brehm, started August 2011.
//
// Copyright (C) 2011 Thorsten Brehm - brehmt (at) gmail com
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef FLIGHTRECORDER_HXX_
#define FLIGHTRECORDER_HXX_
#include <simgear/props/props.hxx>
#include "replay.hxx"
namespace FlightRecorder
{
typedef enum
{
discrete = 0, // no interpolation
linear = 1, // linear interpolation
angular_rad = 2, // angular interpolation, value in radians
angular_deg = 3 // angular interpolation, value in degrees
} TInterpolation;
typedef struct
{
SGPropertyNode_ptr Signal;
TInterpolation Interpolation;
} TCapture;
typedef std::vector<TCapture> TSignalList;
}
class FGFlightRecorder
{
public:
FGFlightRecorder(const char* pConfigName);
virtual ~FGFlightRecorder();
void reinit (void);
FGReplayData* createEmptyRecord (void);
FGReplayData* capture (double SimTime, FGReplayData* pRecycledBuffer);
void replay (double SimTime, const FGReplayData* pNextBuffer,
const FGReplayData* pLastBuffer = NULL);
void deleteRecord (FGReplayData* pRecord);
int getRecordSize (void) { return m_TotalRecordSize;}
private:
void initDefault(void);
void initSignalList(const char* pSignalType, FlightRecorder::TSignalList& SignalList,
SGPropertyNode_ptr BaseNode);
void processSignalList(const char* pSignalType, FlightRecorder::TSignalList& SignalList,
SGPropertyNode_ptr SignalListNode,
string PropPrefix="", int Count = 1);
bool haveProperty(FlightRecorder::TSignalList& Capture,SGPropertyNode* pProperty);
bool haveProperty(SGPropertyNode* pProperty);
SGPropertyNode_ptr m_RecorderNode;
SGPropertyNode_ptr m_ConfigNode;
FlightRecorder::TSignalList m_CaptureDouble;
FlightRecorder::TSignalList m_CaptureFloat;
FlightRecorder::TSignalList m_CaptureInteger;
FlightRecorder::TSignalList m_CaptureInt16;
FlightRecorder::TSignalList m_CaptureInt8;
FlightRecorder::TSignalList m_CaptureBool;
int m_TotalRecordSize;
string m_ConfigName;
};
#endif /* FLIGHTRECORDER_HXX_ */

View file

@ -1,6 +1,7 @@
// replay.cxx - a system to record and replay FlightGear flights
//
// Written by Curtis Olson, started Juley 2003.
// Written by Curtis Olson, started July 2003.
// Updated by Thorsten Brehm, September 2011.
//
// Copyright (C) 2003 Curtis L. Olson - http://www.flightgear.org/~curt
//
@ -25,36 +26,31 @@
#endif
#include <float.h>
#include <simgear/constants.h>
#include <simgear/structure/exception.hxx>
#include <Main/fg_props.hxx>
#include <Network/native_ctrls.hxx>
#include <Network/native_fdm.hxx>
#include <Network/net_ctrls.hxx>
#include <Network/net_fdm.hxx>
#include <FDM/fdm_shell.hxx>
#include "replay.hxx"
const double FGReplay::st_list_time = 60.0; // 60 secs of high res data
const double FGReplay::mt_list_time = 600.0; // 10 mins of 1 fps data
const double FGReplay::lt_list_time = 3600.0; // 1 hr of 10 spf data
// short term sample rate is as every frame
const double FGReplay::mt_dt = 0.5; // medium term sample rate (sec)
const double FGReplay::lt_dt = 5.0; // long term sample rate (sec)
#include "flightrecorder.hxx"
/**
* Constructor
*/
FGReplay::FGReplay() :
last_replay_state(0)
last_replay_state(0),
m_high_res_time(60.0),
m_medium_res_time(600.0),
m_low_res_time(3600.0),
m_medium_sample_rate(0.5), // medium term sample rate (sec)
m_long_sample_rate(5.0), // long term sample rate (sec)
m_pRecorder(new FGFlightRecorder("replay-config"))
{
}
/**
* Destructor
*/
@ -62,31 +58,35 @@ FGReplay::FGReplay() :
FGReplay::~FGReplay()
{
clear();
delete m_pRecorder;
m_pRecorder = NULL;
}
/**
* Clear all internal buffers.
*/
void FGReplay::clear()
void
FGReplay::clear()
{
while ( !short_term.empty() )
{
delete short_term.front();
m_pRecorder->deleteRecord(short_term.front());
short_term.pop_front();
}
while ( !medium_term.empty() )
{
delete medium_term.front();
m_pRecorder->deleteRecord(medium_term.front());
medium_term.pop_front();
}
while ( !long_term.empty() )
{
delete long_term.front();
m_pRecorder->deleteRecord(long_term.front());
long_term.pop_front();
}
while ( !recycler.empty() )
{
delete recycler.front();
m_pRecorder->deleteRecord(recycler.front());
recycler.pop_front();
}
}
@ -95,12 +95,15 @@ void FGReplay::clear()
* Initialize the data structures
*/
void FGReplay::init()
void
FGReplay::init()
{
disable_replay = fgGetNode( "/sim/replay/disable", true );
replay_master = fgGetNode( "/sim/freeze/replay-state", true );
replay_time = fgGetNode( "/sim/replay/time", true);
replay_looped = fgGetNode( "/sim/replay/looped", true);
disable_replay = fgGetNode("/sim/replay/disable", true);
replay_master = fgGetNode("/sim/freeze/replay-state", true);
replay_time = fgGetNode("/sim/replay/time", true);
replay_time_str = fgGetNode("/sim/replay/time-str", true);
replay_looped = fgGetNode("/sim/replay/looped", true);
speed_up = fgGetNode("/sim/speed-up", true);
reinit();
}
@ -108,33 +111,50 @@ void FGReplay::init()
* Reset replay queues.
*/
void FGReplay::reinit()
void
FGReplay::reinit()
{
sim_time = 0.0;
last_mt_time = 0.0;
last_lt_time = 0.0;
// Make sure all queues are flushed
// Flush queues
clear();
m_pRecorder->reinit();
m_high_res_time = fgGetDouble("/sim/replay/buffer/high-res-time", 60.0);
m_medium_res_time = fgGetDouble("/sim/replay/buffer/medium-res-time", 600.0); // 10 mins
m_low_res_time = fgGetDouble("/sim/replay/buffer/low-res-time", 3600.0); // 1 h
// short term sample rate is as every frame
m_medium_sample_rate = fgGetDouble("/sim/replay/buffer/medium-res-sample-dt", 0.5); // medium term sample rate (sec)
m_long_sample_rate = fgGetDouble("/sim/replay/buffer/low-res-sample-dt", 5.0); // long term sample rate (sec)
// Create an estimated nr of required ReplayData objects
// 120 is an estimated maximum frame rate.
int estNrObjects = (int) ((st_list_time*120) + (mt_list_time*mt_dt) +
(lt_list_time*lt_dt));
// 120 is an estimated maximum frame rate.
int estNrObjects = (int) ((m_high_res_time*120) + (m_medium_res_time*m_medium_sample_rate) +
(m_low_res_time*m_long_sample_rate));
for (int i = 0; i < estNrObjects; i++)
{
recycler.push_back(new FGReplayData);
FGReplayData* r = m_pRecorder->createEmptyRecord();
if (r)
recycler.push_back(r);
else
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "ReplaySystem: Out of memory!");
}
}
replay_master->setIntValue(0);
disable_replay->setBoolValue(0);
replay_time->setDoubleValue(0);
replay_time_str->setStringValue("");
}
/**
* Bind to the property tree
*/
void FGReplay::bind()
void
FGReplay::bind()
{
}
@ -143,26 +163,85 @@ void FGReplay::bind()
* Unbind from the property tree
*/
void FGReplay::unbind()
void
FGReplay::unbind()
{
// nothing to unbind
}
static void
printTimeStr(char* pStrBuffer,double _Time, bool ShowDecimal=true)
{
if (_Time<0)
_Time = 0;
unsigned int Time = (unsigned int) (_Time*10);
int h = Time/36000;
int m = (Time % 36000)/600;
int s = (Time % 600)/10;
int d = Time % 10;
if (h>0)
sprintf(pStrBuffer,"%u:%02u",h,m);
else
sprintf(pStrBuffer,"%u",m);
if (ShowDecimal)
sprintf(pStrBuffer,"%s:%02u.%u",pStrBuffer,s,d);
else
sprintf(pStrBuffer,"%s:%02u",pStrBuffer,s);
}
/** Start replay session
*/
bool
FGReplay::start()
{
// freeze the fdm, resume from sim pause
double StartTime = get_start_time();
double EndTime = get_end_time();
fgSetDouble("/sim/replay/start-time", StartTime);
fgSetDouble("/sim/replay/end-time", EndTime);
char StrBuffer[30];
printTimeStr(StrBuffer,StartTime,false);
fgSetString("/sim/replay/start-time-str", StrBuffer);
printTimeStr(StrBuffer,EndTime,false);
fgSetString("/sim/replay/end-time-str", StrBuffer);
unsigned long buffer_elements = short_term.size()+medium_term.size()+long_term.size();
fgSetDouble("/sim/replay/buffer-size-mbyte",
buffer_elements*m_pRecorder->getRecordSize() / (1024*1024.0));
if ((fgGetBool("/sim/freeze/master"))||
(0 == replay_master->getIntValue()))
fgSetString("/sim/messages/copilot", "Replay active. 'Esc' to stop.");
fgSetBool ("/sim/freeze/master", 0);
fgSetBool ("/sim/freeze/clock", 0);
if (0 == replay_master->getIntValue())
{
replay_master->setIntValue(1);
replay_time->setDoubleValue(-1);
replay_time_str->setStringValue("");
}
return true;
}
/**
* Update the saved data
*/
void FGReplay::update( double dt )
void
FGReplay::update( double dt )
{
int current_replay_state = last_replay_state;
timingInfo.clear();
stamp("begin");
if ( disable_replay->getBoolValue() )
{
current_replay_state = replay_master->getIntValue();
replay_master->setIntValue(0);
replay_time->setDoubleValue(0);
replay_time_str->setStringValue("");
disable_replay->setBoolValue(0);
speed_up->setDoubleValue(1.0);
fgSetString("/sim/messages/copilot", "Replay stopped");
}
int replay_state = replay_master->getIntValue();
@ -180,8 +259,17 @@ void FGReplay::update( double dt )
if ((replay_state == 0)&&
(last_replay_state > 0))
{
// replay was active, restore most recent frame
replay(DBL_MAX);
if (current_replay_state == 3)
{
// "my controls!" requested: pilot takes control at current replay position...
// May need to uncrash the aircraft here :)
fgSetBool("/sim/crashed", false);
}
else
{
// replay was active, restore most recent frame
replay(DBL_MAX);
}
// replay is finished, resume FDM
((FDMShell*) globals->get_subsystem("flight"))->getFDM()->resume();
}
@ -195,30 +283,36 @@ void FGReplay::update( double dt )
// replay inactive, keep recording
break;
case 1:
{
// replay active
double current_time = replay_time->getDoubleValue();
if (current_time<=0.0)
{
// replay active
double current_time = replay_time->getDoubleValue();
if (current_time<0.0)
{
// initialize start time
fgSetDouble( "/sim/replay/start-time", get_start_time() );
fgSetDouble( "/sim/replay/end-time", get_end_time() );
double duration = fgGetDouble( "/sim/replay/duration" );
if( duration && duration < (get_end_time() - get_start_time()) ) {
current_time = get_end_time() - duration;
} else {
current_time = get_start_time();
}
// initialize start time
double startTime = get_start_time();
double endTime = get_end_time();
fgSetDouble( "/sim/replay/start-time", startTime );
fgSetDouble( "/sim/replay/end-time", endTime );
double duration = fgGetDouble( "/sim/replay/duration" );
if( duration && (duration < (endTime - startTime)) ) {
current_time = endTime - duration;
} else {
current_time = startTime;
}
bool IsFinished = replay( replay_time->getDoubleValue() );
if ((IsFinished)&&(replay_looped->getBoolValue()))
current_time = -1;
else
current_time += dt * fgGetInt("/sim/speed-up");
replay_time->setDoubleValue(current_time);
}
bool IsFinished = replay( replay_time->getDoubleValue() );
if (IsFinished)
current_time = (replay_looped->getBoolValue()) ? -1 : get_end_time()+0.01;
else
current_time += dt * speed_up->getDoubleValue();
replay_time->setDoubleValue(current_time);
char StrBuffer[30];
printTimeStr(StrBuffer,current_time);
replay_time_str->setStringValue((const char*)StrBuffer);
return; // don't record the replay session
case 2:
}
case 2: // normal replay operation
case 3: // replay operation, prepare to resume normal flight at current replay position
// replay paused, no-op
return; // don't record the replay session
default:
@ -228,78 +322,64 @@ void FGReplay::update( double dt )
// flight recording
//cerr << "Recording replay" << endl;
sim_time += dt;
// build the replay record
//FGNetFDM f;
//FGProps2NetFDM( &f, false );
sim_time += dt * speed_up->getDoubleValue();
// sanity check, don't collect data if FDM data isn't good
if (!fgGetBool("/sim/fdm-initialized", false)) {
return;
}
//FGNetCtrls c;
//FGProps2NetCtrls( &c, false, false );
//stamp("point_04ba");
FGReplayData *r;
//stamp("point_04bb");
if (!recycler.size()) {
stamp("Replay_01");
r = new FGReplayData;
stamp("Replay_02");
} else {
r = recycler.front();
recycler.pop_front();
//stamp("point_04be");
}
r->sim_time = sim_time;
//r->ctrls = c;
//stamp("point_04e");
FGProps2NetFDM( &(r->fdm), false );
FGProps2NetCtrls( &(r->ctrls), false, false );
//r->fdm = f;
//stamp("point_05");
FGReplayData* r = record(sim_time);
if (!r)
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "ReplaySystem: Out of memory!");
return;
}
// update the short term list
//stamp("point_06");
short_term.push_back( r );
//stamp("point_07");
FGReplayData *st_front = short_term.front();
if ( sim_time - st_front->sim_time > st_list_time ) {
while ( sim_time - st_front->sim_time > st_list_time ) {
if (!st_front)
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "ReplaySystem: Inconsistent data!");
}
if ( sim_time - st_front->sim_time > m_high_res_time ) {
while ( sim_time - st_front->sim_time > m_high_res_time ) {
st_front = short_term.front();
recycler.push_back(st_front);
short_term.pop_front();
}
//stamp("point_08");
// update the medium term list
if ( sim_time - last_mt_time > mt_dt ) {
if ( sim_time - last_mt_time > m_medium_sample_rate ) {
last_mt_time = sim_time;
st_front = short_term.front();
medium_term.push_back( st_front );
short_term.pop_front();
FGReplayData *mt_front = medium_term.front();
if ( sim_time - mt_front->sim_time > mt_list_time ) {
if ( sim_time - mt_front->sim_time > m_medium_res_time ) {
//stamp("point_09");
while ( sim_time - mt_front->sim_time > mt_list_time ) {
while ( sim_time - mt_front->sim_time > m_medium_res_time ) {
mt_front = medium_term.front();
recycler.push_back(mt_front);
medium_term.pop_front();
}
// update the long term list
if ( sim_time - last_lt_time > lt_dt ) {
if ( sim_time - last_lt_time > m_long_sample_rate ) {
last_lt_time = sim_time;
mt_front = medium_term.front();
long_term.push_back( mt_front );
medium_term.pop_front();
FGReplayData *lt_front = long_term.front();
if ( sim_time - lt_front->sim_time > lt_list_time ) {
if ( sim_time - lt_front->sim_time > m_low_res_time ) {
//stamp("point_10");
while ( sim_time - lt_front->sim_time > lt_list_time ) {
while ( sim_time - lt_front->sim_time > m_low_res_time ) {
lt_front = long_term.front();
recycler.push_back(lt_front);
long_term.pop_front();
@ -324,224 +404,37 @@ void FGReplay::update( double dt )
//stamp("point_finished");
}
static double weight( double data1, double data2, double ratio,
bool rotational = false ) {
if ( rotational ) {
// special handling of rotational data
double tmp = data2 - data1;
if ( tmp > SGD_PI ) {
tmp -= SGD_2PI;
} else if ( tmp < -SGD_PI ) {
tmp += SGD_2PI;
}
return data1 + tmp * ratio;
} else {
// normal "linear" data
return data1 + ( data2 - data1 ) * ratio;
}
}
/**
* given two FGReplayData elements and a time, interpolate between them
*/
static void update_fdm( FGReplayData frame ) {
FGNetFDM2Props( &frame.fdm, false );
FGNetCtrls2Props( &frame.ctrls, false, false );
}
/**
* given two FGReplayData elements and a time, interpolate between them
*/
static FGReplayData interpolate( double time, FGReplayData f1, FGReplayData f2 )
FGReplayData*
FGReplay::record(double time)
{
FGReplayData result = f1;
FGReplayData* r = NULL;
FGNetFDM fdm1 = f1.fdm;
FGNetFDM fdm2 = f2.fdm;
FGNetCtrls ctrls1 = f1.ctrls;
FGNetCtrls ctrls2 = f2.ctrls;
double ratio = (time - f1.sim_time) / (f2.sim_time - f1.sim_time);
// Interpolate FDM data
// Positions
result.fdm.longitude = weight( fdm1.longitude, fdm2.longitude, ratio );
result.fdm.latitude = weight( fdm1.latitude, fdm2.latitude, ratio );
result.fdm.altitude = weight( fdm1.altitude, fdm2.altitude, ratio );
result.fdm.agl = weight( fdm1.agl, fdm2.agl, ratio );
result.fdm.phi = weight( fdm1.phi, fdm2.phi, ratio, true );
result.fdm.theta = weight( fdm1.theta, fdm2.theta, ratio, true );
result.fdm.psi = weight( fdm1.psi, fdm2.psi, ratio, true );
// Velocities
result.fdm.phidot = weight( fdm1.phidot, fdm2.phidot, ratio, true );
result.fdm.thetadot = weight( fdm1.thetadot, fdm2.thetadot, ratio, true );
result.fdm.psidot = weight( fdm1.psidot, fdm2.psidot, ratio, true );
result.fdm.vcas = weight( fdm1.vcas, fdm2.vcas, ratio );
result.fdm.climb_rate = weight( fdm1.climb_rate, fdm2.climb_rate, ratio );
result.fdm.v_north = weight( fdm1.v_north, fdm2.v_north, ratio );
result.fdm.v_east = weight( fdm1.v_east, fdm2.v_east, ratio );
result.fdm.v_down = weight( fdm1.v_down, fdm2.v_down, ratio );
result.fdm.v_wind_body_north
= weight( fdm1.v_wind_body_north, fdm2.v_wind_body_north, ratio );
result.fdm.v_wind_body_east
= weight( fdm1.v_wind_body_east, fdm2.v_wind_body_east, ratio );
result.fdm.v_wind_body_down
= weight( fdm1.v_wind_body_down, fdm2.v_wind_body_down, ratio );
// Stall
result.fdm.stall_warning
= weight( fdm1.stall_warning, fdm2.stall_warning, ratio );
// Accelerations
result.fdm.A_X_pilot = weight( fdm1.A_X_pilot, fdm2.A_X_pilot, ratio );
result.fdm.A_Y_pilot = weight( fdm1.A_Y_pilot, fdm2.A_Y_pilot, ratio );
result.fdm.A_Z_pilot = weight( fdm1.A_Z_pilot, fdm2.A_Z_pilot, ratio );
unsigned int i;
// Engine status
for ( i = 0; i < fdm1.num_engines; ++i ) {
result.fdm.eng_state[i] = fdm1.eng_state[i];
result.fdm.rpm[i] = weight( fdm1.rpm[i], fdm2.rpm[i], ratio );
result.fdm.fuel_flow[i]
= weight( fdm1.fuel_flow[i], fdm2.fuel_flow[i], ratio );
result.fdm.fuel_px[i]
= weight( fdm1.fuel_px[i], fdm2.fuel_px[i], ratio );
result.fdm.egt[i] = weight( fdm1.egt[i], fdm2.egt[i], ratio );
result.fdm.cht[i] = weight( fdm1.cht[i], fdm2.cht[i], ratio );
result.fdm.mp_osi[i] = weight( fdm1.mp_osi[i], fdm2.mp_osi[i], ratio );
result.fdm.tit[i] = weight( fdm1.tit[i], fdm2.tit[i], ratio );
result.fdm.oil_temp[i]
= weight( fdm1.oil_temp[i], fdm2.oil_temp[i], ratio );
result.fdm.oil_px[i] = weight( fdm1.oil_px[i], fdm2.oil_px[i], ratio );
if (recycler.size())
{
r = recycler.front();
recycler.pop_front();
}
// Consumables
for ( i = 0; i < fdm1.num_tanks; ++i ) {
result.fdm.fuel_quantity[i]
= weight( fdm1.fuel_quantity[i], fdm2.fuel_quantity[i], ratio );
}
r = m_pRecorder->capture(time, r);
// Gear status
for ( i = 0; i < fdm1.num_wheels; ++i ) {
result.fdm.wow[i] = (int)(weight( fdm1.wow[i], fdm2.wow[i], ratio ));
result.fdm.gear_pos[i]
= weight( fdm1.gear_pos[i], fdm2.gear_pos[i], ratio );
result.fdm.gear_steer[i]
= weight( fdm1.gear_steer[i], fdm2.gear_steer[i], ratio );
result.fdm.gear_compression[i]
= weight( fdm1.gear_compression[i], fdm2.gear_compression[i],
ratio );
}
// Environment
result.fdm.cur_time = fdm1.cur_time;
result.fdm.warp = fdm1.warp;
result.fdm.visibility = weight( fdm1.visibility, fdm2.visibility, ratio );
// Control surface positions (normalized values)
result.fdm.elevator = weight( fdm1.elevator, fdm2.elevator, ratio );
result.fdm.left_flap = weight( fdm1.left_flap, fdm2.left_flap, ratio );
result.fdm.right_flap = weight( fdm1.right_flap, fdm2.right_flap, ratio );
result.fdm.left_aileron
= weight( fdm1.left_aileron, fdm2.left_aileron, ratio );
result.fdm.right_aileron
= weight( fdm1.right_aileron, fdm2.right_aileron, ratio );
result.fdm.rudder = weight( fdm1.rudder, fdm2.rudder, ratio );
result.fdm.speedbrake = weight( fdm1.speedbrake, fdm2.speedbrake, ratio );
result.fdm.spoilers = weight( fdm1.spoilers, fdm2.spoilers, ratio );
// Interpolate Control input data
// Aero controls
result.ctrls.aileron = weight( ctrls1.aileron, ctrls2.aileron, ratio );
result.ctrls.elevator = weight( ctrls1.elevator, ctrls2.elevator, ratio );
result.ctrls.rudder = weight( ctrls1.rudder, ctrls2.rudder, ratio );
result.ctrls.aileron_trim
= weight( ctrls1.aileron_trim, ctrls2.aileron_trim, ratio );
result.ctrls.elevator_trim
= weight( ctrls1.elevator_trim, ctrls2.elevator_trim, ratio );
result.ctrls.rudder_trim
= weight( ctrls1.rudder_trim, ctrls2.rudder_trim, ratio );
result.ctrls.flaps = weight( ctrls1.flaps, ctrls2.flaps, ratio );
result.ctrls.flaps_power = ctrls1.flaps_power;
result.ctrls.flap_motor_ok = ctrls1.flap_motor_ok;
// Engine controls
for ( i = 0; i < ctrls1.num_engines; ++i ) {
result.ctrls.master_bat[i] = ctrls1.master_bat[i];
result.ctrls.master_alt[i] = ctrls1.master_alt[i];
result.ctrls.magnetos[i] = ctrls1.magnetos[i];
result.ctrls.starter_power[i] = ctrls1.starter_power[i];
result.ctrls.throttle[i]
= weight( ctrls1.throttle[i], ctrls2.throttle[i], ratio );
result.ctrls.mixture[i]
= weight( ctrls1.mixture[i], ctrls2.mixture[i], ratio );
result.ctrls.fuel_pump_power[i] = ctrls1.fuel_pump_power[i];
result.ctrls.prop_advance[i]
= weight( ctrls1.prop_advance[i], ctrls2.prop_advance[i], ratio );
result.ctrls.engine_ok[i] = ctrls1.engine_ok[i];
result.ctrls.mag_left_ok[i] = ctrls1.mag_left_ok[i];
result.ctrls.mag_right_ok[i] = ctrls1.mag_right_ok[i];
result.ctrls.spark_plugs_ok[i] = ctrls1.spark_plugs_ok[i];
result.ctrls.oil_press_status[i] = ctrls1.oil_press_status[i];
result.ctrls.fuel_pump_ok[i] = ctrls1.fuel_pump_ok[i];
}
// Fuel management
for ( i = 0; i < ctrls1.num_tanks; ++i ) {
result.ctrls.fuel_selector[i] = ctrls1.fuel_selector[i];
}
// Brake controls
result.ctrls.brake_left
= weight( ctrls1.brake_left, ctrls2.brake_left, ratio );
result.ctrls.brake_right
= weight( ctrls1.brake_right, ctrls2.brake_right, ratio );
result.ctrls.brake_parking
= weight( ctrls1.brake_parking, ctrls2.brake_parking, ratio );
// Landing Gear
result.ctrls.gear_handle = ctrls1.gear_handle;
// Switches
result.ctrls.turbulence_norm = ctrls1.turbulence_norm;
// wind and turbulance
result.ctrls.wind_speed_kt
= weight( ctrls1.wind_speed_kt, ctrls2.wind_speed_kt, ratio );
result.ctrls.wind_dir_deg
= weight( ctrls1.wind_dir_deg, ctrls2.wind_dir_deg, ratio );
result.ctrls.turbulence_norm
= weight( ctrls1.turbulence_norm, ctrls2.turbulence_norm, ratio );
// other information about environment
result.ctrls.hground = weight( ctrls1.hground, ctrls2.hground, ratio );
result.ctrls.magvar = weight( ctrls1.magvar, ctrls2.magvar, ratio );
// simulation control
result.ctrls.speedup = ctrls1.speedup;
result.ctrls.freeze = ctrls1.freeze;
return result;
return r;
}
/**
* interpolate a specific time from a specific list
*/
static void interpolate( double time, const replay_list_type &list ) {
void
FGReplay::interpolate( double time, const replay_list_type &list)
{
// sanity checking
if ( list.size() == 0 ) {
if ( list.size() == 0 )
{
// handle empty list
return;
} else if ( list.size() == 1 ) {
} else if ( list.size() == 1 )
{
// handle list size == 1
update_fdm( (*list[0]) );
replay(time, list[0]);
return;
}
@ -549,9 +442,9 @@ static void interpolate( double time, const replay_list_type &list ) {
unsigned int first = 0;
unsigned int mid = ( last + first ) / 2;
bool done = false;
while ( !done ) {
while ( !done )
{
// cout << " " << first << " <=> " << last << endl;
if ( last == first ) {
done = true;
@ -568,19 +461,17 @@ static void interpolate( double time, const replay_list_type &list ) {
}
}
FGReplayData result = interpolate( time, (*list[mid]), (*list[mid+1]) );
update_fdm( result );
replay(time, list[mid+1], list[mid]);
}
/**
* Replay a saved frame based on time, interpolate from the two
* nearest saved frames.
* Returns true when replay sequence has finished, false otherwise.
*/
bool FGReplay::replay( double time ) {
bool
FGReplay::replay( double time ) {
// cout << "replay: " << time << " ";
// find the two frames to interpolate between
double t1, t2;
@ -590,7 +481,7 @@ bool FGReplay::replay( double time ) {
t2 = short_term.front()->sim_time;
if ( time > t1 ) {
// replay the most recent frame
update_fdm( (*short_term.back()) );
replay( time, short_term.back() );
// replay is finished now
return true;
// cout << "first frame" << endl;
@ -600,11 +491,9 @@ bool FGReplay::replay( double time ) {
} else if ( medium_term.size() > 0 ) {
t1 = short_term.front()->sim_time;
t2 = medium_term.back()->sim_time;
if ( time <= t1 && time >= t2 ) {
FGReplayData result = interpolate( time,
(*medium_term.back()),
(*short_term.front()) );
update_fdm( result );
if ( time <= t1 && time >= t2 )
{
replay(time, medium_term.back(), short_term.front());
// cout << "from short/medium term" << endl;
} else {
t1 = medium_term.back()->sim_time;
@ -615,11 +504,9 @@ bool FGReplay::replay( double time ) {
} else if ( long_term.size() > 0 ) {
t1 = medium_term.front()->sim_time;
t2 = long_term.back()->sim_time;
if ( time <= t1 && time >= t2 ) {
FGReplayData result = interpolate( time,
(*long_term.back()),
(*medium_term.front()));
update_fdm( result );
if ( time <= t1 && time >= t2 )
{
replay(time, long_term.back(), medium_term.front());
// cout << "from medium/long term" << endl;
} else {
t1 = long_term.back()->sim_time;
@ -629,19 +516,19 @@ bool FGReplay::replay( double time ) {
// cout << "from long term" << endl;
} else {
// replay the oldest long term frame
update_fdm( (*long_term.front()) );
replay(time, long_term.front());
// cout << "oldest long term frame" << endl;
}
}
} else {
// replay the oldest medium term frame
update_fdm( (*medium_term.front()) );
replay(time, medium_term.front());
// cout << "oldest medium term frame" << endl;
}
}
} else {
// replay the oldest short term frame
update_fdm( (*short_term.front()) );
replay(time, short_term.front());
// cout << "oldest short term frame" << endl;
}
} else {
@ -651,23 +538,41 @@ bool FGReplay::replay( double time ) {
return false;
}
/**
* given two FGReplayData elements and a time, interpolate between them
*/
void
FGReplay::replay(double time, FGReplayData* pCurrentFrame, FGReplayData* pOldFrame)
{
m_pRecorder->replay(time,pCurrentFrame,pOldFrame);
}
double FGReplay::get_start_time() {
if ( long_term.size() > 0 ) {
return (*long_term.front()).sim_time;
} else if ( medium_term.size() > 0 ) {
return (*medium_term.front()).sim_time;
} else if ( short_term.size() ) {
return (*short_term.front()).sim_time;
} else {
double
FGReplay::get_start_time()
{
if ( long_term.size() > 0 )
{
return long_term.front()->sim_time;
} else if ( medium_term.size() > 0 )
{
return medium_term.front()->sim_time;
} else if ( short_term.size() )
{
return short_term.front()->sim_time;
} else
{
return 0.0;
}
}
double FGReplay::get_end_time() {
if ( short_term.size() ) {
return (*short_term.back()).sim_time;
} else {
double
FGReplay::get_end_time()
{
if ( short_term.size() )
{
return short_term.back()->sim_time;
} else
{
return 0.0;
}
}

View file

@ -1,6 +1,6 @@
// replay.hxx - a system to record and replay FlightGear flights
//
// Written by Curtis Olson, started Juley 2003.
// Written by Curtis Olson, started July 2003.
//
// Copyright (C) 2003 Curtis L. Olson - http://www.flightgear.org/~curt
//
@ -36,20 +36,15 @@
#include <simgear/props/props.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <Network/net_ctrls.hxx>
#include <Network/net_fdm.hxx>
using std::deque;
class FGFlightRecorder;
class FGReplayData {
public:
typedef struct {
double sim_time;
FGNetFDM fdm;
FGNetCtrls ctrls;
};
char raw_data;
/* more data here, hidden to the outside world */
} FGReplayData;
typedef deque < FGReplayData *> replay_list_type;
@ -73,21 +68,17 @@ public:
virtual void bind();
virtual void unbind();
virtual void update( double dt );
bool start();
private:
void clear();
FGReplayData* record(double time);
void interpolate(double time, const replay_list_type &list);
void replay(double time, FGReplayData* pCurrentFrame, FGReplayData* pOldFrame=NULL);
bool replay( double time );
double get_start_time();
double get_end_time();
private:
void clear();
static const double st_list_time; // 60 secs of high res data
static const double mt_list_time; // 10 mins of 1 fps data
static const double lt_list_time; // 1 hr of 10 spf data
// short term sample rate is as every frame
static const double mt_dt; // medium term sample rate (sec)
static const double lt_dt; // long term sample rate (sec)
double sim_time;
double last_mt_time;
@ -101,7 +92,18 @@ private:
SGPropertyNode_ptr disable_replay;
SGPropertyNode_ptr replay_master;
SGPropertyNode_ptr replay_time;
SGPropertyNode_ptr replay_time_str;
SGPropertyNode_ptr replay_looped;
SGPropertyNode_ptr speed_up;
double m_high_res_time; // default: 60 secs of high res data
double m_medium_res_time; // default: 10 mins of 1 fps data
double m_low_res_time; // default: 1 hr of 10 spf data
// short term sample rate is as every frame
double m_medium_sample_rate; // medium term sample rate (sec)
double m_long_sample_rate; // long term sample rate (sec)
FGFlightRecorder* m_pRecorder;
};

View file

@ -478,25 +478,30 @@ private:
int freqKhz = atoi(token[1].c_str());
int rangeNm = 50;
FGPositioned::Type ty;
switch (lineId) {
case 50:
ty = FGPositioned::FREQ_AWOS;
if (token[2] == "ATIS") {
ty = FGPositioned::FREQ_ATIS;
}
break;
case 51: ty = FGPositioned::FREQ_UNICOM; break;
case 52: ty = FGPositioned::FREQ_CLEARANCE; break;
case 53: ty = FGPositioned::FREQ_GROUND; break;
case 54: ty = FGPositioned::FREQ_TOWER; break;
case 55:
case 56: ty = FGPositioned::FREQ_APP_DEP; break;
default:
throw sg_range_exception("unupported apt.dat comm station type");
}
// Make sure we only pass on stations with at least a name
if (token.size() >2){
commStations.push_back(new flightgear::CommStation(token[2], ty, pos, rangeNm, freqKhz));
switch (lineId) {
case 50:
ty = FGPositioned::FREQ_AWOS;
if (token[2] == "ATIS") {
ty = FGPositioned::FREQ_ATIS;
}
break;
case 51: ty = FGPositioned::FREQ_UNICOM; break;
case 52: ty = FGPositioned::FREQ_CLEARANCE; break;
case 53: ty = FGPositioned::FREQ_GROUND; break;
case 54: ty = FGPositioned::FREQ_TOWER; break;
case 55:
case 56: ty = FGPositioned::FREQ_APP_DEP; break;
default:
throw sg_range_exception("unupported apt.dat comm station type");
}
commStations.push_back(new flightgear::CommStation(token[2], ty, pos, rangeNm, freqKhz));
}
else SG_LOG( SG_GENERAL, SG_DEBUG, "Found unnamed comm. Skipping: " << lineId);
}
};

View file

@ -35,93 +35,117 @@ class FGEnvironment;
class FGAirportDynamics {
private:
FGAirport* _ap;
FGAirport* _ap;
FGParkingVec parkings;
FGRunwayPreference rwyPrefs;
FGSidStar SIDs;
FGStartupController startupController;
FGGroundNetwork groundNetwork;
FGTowerController towerController;
FGApproachController approachController;
FGParkingVec parkings;
FGRunwayPreference rwyPrefs;
FGSidStar SIDs;
FGStartupController startupController;
FGGroundNetwork groundNetwork;
FGTowerController towerController;
FGApproachController approachController;
time_t lastUpdate;
std::string prevTrafficType;
stringVec landing;
stringVec takeoff;
stringVec milActive, comActive, genActive, ulActive;
stringVec *currentlyActive;
intVec freqAwos; // </AWOS>
intVec freqUnicom; // </UNICOM>
intVec freqClearance;// </CLEARANCE>
intVec freqGround; // </GROUND>
intVec freqTower; // </TOWER>
intVec freqApproach; // </APPROACH>
time_t lastUpdate;
std::string prevTrafficType;
stringVec landing;
stringVec takeoff;
stringVec milActive, comActive, genActive, ulActive;
stringVec *currentlyActive;
intVec freqAwos; // </AWOS>
intVec freqUnicom; // </UNICOM>
intVec freqClearance;// </CLEARANCE>
intVec freqGround; // </GROUND>
intVec freqTower; // </TOWER>
intVec freqApproach; // </APPROACH>
int atisSequenceIndex;
double atisSequenceTimeStamp;
std::string chooseRunwayFallback();
bool innerGetActiveRunway(const std::string &trafficType, int action, std::string &runway, double heading);
std::string chooseRwyByHeading(stringVec rwys, double heading);
int atisSequenceIndex;
double atisSequenceTimeStamp;
double elevation;
std::string chooseRunwayFallback();
bool innerGetActiveRunway(const std::string &trafficType, int action, std::string &runway, double heading);
std::string chooseRwyByHeading(stringVec rwys, double heading);
double elevation;
public:
FGAirportDynamics(FGAirport* ap);
~FGAirportDynamics();
FGAirportDynamics(FGAirport* ap);
~FGAirportDynamics();
void addAwosFreq (int val) { freqAwos.push_back(val); };
void addUnicomFreq (int val) { freqUnicom.push_back(val); };
void addClearanceFreq(int val) { freqClearance.push_back(val); };
void addGroundFreq (int val) { freqGround.push_back(val); };
void addTowerFreq (int val) { freqTower.push_back(val); };
void addApproachFreq (int val) { freqApproach.push_back(val); };
void addAwosFreq (int val) {
freqAwos.push_back(val);
};
void addUnicomFreq (int val) {
freqUnicom.push_back(val);
};
void addClearanceFreq(int val) {
freqClearance.push_back(val);
};
void addGroundFreq (int val) {
freqGround.push_back(val);
};
void addTowerFreq (int val) {
freqTower.push_back(val);
};
void addApproachFreq (int val) {
freqApproach.push_back(val);
};
void init();
double getLongitude() const;
// Returns degrees
double getLatitude() const;
// Returns ft
double getElevation() const;
const string& getId() const;
void getActiveRunway(const string& trafficType, int action, string& runway, double heading);
void init();
double getLongitude() const;
// Returns degrees
double getLatitude() const;
// Returns ft
double getElevation() const;
const string& getId() const;
void addParking(FGParking& park);
bool getAvailableParking(double *lat, double *lon,
double *heading, int *gate, double rad, const string& fltype,
const string& acType, const string& airline);
void getParking (int id, double *lat, double* lon, double *heading);
FGParking *getParking(int i);
void releaseParking(int id);
string getParkingName(int i);
int getNrOfParkings() { return parkings.size(); };
//FGAirport *getAddress() { return this; };
//const string &getName() const { return _name;};
// Returns degrees
void getActiveRunway(const string& trafficType, int action, string& runway, double heading);
// Departure / Arrival procedures
FGSidStar * getSIDs() { return &SIDs; };
FGAIFlightPlan * getSID(string activeRunway, double heading);
void addParking(FGParking& park);
bool getAvailableParking(double *lat, double *lon,
double *heading, int *gate, double rad, const string& fltype,
const string& acType, const string& airline);
void getParking (int id, double *lat, double* lon, double *heading);
FGParking *getParking(int i);
void releaseParking(int id);
string getParkingName(int i);
int getNrOfParkings() {
return parkings.size();
};
//FGAirport *getAddress() { return this; };
//const string &getName() const { return _name;};
// Returns degrees
// Departure / Arrival procedures
FGSidStar * getSIDs() {
return &SIDs;
};
FGAIFlightPlan * getSID(string activeRunway, double heading);
// ATC related functions.
FGStartupController *getStartupController() { return &startupController; };
FGGroundNetwork *getGroundNetwork() { return &groundNetwork; };
FGTowerController *getTowerController() { return &towerController; };
FGApproachController *getApproachController() { return &approachController; };
// ATC related functions.
FGStartupController *getStartupController() {
return &startupController;
};
FGGroundNetwork *getGroundNetwork() {
return &groundNetwork;
};
FGTowerController *getTowerController() {
return &towerController;
};
FGApproachController *getApproachController() {
return &approachController;
};
int getGroundFrequency(unsigned leg);
int getTowerFrequency (unsigned nr);
/// get current ATIS sequence letter
const std::string getAtisSequence();
int getGroundFrequency(unsigned leg);
int getTowerFrequency (unsigned nr);
/// get the current ATIS sequence number, updating it if necessary
int updateAtisSequence(int interval, bool forceUpdate);
/// get current ATIS sequence letter
const std::string getAtisSequence();
void setRwyUse(const FGRunwayPreference& ref);
/// get the current ATIS sequence number, updating it if necessary
int updateAtisSequence(int interval, bool forceUpdate);
void setRwyUse(const FGRunwayPreference& ref);
};

View file

@ -88,7 +88,7 @@ void FGTaxiSegment::setEnd(FGTaxiNodeVector * nodes)
// There is probably a computationally cheaper way of
// There is probably a computationally cheaper way of
// doing this.
void FGTaxiSegment::setDimensions(double elevation)
{
@ -164,9 +164,9 @@ bool FGTaxiRoute::next(int *nde, int *rte)
} else {
// If currNode points to the first node, this means the aircraft is not on the taxi node
// yet. Make sure to return a unique identifyer in this situation though, because otherwise
// the speed adjust AI code may be unable to resolve whether two aircraft are on the same
// taxi route or not. the negative of the preceding route seems a logical choice, as it is
// unique for any starting location.
// the speed adjust AI code may be unable to resolve whether two aircraft are on the same
// taxi route or not. the negative of the preceding route seems a logical choice, as it is
// unique for any starting location.
// Note that this is probably just a temporary fix until I get Parking / tower control working.
*rte = -1 * *(currRoute);
}
@ -205,6 +205,11 @@ bool compare_segments(FGTaxiSegment * a, FGTaxiSegment * b)
return (*a) < (*b);
}
bool compare_trafficrecords(FGTrafficRecord a, FGTrafficRecord b)
{
return (a.getIntentions().size() < b.getIntentions().size());
}
FGGroundNetwork::FGGroundNetwork()
{
hasNetwork = false;
@ -244,18 +249,18 @@ FGGroundNetwork::~FGGroundNetwork()
}
cachefile << "[GroundNetcachedata:ref:2011:09:04]" << endl;
for (FGTaxiNodeVectorIterator node = nodes.begin();
node != nodes.end(); node++) {
if (saveData) {
node != nodes.end(); node++) {
if (saveData) {
cachefile << (*node)->getIndex () << " "
<< (*node)->getElevation () << " "
<< endl;
}
<< (*node)->getElevation () << " "
<< endl;
}
delete(*node);
}
nodes.clear();
pushBackNodes.clear();
for (FGTaxiSegmentVectorIterator seg = segments.begin();
seg != segments.end(); seg++) {
seg != segments.end(); seg++) {
delete(*seg);
}
segments.clear();
@ -288,12 +293,12 @@ void FGGroundNetwork::saveElevationCache() {
}
cachefile << "[GroundNetcachedata:ref:2011:09:04]" << endl;
for (FGTaxiNodeVectorIterator node = nodes.begin();
node != nodes.end(); node++) {
if (saveData) {
node != nodes.end(); node++) {
if (saveData) {
cachefile << (*node)->getIndex () << " "
<< (*node)->getElevation () << " "
<< endl;
}
<< (*node)->getElevation () << " "
<< endl;
}
}
if (saveData) {
cachefile.close();
@ -405,12 +410,12 @@ void FGGroundNetwork::init()
string revisionStr;
data >> revisionStr;
if (revisionStr != "[GroundNetcachedata:ref:2011:09:04]") {
SG_LOG(SG_GENERAL, SG_ALERT,"GroundNetwork Warning: discarding outdated cachefile " <<
cacheData.c_str() << " for Airport " << airport);
SG_LOG(SG_GENERAL, SG_ALERT,"GroundNetwork Warning: discarding outdated cachefile " <<
cacheData.c_str() << " for Airport " << airport);
} else {
for (FGTaxiNodeVectorIterator i = nodes.begin();
i != nodes.end();
i++) {
i != nodes.end();
i++) {
(*i)->setElevation(parent->getElevation() * SG_FEET_TO_METER);
data >> index >> elev;
if (data.eof())
@ -435,7 +440,7 @@ int FGGroundNetwork::findNearestNode(const SGGeod & aGeod)
int index = -1;
for (FGTaxiNodeVectorIterator itr = nodes.begin(); itr != nodes.end();
itr++) {
itr++) {
double d = SGGeodesy::distanceM(aGeod, (*itr)->getGeod());
if (d < minDist) {
minDist = d;
@ -454,7 +459,7 @@ int FGGroundNetwork::findNearestNode(double lat, double lon)
FGTaxiNode *FGGroundNetwork::findNode(unsigned idx)
{ /*
for (FGTaxiNodeVectorIterator
for (FGTaxiNodeVectorIterator
itr = nodes.begin();
itr != nodes.end(); itr++)
{
@ -470,13 +475,13 @@ FGTaxiNode *FGGroundNetwork::findNode(unsigned idx)
FGTaxiSegment *FGGroundNetwork::findSegment(unsigned idx)
{ /*
for (FGTaxiSegmentVectorIterator
for (FGTaxiSegmentVectorIterator
itr = segments.begin();
itr != segments.end(); itr++)
{
if (itr->getIndex() == idx)
return itr->getAddress();
}
}
*/
if ((idx > 0) && (idx <= segments.size()))
return segments[idx - 1]->getAddress();
@ -488,7 +493,7 @@ FGTaxiSegment *FGGroundNetwork::findSegment(unsigned idx)
FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
bool fullSearch)
bool fullSearch)
{
//implements Dijkstra's algorithm to find shortest distance route from start to end
//taken from http://en.wikipedia.org/wiki/Dijkstra's_algorithm
@ -504,7 +509,7 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
}
for (FGTaxiNodeVectorIterator
itr = currNodesSet->begin(); itr != currNodesSet->end(); itr++) {
itr = currNodesSet->begin(); itr != currNodesSet->end(); itr++) {
(*itr)->setPathScore(HUGE_VAL); //infinity by all practical means
(*itr)->setPreviousNode(0); //
(*itr)->setPreviousSeg(0); //
@ -520,7 +525,7 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
while (!unvisited.empty()) {
FGTaxiNode *best = *(unvisited.begin());
for (FGTaxiNodeVectorIterator
itr = unvisited.begin(); itr != unvisited.end(); itr++) {
itr = unvisited.begin(); itr != unvisited.end(); itr++) {
if ((*itr)->getPathScore() < best->getPathScore())
best = (*itr);
}
@ -533,8 +538,8 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
break;
} else {
for (FGTaxiSegmentVectorIterator
seg = best->getBeginRoute();
seg != best->getEndRoute(); seg++) {
seg = best->getBeginRoute();
seg != best->getEndRoute(); seg++) {
if (fullSearch || (*seg)->isPushBack()) {
FGTaxiNode *tgt = (*seg)->getEnd();
double alt =
@ -623,7 +628,8 @@ void FGGroundNetwork::announcePosition(int id,
rec.setPositionAndHeading(lat, lon, heading, speed, alt);
rec.setRadius(radius); // only need to do this when creating the record.
rec.setAircraft(aircraft);
activeTraffic.push_back(rec);
activeTraffic.push_front(rec);
} else {
i->setPositionAndIntentions(currentPosition, intendedRoute);
i->setPositionAndHeading(lat, lon, heading, speed, alt);
@ -666,7 +672,7 @@ void FGGroundNetwork::signOff(int id)
* 9 = Acknowledge switch tower frequency
*************************************************************************************************************************/
bool FGGroundNetwork::checkTransmissionState(int minState, int maxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId,
AtcMsgDir msgDir)
AtcMsgDir msgDir)
{
int state = i->getState();
if ((state >= minState) && (state <= maxState) && available) {
@ -676,10 +682,10 @@ bool FGGroundNetwork::checkTransmissionState(int minState, int maxState, Traffic
int n = trans_num->getIntValue();
if (n == 0) {
trans_num->setIntValue(-1);
// PopupCallback(n);
//cerr << "Selected transmission message " << n << endl;
FGATCManager *atc = (FGATCManager*) globals->get_subsystem("atc");
atc->getATCDialog()->removeEntry(1);
// PopupCallback(n);
//cerr << "Selected transmission message " << n << endl;
FGATCManager *atc = (FGATCManager*) globals->get_subsystem("atc");
FGATCDialogNew::instance()->removeEntry(1);
} else {
//cerr << "creating message for " << i->getAircraft()->getCallSign() << endl;
transmit(&(*i), &(*parent->getDynamics()), msgId, msgDir, false);
@ -696,18 +702,18 @@ bool FGGroundNetwork::checkTransmissionState(int minState, int maxState, Traffic
}
void FGGroundNetwork::updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt,
double dt)
double heading, double speed, double alt,
double dt)
{
time_t currentTime = time(NULL);
if (nextSave < currentTime) {
saveElevationCache();
nextSave = currentTime + 100 + rand() % 200;
}
// Check whether aircraft are on hold due to a preceding pushback. If so, make sure to
// Check whether aircraft are on hold due to a preceding pushback. If so, make sure to
// Transmit air-to-ground "Ready to taxi request:
// Transmit ground to air approval / hold
// Transmit confirmation ...
// Transmit confirmation ...
// Probably use a status mechanism similar to the Engine start procedure in the startup controller.
@ -747,9 +753,9 @@ void FGGroundNetwork::updateAircraftInformation(int id, double lat, double lon,
bool needsTaxiClearance = current->getAircraft()->getTaxiClearanceRequest();
if (!needsTaxiClearance) {
checkHoldPosition(id, lat, lon, heading, speed, alt);
if (checkForCircularWaits(id)) {
i->setResolveCircularWait();
}
//if (checkForCircularWaits(id)) {
// i->setResolveCircularWait();
//}
} else {
current->setHoldPosition(true);
int state = current->getState();
@ -783,7 +789,7 @@ void FGGroundNetwork::updateAircraftInformation(int id, double lat, double lon,
aircraft. For traffic that is on other routes we need to issue a "HOLD Position"
instruction. See below for the hold position instruction.
Note that there currently still is one flaw in the logic that needs to be addressed.
Note that there currently still is one flaw in the logic that needs to be addressed.
There can be situations where one aircraft is in front of the current aircraft, on a separate
route, but really close after an intersection coming off the current route. This
aircraft is still close enough to block the current aircraft. This situation is currently
@ -791,11 +797,11 @@ void FGGroundNetwork::updateAircraftInformation(int id, double lat, double lon,
*/
void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
double lon, double heading,
double speed, double alt)
double lon, double heading,
double speed, double alt)
{
TrafficVectorIterator current, closest;
TrafficVectorIterator current, closest, closestOnNetwork;
TrafficVectorIterator i = activeTraffic.begin();
bool otherReasonToSlowDown = false;
bool previousInstruction;
@ -825,7 +831,7 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
//TrafficVector iterator closest;
closest = current;
for (TrafficVectorIterator i = activeTraffic.begin();
i != activeTraffic.end(); i++) {
i != activeTraffic.end(); i++) {
if (i == current) {
continue;
}
@ -840,14 +846,16 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
if ((dist < mindist) && (bearing < 60.0)) {
mindist = dist;
closest = i;
closestOnNetwork = i;
minbearing = bearing;
}
}
//Check traffic at the tower controller
if (towerController->hasActiveTraffic()) {
for (TrafficVectorIterator i =
towerController->getActiveTraffic().begin();
i != towerController->getActiveTraffic().end(); i++) {
towerController->getActiveTraffic().begin();
i != towerController->getActiveTraffic().end(); i++) {
//cerr << "Comparing " << current->getId() << " and " << i->getId() << endl;
SGGeod other(SGGeod::fromDegM(i->getLongitude(),
i->getLatitude(),
@ -858,8 +866,8 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
bearing = 360 - bearing;
if ((dist < mindist) && (bearing < 60.0)) {
//cerr << "Current aircraft " << current->getAircraft()->getTrafficRef()->getCallSign()
// << " is closest to " << i->getAircraft()->getTrafficRef()->getCallSign()
// << ", which has status " << i->getAircraft()->isScheduledForTakeoff()
// << " is closest to " << i->getAircraft()->getTrafficRef()->getCallSign()
// << ", which has status " << i->getAircraft()->isScheduledForTakeoff()
// << endl;
mindist = dist;
closest = i;
@ -887,9 +895,9 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
}
*/
current->clearSpeedAdjustment();
bool needBraking = false;
if (current->checkPositionAndIntentions(*closest)
|| otherReasonToSlowDown) {
|| otherReasonToSlowDown) {
double maxAllowableDistance =
(1.1 * current->getRadius()) +
(1.1 * closest->getRadius());
@ -901,12 +909,13 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
if (closest->getId() != current->getId()) {
current->setSpeedAdjustment(closest->getSpeed() *
(mindist / 100));
if (
closest->getAircraft()->getTakeOffStatus() &&
needBraking = true;
if (
closest->getAircraft()->getTakeOffStatus() &&
(current->getAircraft()->getTrafficRef()->getDepartureAirport() == closest->getAircraft()->getTrafficRef()->getDepartureAirport()) &&
(current->getAircraft()->GetFlightPlan()->getRunway() == closest->getAircraft()->GetFlightPlan()->getRunway())
)
current->getAircraft()->scheduleForATCTowerDepartureControl(1);
)
current->getAircraft()->scheduleForATCTowerDepartureControl(1);
} else {
current->setSpeedAdjustment(0); // This can only happen when the user aircraft is the one closest
}
@ -920,6 +929,9 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
}
}
}
if ((closest == closestOnNetwork) && (current->getPriority() < closest->getPriority()) && needBraking) {
swap(current, closest);
}
}
}
@ -938,7 +950,7 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat,
TrafficVectorIterator current;
TrafficVectorIterator i = activeTraffic.begin();
if (activeTraffic.size()) {
//while ((i->getId() != id) && i != activeTraffic.end())
//while ((i->getId() != id) && i != activeTraffic.end())
while (i != activeTraffic.end()) {
if (i->getId() == id) {
break;
@ -956,80 +968,100 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat,
bool origStatus = current->hasHoldPosition();
current->setHoldPosition(false);
SGGeod curr(SGGeod::fromDegM(lon, lat, alt));
int currentRoute = i->getCurrentPosition();
int nextRoute;
if (i->getIntentions().size()) {
nextRoute = (*(i->getIntentions().begin()));
} else {
nextRoute = 0;
}
if (currentRoute > 0) {
FGTaxiSegment *tx = findSegment(currentRoute);
FGTaxiSegment *nx;
if (nextRoute) {
nx = findSegment(nextRoute);
} else {
nx = tx;
}
if (tx->hasBlock() || nx->hasBlock() ) {
current->setHoldPosition(true);
}
}
for (i = activeTraffic.begin(); i != activeTraffic.end(); i++) {
if (i->getId() != current->getId()) {
int node = current->crosses(this, *i);
if (node != -1) {
FGTaxiNode *taxiNode = findNode(node);
// Determine whether it's save to continue or not.
// If we have a crossing route, there are two possibilities:
// 1) This is an interestion
// 2) This is oncoming two-way traffic, using the same taxiway.
//cerr << "Hold check 1 : " << id << " has common node " << node << endl;
/* for (i = activeTraffic.begin(); i != activeTraffic.end(); i++) {
if (i->getId() != current->getId()) {
int node = current->crosses(this, *i);
if (node != -1) {
FGTaxiNode *taxiNode = findNode(node);
SGGeod other(SGGeod::
fromDegM(i->getLongitude(), i->getLatitude(),
i->getAltitude()));
bool needsToWait;
bool opposing;
if (current->isOpposing(this, *i, node)) {
needsToWait = true;
opposing = true;
//cerr << "Hold check 2 : " << node << " has opposing segment " << endl;
// issue a "Hold Position" as soon as we're close to the offending node
// For now, I'm doing this as long as the other aircraft doesn't
// have a hold instruction as soon as we're within a reasonable
// distance from the offending node.
// This may be a bit of a conservative estimate though, as it may
// be well possible that both aircraft can both continue to taxi
// without crashing into each other.
} else {
opposing = false;
if (SGGeodesy::distanceM(other, taxiNode->getGeod()) > 200) // 2.0*i->getRadius())
{
needsToWait = false;
//cerr << "Hold check 3 : " << id <<" Other aircraft approaching node is still far away. (" << dist << " nm). Can safely continue "
// << endl;
} else {
// Determine whether it's save to continue or not.
// If we have a crossing route, there are two possibilities:
// 1) This is an interestion
// 2) This is oncoming two-way traffic, using the same taxiway.
//cerr << "Hold check 1 : " << id << " has common node " << node << endl;
SGGeod other(SGGeod::
fromDegM(i->getLongitude(), i->getLatitude(),
i->getAltitude()));
bool needsToWait;
bool opposing;
if (current->isOpposing(this, *i, node)) {
needsToWait = true;
//cerr << "Hold check 4: " << id << " Would need to wait for other aircraft : distance = " << dist << " meters" << endl;
}
}
double dist =
SGGeodesy::distanceM(curr, taxiNode->getGeod());
if (!(i->hasHoldPosition())) {
if ((dist < 200) && //2.5*current->getRadius()) &&
(needsToWait) && (i->onRoute(this, *current)) &&
//((i->onRoute(this, *current)) || ((!(i->getSpeedAdjustment())))) &&
(!(current->getId() == i->getWaitsForId())))
//(!(i->getSpeedAdjustment()))) // &&
//(!(current->getSpeedAdjustment())))
{
if (!(isUserAircraft(i->getAircraft()))) { // test code. Don't wait for the user, let the user wait for you.
current->setHoldPosition(true);
current->setWaitsForId(i->getId());
}
//cerr << "Hold check 5: " << current->getCallSign() <<" Setting Hold Position: distance to node (" << node << ") "
// << dist << " meters. Waiting for " << i->getCallSign();
//if (opposing)
//cerr <<" [opposing] " << endl;
//else
// cerr << "[non-opposing] " << endl;
//if (i->hasSpeefAdjustment())
// {
// cerr << " (which in turn waits for ) " << i->
opposing = true;
//cerr << "Hold check 2 : " << node << " has opposing segment " << endl;
// issue a "Hold Position" as soon as we're close to the offending node
// For now, I'm doing this as long as the other aircraft doesn't
// have a hold instruction as soon as we're within a reasonable
// distance from the offending node.
// This may be a bit of a conservative estimate though, as it may
// be well possible that both aircraft can both continue to taxi
// without crashing into each other.
} else {
//cerr << "Hold check 6: " << id << " No need to hold yet: Distance to node : " << dist << " nm"<< endl;
opposing = false;
if (SGGeodesy::distanceM(other, taxiNode->getGeod()) > 200) // 2.0*i->getRadius())
{
needsToWait = false;
//cerr << "Hold check 3 : " << id <<" Other aircraft approaching node is still far away. (" << dist << " nm). Can safely continue "
// << endl;
} else {
needsToWait = true;
//cerr << "Hold check 4: " << id << " Would need to wait for other aircraft : distance = " << dist << " meters" << endl;
}
}
double dist =
SGGeodesy::distanceM(curr, taxiNode->getGeod());
if (!(i->hasHoldPosition())) {
if ((dist < 200) && //2.5*current->getRadius()) &&
(needsToWait) && (i->onRoute(this, *current)) &&
//((i->onRoute(this, *current)) || ((!(i->getSpeedAdjustment())))) &&
(!(current->getId() == i->getWaitsForId())))
//(!(i->getSpeedAdjustment()))) // &&
//(!(current->getSpeedAdjustment())))
{
if (!(isUserAircraft(i->getAircraft()))) { // test code. Don't wait for the user, let the user wait for you.
current->setHoldPosition(true);
current->setWaitsForId(i->getId());
}
//cerr << "Hold check 5: " << current->getCallSign() <<" Setting Hold Position: distance to node (" << node << ") "
// << dist << " meters. Waiting for " << i->getCallSign();
//if (opposing)
//cerr <<" [opposing] " << endl;
//else
// cerr << "[non-opposing] " << endl;
//if (i->hasSpeefAdjustment())
// {
// cerr << " (which in turn waits for ) " << i->
} else {
//cerr << "Hold check 6: " << id << " No need to hold yet: Distance to node : " << dist << " nm"<< endl;
}
}
}
}
}
}
} */
bool currStatus = current->hasHoldPosition();
current->setHoldPosition(origStatus);
// Either a Hold Position or a resume taxi transmission has been issued
@ -1064,17 +1096,17 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat,
//int state = current->getState();
if (checkTransmissionState(1,1, current, now, MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND)) {
current->setState(0);
current->setHoldPosition(true);
current->setState(0);
current->setHoldPosition(true);
}
if (checkTransmissionState(2,2, current, now, MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND)) {
current->setState(0);
current->setHoldPosition(false);
current->setState(0);
current->setHoldPosition(false);
}
if (current->getAircraft()->getTakeOffStatus() && (current->getState() == 0)) {
//cerr << "Scheduling " << current->getAircraft()->getCallSign() << " for hold short" << endl;
current->setState(6);
}
//cerr << "Scheduling " << current->getAircraft()->getCallSign() << " for hold short" << endl;
current->setState(6);
}
if (checkTransmissionState(6,6, current, now, MSG_REPORT_RUNWAY_HOLD_SHORT, ATC_AIR_TO_GROUND)) {
}
if (checkTransmissionState(7,7, current, now, MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT, ATC_GROUND_TO_AIR)) {
@ -1086,15 +1118,15 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat,
//current->setState(0);
}
//current->setState(0);
}
/**
* Check whether situations occur where the current aircraft is waiting for itself
* due to higher order interactions.
* due to higher order interactions.
* A 'circular' wait is a situation where a waits for b, b waits for c, and c waits
* for a. Ideally each aircraft only waits for one other aircraft, so by tracing
* through this list of waiting aircraft, we can check if we'd eventually end back
* for a. Ideally each aircraft only waits for one other aircraft, so by tracing
* through this list of waiting aircraft, we can check if we'd eventually end back
* at the current aircraft.
*
* Note that we should consider the situation where we are actually checking aircraft
@ -1140,7 +1172,7 @@ bool FGGroundNetwork::checkForCircularWaits(int id)
//printed = true;
TrafficVectorIterator i = activeTraffic.begin();
if (trafficSize) {
//while ((i->getId() != id) && i != activeTraffic.end())
//while ((i->getId() != id) && i != activeTraffic.end())
while (i != activeTraffic.end()) {
if (i->getId() == target) {
break;
@ -1161,7 +1193,7 @@ bool FGGroundNetwork::checkForCircularWaits(int id)
// actually this trap isn't as impossible as it first seemed:
// the setWaitsForID(id) is set to current when the aircraft
// is waiting for the user controlled aircraft.
// is waiting for the user controlled aircraft.
//if (current->getId() == other->getId()) {
// cerr << "Caught the impossible trap" << endl;
// cerr << "Current = " << current->getId() << endl;
@ -1175,7 +1207,7 @@ bool FGGroundNetwork::checkForCircularWaits(int id)
if (current->getId() == other->getId())
return false;
//}
//cerr << current->getCallSign() << " (" << current->getId() << ") " << " -> " << other->getCallSign()
//cerr << current->getCallSign() << " (" << current->getId() << ") " << " -> " << other->getCallSign()
// << " (" << other->getId() << "); " << endl;;
//current = other;
}
@ -1271,10 +1303,10 @@ void FGGroundNetwork::render(bool visible)
//while (group->getNumChildren()) {
// cerr << "Number of children: " << group->getNumChildren() << endl;
//simgear::EffectGeode* geode = (simgear::EffectGeode*) group->getChild(0);
//osg::MatrixTransform *obj_trans = (osg::MatrixTransform*) group->getChild(0);
//geode->releaseGLObjects();
//group->removeChild(geode);
//delete geode;
//osg::MatrixTransform *obj_trans = (osg::MatrixTransform*) group->getChild(0);
//geode->releaseGLObjects();
//group->removeChild(geode);
//delete geode;
group = 0;
}
if (visible) {
@ -1288,7 +1320,7 @@ void FGGroundNetwork::render(bool visible)
// Handle start point
int pos = i->getCurrentPosition() - 1;
if (pos >= 0) {
SGGeod start(SGGeod::fromDeg((i->getLongitude()), (i->getLatitude())));
SGGeod end (SGGeod::fromDeg(segments[pos]->getEnd()->getLongitude(), segments[pos]->getEnd()->getLatitude()));
@ -1301,7 +1333,7 @@ void FGGroundNetwork::render(bool visible)
SGGeod center;
SGGeodesy::direct(start, heading, coveredDistance, center, az2);
//cerr << "Active Aircraft : Centerpoint = (" << center.getLatitudeDeg() << ", " << center.getLongitudeDeg() << "). Heading = " << heading << endl;
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Make a helper function out of this
osg::Matrix obj_pos;
osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
@ -1311,7 +1343,7 @@ void FGGroundNetwork::render(bool visible)
if (isUserAircraft((i)->getAircraft())) {
elevationStart = fgGetDouble("/position/ground-elev-m");
} else {
elevationStart = ((i)->getAircraft()->_getAltitude());
elevationStart = ((i)->getAircraft()->_getAltitude());
}
double elevationEnd = segments[pos]->getEnd()->getElevation();
//cerr << "Using elevation " << elevationEnd << endl;
@ -1321,19 +1353,19 @@ void FGGroundNetwork::render(bool visible)
center2.setElevationM(SG_MAX_ELEVATION_M);
if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) {
elevation_feet = elevationEnd * SG_METER_TO_FEET + 0.5;
//elevation_meters += 0.5;
//elevation_meters += 0.5;
}
else {
else {
elevationEnd = parent->getElevation();
}
segments[pos]->getEnd()->setElevation(elevationEnd);
}
double elevationMean = (elevationStart + elevationEnd) / 2.0;
double elevDiff = elevationEnd - elevationStart;
double slope = atan2(elevDiff, length) * SGD_RADIANS_TO_DEGREES;
//cerr << "1. Using mean elevation : " << elevationMean << " and " << slope << endl;
double slope = atan2(elevDiff, length) * SGD_RADIANS_TO_DEGREES;
//cerr << "1. Using mean elevation : " << elevationMean << " and " << slope << endl;
WorldCoordinate( obj_pos, center.getLatitudeDeg(), center.getLongitudeDeg(), elevationMean+ 0.5, -(heading), slope );
@ -1350,18 +1382,23 @@ void FGGroundNetwork::render(bool visible)
geode->setName("test");
geode->addDrawable(geometry);
//osg::Node *custom_obj;
SGMaterial *mat = matlib->find("UnidirectionalTaper");
SGMaterial *mat;
if (segments[pos]->hasBlock()) {
mat = matlib->find("UnidirectionalTaperRed");
} else {
mat = matlib->find("UnidirectionalTaperGreen");
}
if (mat)
geode->setEffect(mat->get_effect());
obj_trans->addChild(geode);
// wire as much of the scene graph together as we can
//->addChild( obj_trans );
group->addChild( obj_trans );
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
} else {
//cerr << "BIG FAT WARNING: current position is here : " << pos << endl;
}
for(intVecIterator j = (i)->getIntentions().begin(); j != (i)->getIntentions().end(); j++) {
for (intVecIterator j = (i)->getIntentions().begin(); j != (i)->getIntentions().end(); j++) {
osg::Matrix obj_pos;
int k = (*j)-1;
if (k >= 0) {
@ -1378,7 +1415,7 @@ void FGGroundNetwork::render(bool visible)
elevation_feet = elevationStart * SG_METER_TO_FEET + 0.5;
//elevation_meters += 0.5;
}
else {
else {
elevationStart = parent->getElevation();
}
segments[k]->getStart()->setElevation(elevationStart);
@ -1390,7 +1427,7 @@ void FGGroundNetwork::render(bool visible)
elevation_feet = elevationEnd * SG_METER_TO_FEET + 0.5;
//elevation_meters += 0.5;
}
else {
else {
elevationEnd = parent->getElevation();
}
segments[k]->getEnd()->setElevation(elevationEnd);
@ -1400,8 +1437,8 @@ void FGGroundNetwork::render(bool visible)
double elevDiff = elevationEnd - elevationStart;
double length = segments[k]->getLength();
double slope = atan2(elevDiff, length) * SGD_RADIANS_TO_DEGREES;
// cerr << "2. Using mean elevation : " << elevationMean << " and " << slope << endl;
// cerr << "2. Using mean elevation : " << elevationMean << " and " << slope << endl;
WorldCoordinate( obj_pos, segments[k]->getLatitude(), segments[k]->getLongitude(), elevationMean+ 0.5, -(segments[k]->getHeading()), slope );
@ -1419,7 +1456,12 @@ void FGGroundNetwork::render(bool visible)
geode->setName("test");
geode->addDrawable(geometry);
//osg::Node *custom_obj;
SGMaterial *mat = matlib->find("UnidirectionalTaper");
SGMaterial *mat;
if (segments[k]->hasBlock()) {
mat = matlib->find("UnidirectionalTaperRed");
} else {
mat = matlib->find("UnidirectionalTaperGreen");
}
if (mat)
geode->setEffect(mat->get_effect());
obj_trans->addChild(geode);
@ -1437,3 +1479,96 @@ void FGGroundNetwork::render(bool visible)
string FGGroundNetwork::getName() {
return string(parent->getId() + "-ground");
}
void FGGroundNetwork::update(double dt)
{
for (FGTaxiSegmentVectorIterator tsi = segments.begin(); tsi != segments.end(); tsi++) {
(*tsi)->unblock();
}
int priority = 1;
//sort(activeTraffic.begin(), activeTraffic.end(), compare_trafficrecords);
// Handle traffic that is under ground control first; this way we'll prevent clutter at the gate areas.
// Don't allow an aircraft to pushback when a taxiing aircraft is currently using part of the intended route.
for (TrafficVectorIterator i = parent->getDynamics()->getStartupController()->getActiveTraffic().begin();
i != parent->getDynamics()->getStartupController()->getActiveTraffic().end(); i++) {
i->allowPushBack();
i->setPriority(priority++);
if (i->isActive(60)) {
// Check for all active aircraft whether it's current pos segment is
// an opposite of one of the departing aircraft's intentions
for (TrafficVectorIterator j = activeTraffic.begin(); j != activeTraffic.end(); j++) {
int pos = j->getCurrentPosition();
if (pos > 0) {
FGTaxiSegment *seg = segments[pos-1]->opposite();
if (seg) {
int posReverse = seg->getIndex();
for (intVecIterator k = i->getIntentions().begin(); k != i->getIntentions().end(); k++) {
if ((*k) == posReverse) {
i->denyPushBack();
segments[posReverse-1]->block();
}
}
}
}
}
// if the current aircraft is still allowed to pushback, we can start reserving a route for if by blocking all the entry taxiways.
if (i->pushBackAllowed()) {
int pos = i->getCurrentPosition();
if (pos > 0) {
FGTaxiSegment *seg = segments[pos-1];
FGTaxiNode *node = seg->getEnd();
for (FGTaxiSegmentVectorIterator tsi = segments.begin(); tsi != segments.end(); tsi++) {
if (((*tsi)->getEnd() == node) && ((*tsi) != seg)) {
(*tsi)->block();
}
}
}
for (intVecIterator j = i->getIntentions().begin(); j != i->getIntentions().end(); j++) {
int pos = (*j);
if (pos > 0) {
FGTaxiSegment *seg = segments[pos-1];
FGTaxiNode *node = seg->getEnd();
for (FGTaxiSegmentVectorIterator tsi = segments.begin(); tsi != segments.end(); tsi++) {
if (((*tsi)->getEnd() == node) && ((*tsi) != seg)) {
(*tsi)->block();
}
}
}
}
}
}
}
for (TrafficVectorIterator i = activeTraffic.begin(); i != activeTraffic.end(); i++) {
i->setPriority(priority++);
int pos = i->getCurrentPosition();
if (pos > 0) {
if (segments[pos-1]->hasBlock()) {
SG_LOG(SG_GENERAL, SG_ALERT, "Taxiway incursion for AI aircraft" << i->getAircraft()->getCallSign());
}
}
intVecIterator ivi;
for (ivi = i->getIntentions().begin(); ivi != i->getIntentions().end(); ivi++) {
int segIndex = (*ivi);
if (segIndex > 0) {
if (segments[segIndex-1]->hasBlock())
break;
}
}
//after this, ivi points just behind the last valid unblocked taxi segment.
for (intVecIterator j = i->getIntentions().begin(); j != ivi; j++) {
int pos = (*j);
if (pos > 0) {
FGTaxiSegment *seg = segments[pos-1];
FGTaxiNode *node = seg->getEnd();
for (FGTaxiSegmentVectorIterator tsi = segments.begin(); tsi != segments.end(); tsi++) {
if (((*tsi)->getEnd() == node) && ((*tsi) != seg)) {
(*tsi)->block();
}
}
}
}
}
}

View file

@ -60,98 +60,143 @@ typedef vector<FGTaxiSegment*>::iterator FGTaxiSegmentVectorIterator;
class FGTaxiSegment
{
private:
int startNode;
int endNode;
double length;
double heading;
SGGeod center;
bool isActive;
bool isPushBackRoute;
FGTaxiNode *start;
FGTaxiNode *end;
int index;
FGTaxiSegment *oppositeDirection;
int startNode;
int endNode;
double length;
double heading;
SGGeod center;
bool isActive;
bool isPushBackRoute;
bool isBlocked;
FGTaxiNode *start;
FGTaxiNode *end;
int index;
FGTaxiSegment *oppositeDirection;
public:
FGTaxiSegment() :
startNode(0),
endNode(0),
length(0),
heading(0),
isActive(0),
isPushBackRoute(0),
start(0),
end(0),
index(0),
oppositeDirection(0)
{
};
FGTaxiSegment() :
startNode(0),
endNode(0),
length(0),
heading(0),
isActive(0),
isPushBackRoute(0),
isBlocked(0),
start(0),
end(0),
index(0),
oppositeDirection(0)
{
};
FGTaxiSegment (const FGTaxiSegment &other) :
startNode (other.startNode),
endNode (other.endNode),
length (other.length),
heading (other.heading),
center (other.center),
isActive (other.isActive),
isPushBackRoute (other.isPushBackRoute),
start (other.start),
end (other.end),
index (other.index),
oppositeDirection (other.oppositeDirection)
{
};
FGTaxiSegment (const FGTaxiSegment &other) :
startNode (other.startNode),
endNode (other.endNode),
length (other.length),
heading (other.heading),
center (other.center),
isActive (other.isActive),
isPushBackRoute (other.isPushBackRoute),
isBlocked (other.isBlocked),
start (other.start),
end (other.end),
index (other.index),
oppositeDirection (other.oppositeDirection)
{
};
FGTaxiSegment& operator=(const FGTaxiSegment &other)
{
startNode = other.startNode;
endNode = other.endNode;
length = other.length;
heading = other.heading;
center = other.center;
isActive = other.isActive;
isPushBackRoute = other.isPushBackRoute;
start = other.start;
end = other.end;
index = other.index;
oppositeDirection = other.oppositeDirection;
return *this;
};
FGTaxiSegment& operator=(const FGTaxiSegment &other)
{
startNode = other.startNode;
endNode = other.endNode;
length = other.length;
heading = other.heading;
center = other.center;
isActive = other.isActive;
isPushBackRoute = other.isPushBackRoute;
isBlocked = other.isBlocked;
start = other.start;
end = other.end;
index = other.index;
oppositeDirection = other.oppositeDirection;
return *this;
};
void setIndex (int val) { index = val; };
void setStartNodeRef (int val) { startNode = val; };
void setEndNodeRef (int val) { endNode = val; };
void setIndex (int val) {
index = val;
};
void setStartNodeRef (int val) {
startNode = val;
};
void setEndNodeRef (int val) {
endNode = val;
};
void setOpposite(FGTaxiSegment *opp) { oppositeDirection = opp; };
void setOpposite(FGTaxiSegment *opp) {
oppositeDirection = opp;
};
void setStart(FGTaxiNodeVector *nodes);
void setEnd (FGTaxiNodeVector *nodes);
void setPushBackType(bool val) { isPushBackRoute = val; };
void setDimensions(double elevation);
void setStart(FGTaxiNodeVector *nodes);
void setEnd (FGTaxiNodeVector *nodes);
void setPushBackType(bool val) {
isPushBackRoute = val;
};
void setDimensions(double elevation);
void block() {
isBlocked = true;
}
void unblock() {
isBlocked = false;
};
bool hasBlock() {
return isBlocked;
};
FGTaxiNode * getEnd() { return end;};
FGTaxiNode * getStart() { return start; };
double getLength() { return length; };
int getIndex() { return index; };
double getLatitude() { return center.getLatitudeDeg(); };
double getLongitude() { return center.getLongitudeDeg(); };
double getHeading() { return heading; };
bool isPushBack() { return isPushBackRoute; };
FGTaxiNode * getEnd() {
return end;
};
FGTaxiNode * getStart() {
return start;
};
double getLength() {
return length;
};
int getIndex() {
return index;
};
double getLatitude() {
return center.getLatitudeDeg();
};
double getLongitude() {
return center.getLongitudeDeg();
};
double getHeading() {
return heading;
};
bool isPushBack() {
return isPushBackRoute;
};
int getPenalty(int nGates);
int getPenalty(int nGates);
FGTaxiSegment *getAddress() { return this;};
FGTaxiSegment *getAddress() {
return this;
};
bool operator<(const FGTaxiSegment &other) const {
return index < other.index;
};
//bool hasSmallerHeadingDiff (const FGTaxiSegment &other) const { return headingDiff < other.headingDiff; };
FGTaxiSegment *opposite() {
return oppositeDirection;
};
void setCourseDiff(double crse);
bool operator<(const FGTaxiSegment &other) const { return index < other.index; };
//bool hasSmallerHeadingDiff (const FGTaxiSegment &other) const { return headingDiff < other.headingDiff; };
FGTaxiSegment *opposite() { return oppositeDirection; };
void setCourseDiff(double crse);
};
@ -168,52 +213,67 @@ typedef vector<int>::iterator intVecIterator;
class FGTaxiRoute
{
private:
intVec nodes;
intVec routes;
double distance;
intVec nodes;
intVec routes;
double distance;
// int depth;
intVecIterator currNode;
intVecIterator currRoute;
intVecIterator currNode;
intVecIterator currRoute;
public:
FGTaxiRoute() { distance = 0; currNode = nodes.begin(); currRoute = routes.begin();};
FGTaxiRoute(intVec nds, intVec rts, double dist, int dpth) {
nodes = nds;
routes = rts;
distance = dist;
currNode = nodes.begin();
currRoute = routes.begin();
FGTaxiRoute() {
distance = 0;
currNode = nodes.begin();
currRoute = routes.begin();
};
FGTaxiRoute(intVec nds, intVec rts, double dist, int dpth) {
nodes = nds;
routes = rts;
distance = dist;
currNode = nodes.begin();
currRoute = routes.begin();
// depth = dpth;
};
};
FGTaxiRoute& operator= (const FGTaxiRoute &other) {
nodes = other.nodes;
routes = other.routes;
distance = other.distance;
FGTaxiRoute& operator= (const FGTaxiRoute &other) {
nodes = other.nodes;
routes = other.routes;
distance = other.distance;
// depth = other.depth;
currNode = nodes.begin();
currRoute = routes.begin();
return *this;
};
currNode = nodes.begin();
currRoute = routes.begin();
return *this;
};
FGTaxiRoute(const FGTaxiRoute& copy) :
nodes(copy.nodes),
routes(copy.routes),
distance(copy.distance),
FGTaxiRoute(const FGTaxiRoute& copy) :
nodes(copy.nodes),
routes(copy.routes),
distance(copy.distance),
// depth(copy.depth),
currNode(nodes.begin()),
currRoute(routes.begin())
{};
currNode(nodes.begin()),
currRoute(routes.begin())
{};
bool operator< (const FGTaxiRoute &other) const {return distance < other.distance; };
bool empty () { return nodes.begin() == nodes.end(); };
bool next(int *nde);
bool next(int *nde, int *rte);
void rewind(int legNr);
void first() { currNode = nodes.begin(); currRoute = routes.begin(); };
int size() { return nodes.size(); };
int nodesLeft() { return nodes.end() - currNode; };
bool operator< (const FGTaxiRoute &other) const {
return distance < other.distance;
};
bool empty () {
return nodes.begin() == nodes.end();
};
bool next(int *nde);
bool next(int *nde, int *rte);
void rewind(int legNr);
void first() {
currNode = nodes.begin();
currRoute = routes.begin();
};
int size() {
return nodes.size();
};
int nodesLeft() {
return nodes.end() - currNode;
};
// int getDepth() { return depth; };
};
@ -227,75 +287,84 @@ typedef vector<FGTaxiRoute>::iterator TaxiRouteVectorIterator;
class FGGroundNetwork : public FGATCController
{
private:
bool hasNetwork;
bool networkInitialized;
time_t nextSave;
//int maxDepth;
int count;
FGTaxiNodeVector nodes;
FGTaxiNodeVector pushBackNodes;
FGTaxiSegmentVector segments;
//intVec route;
//intVec nodesStack;
//intVec routesStack;
TaxiRouteVector routes;
TrafficVector activeTraffic;
TrafficVectorIterator currTraffic;
bool hasNetwork;
bool networkInitialized;
time_t nextSave;
//int maxDepth;
int count;
FGTaxiNodeVector nodes;
FGTaxiNodeVector pushBackNodes;
FGTaxiSegmentVector segments;
//intVec route;
//intVec nodesStack;
//intVec routesStack;
TaxiRouteVector routes;
TrafficVector activeTraffic;
TrafficVectorIterator currTraffic;
bool foundRoute;
double totalDistance, maxDistance;
FGTowerController *towerController;
FGAirport *parent;
bool foundRoute;
double totalDistance, maxDistance;
FGTowerController *towerController;
FGAirport *parent;
//void printRoutingError(string);
//void printRoutingError(string);
void checkSpeedAdjustment(int id, double lat, double lon,
double heading, double speed, double alt);
void checkHoldPosition(int id, double lat, double lon,
double heading, double speed, double alt);
void checkSpeedAdjustment(int id, double lat, double lon,
double heading, double speed, double alt);
void checkHoldPosition(int id, double lat, double lon,
double heading, double speed, double alt);
public:
FGGroundNetwork();
~FGGroundNetwork();
FGGroundNetwork();
~FGGroundNetwork();
void addNode (const FGTaxiNode& node);
void addNodes (FGParkingVec *parkings);
void addSegment(const FGTaxiSegment& seg);
void addNode (const FGTaxiNode& node);
void addNodes (FGParkingVec *parkings);
void addSegment(const FGTaxiSegment& seg);
void init();
bool exists() { return hasNetwork; };
void setTowerController(FGTowerController *twrCtrlr) { towerController = twrCtrlr; };
void init();
bool exists() {
return hasNetwork;
};
void setTowerController(FGTowerController *twrCtrlr) {
towerController = twrCtrlr;
};
int findNearestNode(double lat, double lon);
int findNearestNode(const SGGeod& aGeod);
int findNearestNode(double lat, double lon);
int findNearestNode(const SGGeod& aGeod);
FGTaxiNode *findNode(unsigned idx);
FGTaxiSegment *findSegment(unsigned idx);
FGTaxiRoute findShortestRoute(int start, int end, bool fullSearch=true);
//void trace(FGTaxiNode *, int, int, double dist);
FGTaxiNode *findNode(unsigned idx);
FGTaxiSegment *findSegment(unsigned idx);
FGTaxiRoute findShortestRoute(int start, int end, bool fullSearch=true);
//void trace(FGTaxiNode *, int, int, double dist);
int getNrOfNodes() { return nodes.size(); };
int getNrOfNodes() {
return nodes.size();
};
void setParent(FGAirport *par) { parent = par; };
void setParent(FGAirport *par) {
parent = par;
};
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon, double hdg, double spd, double alt,
double radius, int leg, FGAIAircraft *aircraft);
virtual void signOff(int id);
virtual void updateAircraftInformation(int id, double lat, double lon, double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon, double hdg, double spd, double alt,
double radius, int leg, FGAIAircraft *aircraft);
virtual void signOff(int id);
virtual void updateAircraftInformation(int id, double lat, double lon, double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
bool checkTransmissionState(int minState, int MaxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId,
AtcMsgDir msgDir);
bool checkForCircularWaits(int id);
virtual void render(bool);
virtual string getName();
bool checkTransmissionState(int minState, int MaxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId,
AtcMsgDir msgDir);
bool checkForCircularWaits(int id);
virtual void render(bool);
virtual string getName();
virtual void update(double dt);
void saveElevationCache();
void saveElevationCache();
};

View file

@ -978,7 +978,6 @@ void FGRouteMgr::update_mirror()
const SGGeod& pos(wp->position());
prop->setStringValue("id", wp->ident().c_str());
//prop->setStringValue("name", wp.get_name().c_str());
prop->setDoubleValue("longitude-deg", pos.getLongitudeDeg());
prop->setDoubleValue("latitude-deg",pos.getLatitudeDeg());
@ -995,6 +994,7 @@ void FGRouteMgr::update_mirror()
double ft = wp->altitudeFt();
prop->setDoubleValue("altitude-m", ft * SG_FEET_TO_METER);
prop->setDoubleValue("altitude-ft", ft);
prop->setIntValue("flight-level", static_cast<int>(ft / 1000) * 10);
} else {
prop->setDoubleValue("altitude-m", -9999.9);
prop->setDoubleValue("altitude-ft", -9999.9);
@ -1273,6 +1273,15 @@ Waypt* FGRouteMgr::wayptAtIndex(int index) const
return _route[index];
}
SGPropertyNode_ptr FGRouteMgr::wayptNodeAtIndex(int index) const
{
if ((index < 0) || (index >= numWaypts())) {
throw sg_range_exception("waypt index out of range", "FGRouteMgr::wayptAtIndex");
}
return mirror->getChild("wp", index);
}
bool FGRouteMgr::saveRoute(const SGPath& path)
{
SG_LOG(SG_IO, SG_INFO, "Saving route to " << path.str());
@ -1556,3 +1565,42 @@ void FGRouteMgr::setDestinationICAO(const char* aIdent)
arrivalChanged();
}
FGAirportRef FGRouteMgr::departureAirport() const
{
return _departure;
}
FGAirportRef FGRouteMgr::destinationAirport() const
{
return _destination;
}
FGRunway* FGRouteMgr::departureRunway() const
{
if (!_departure) {
return NULL;
}
string runwayId(departure->getStringValue("runway"));
if (!_departure->hasRunwayWithIdent(runwayId)) {
return NULL;
}
return _departure->getRunwayByIdent(runwayId);
}
FGRunway* FGRouteMgr::destinationRunway() const
{
if (!_destination) {
return NULL;
}
string runwayId(destination->getStringValue("runway"));
if (!_destination->hasRunwayWithIdent(runwayId)) {
return NULL;
}
return _destination->getRunwayByIdent(runwayId);
}

View file

@ -35,6 +35,8 @@ class SGPath;
class PropertyWatcher;
class FGAirport;
class FGRunway;
typedef SGSharedPtr<FGAirport> FGAirportRef;
/**
@ -92,6 +94,8 @@ public:
flightgear::Waypt* wayptAtIndex(int index) const;
SGPropertyNode_ptr wayptNodeAtIndex(int index) const;
/**
* Find a waypoint in the route, by position, and return its index, or
* -1 if no matching waypoint was found in the route.
@ -134,6 +138,12 @@ public:
* - navaid/radial-deg/offset-nm
*/
flightgear::WayptRef waypointFromString(const std::string& target);
FGAirportRef departureAirport() const;
FGAirportRef destinationAirport() const;
FGRunway* departureRunway() const;
FGRunway* destinationRunway() const;
private:
flightgear::WayptVec _route;
int _currentIndex;

View file

@ -1,5 +1,86 @@
include(FlightGearComponent)
set(HEADERS
FGFDMExec.h
FGJSBBase.h
JSBSim.hxx
initialization/FGInitialCondition.h
initialization/FGTrim.h
initialization/FGTrimAxis.h
input_output/FGXMLParse.h
input_output/FGXMLFileRead.h
input_output/FGPropertyManager.h
input_output/FGScript.h
input_output/FGfdmSocket.h
input_output/string_utilities.h
input_output/FGXMLElement.h
input_output/net_fdm.hxx
input_output/FGGroundCallback.h
math/FGParameter.h
math/LagrangeMultiplier.h
math/FGColumnVector3.h
math/FGCondition.h
math/FGFunction.h
math/FGLocation.h
math/FGMatrix33.h
math/FGModelFunctions.h
math/FGPropertyValue.h
math/FGQuaternion.h
math/FGRealValue.h
math/FGRungeKutta.h
math/FGTable.h
models/FGAccelerations.h
models/FGAerodynamics.h
models/FGAircraft.h
models/FGAtmosphere.h
models/FGAuxiliary.h
models/FGBuoyantForces.h
models/FGExternalForce.h
models/FGExternalReactions.h
models/FGFCS.h
models/FGGasCell.h
models/FGGroundReactions.h
models/FGInertial.h
models/FGInput.h
models/FGLGear.h
models/FGMassBalance.h
models/FGModel.h
models/FGOutput.h
models/FGPropagate.h
models/FGPropulsion.h
models/atmosphere/FGMSIS.h
models/atmosphere/FGStandardAtmosphere.h
models/atmosphere/FGMars.h
models/atmosphere/FGWinds.h
models/flight_control/FGAccelerometer.h
models/flight_control/FGActuator.h
models/flight_control/FGDeadBand.h
models/flight_control/FGFCSComponent.h
models/flight_control/FGFCSFunction.h
models/flight_control/FGFilter.h
models/flight_control/FGGain.h
models/flight_control/FGGyro.h
models/flight_control/FGKinemat.h
models/flight_control/FGMagnetometer.h
models/flight_control/FGPID.h
models/flight_control/FGSensor.h
models/flight_control/FGSensorOrientation.h
models/flight_control/FGSummer.h
models/flight_control/FGSwitch.h
models/propulsion/FGElectric.h
models/propulsion/FGEngine.h
models/propulsion/FGForce.h
models/propulsion/FGNozzle.h
models/propulsion/FGPiston.h
models/propulsion/FGPropeller.h
models/propulsion/FGRocket.h
models/propulsion/FGRotor.h
models/propulsion/FGTank.h
models/propulsion/FGThruster.h
models/propulsion/FGTurbine.h
models/propulsion/FGTurboProp.h
)
set(SOURCES
FGFDMExec.cpp
FGJSBBase.cpp
@ -24,6 +105,7 @@ set(SOURCES
math/FGRealValue.cpp
math/FGRungeKutta.cpp
math/FGTable.cpp
models/FGAccelerations.cpp
models/FGAerodynamics.cpp
models/FGAircraft.cpp
models/FGAtmosphere.cpp
@ -44,7 +126,9 @@ set(SOURCES
models/FGPropulsion.cpp
models/atmosphere/FGMSIS.cpp
models/atmosphere/FGMSISData.cpp
models/atmosphere/FGStandardAtmosphere.cpp
models/atmosphere/FGMars.cpp
models/atmosphere/FGWinds.cpp
models/flight_control/FGAccelerometer.cpp
models/flight_control/FGActuator.cpp
models/flight_control/FGDeadBand.cpp
@ -52,7 +136,6 @@ set(SOURCES
models/flight_control/FGFCSFunction.cpp
models/flight_control/FGFilter.cpp
models/flight_control/FGGain.cpp
models/flight_control/FGGradient.cpp
models/flight_control/FGGyro.cpp
models/flight_control/FGKinemat.cpp
models/flight_control/FGMagnetometer.cpp
@ -76,4 +159,4 @@ set(SOURCES
include_directories(${PROJECT_SOURCE_DIR}/src/FDM/JSBSim)
flightgear_component(JSBSim "${SOURCES}")
flightgear_component(JSBSim "${SOURCES}" "${HEADERS}")

View file

@ -41,10 +41,13 @@ COMMENTS, REFERENCES, and NOTES
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <iostream>
#include <iterator>
#include <cstdlib>
#include "FGFDMExec.h"
#include "models/FGAtmosphere.h"
#include "models/atmosphere/FGMSIS.h"
#include "models/atmosphere/FGMars.h"
#include "models/atmosphere/FGStandardAtmosphere.h"
#include "models/atmosphere/FGWinds.h"
#include "models/FGFCS.h"
#include "models/FGPropulsion.h"
#include "models/FGMassBalance.h"
@ -54,24 +57,20 @@ INCLUDES
#include "models/FGAerodynamics.h"
#include "models/FGInertial.h"
#include "models/FGAircraft.h"
#include "models/FGAccelerations.h"
#include "models/FGPropagate.h"
#include "models/FGAuxiliary.h"
#include "models/FGInput.h"
#include "models/FGOutput.h"
#include "initialization/FGInitialCondition.h"
//#include "initialization/FGTrimAnalysis.h" // Remove until later
#include "input_output/FGPropertyManager.h"
#include "input_output/FGScript.h"
#include <iostream>
#include <iterator>
#include <cstdlib>
using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.95 2011/05/20 10:35:25 jberndt Exp $";
static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.115 2011/09/25 11:56:00 bcoconni Exp $";
static const char *IdHdr = ID_FDMEXEC;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -87,19 +86,6 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root)
Frame = 0;
Error = 0;
GroundCallback = 0;
Atmosphere = 0;
FCS = 0;
Propulsion = 0;
MassBalance = 0;
Aerodynamics = 0;
Inertial = 0;
GroundReactions = 0;
ExternalReactions = 0;
BuoyantForces = 0;
Aircraft = 0;
Propagate = 0;
Auxiliary = 0;
Input = 0;
IC = 0;
Trim = 0;
Script = 0;
@ -111,6 +97,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root)
holding = false;
Terminate = false;
StandAlone = false;
firstPass = true;
sim_time = 0.0;
dT = 1.0/120.0; // a default timestep size. This is needed for when JSBSim is
@ -197,7 +184,7 @@ FGFDMExec::~FGFDMExec()
PropertyCatalog.clear();
FDMctr--;
if (FDMctr > 0) (*FDMctr)--;
Debug(1);
}
@ -208,44 +195,54 @@ bool FGFDMExec::Allocate(void)
{
bool result=true;
Atmosphere = new FGAtmosphere(this);
FCS = new FGFCS(this);
Propulsion = new FGPropulsion(this);
MassBalance = new FGMassBalance(this);
Aerodynamics = new FGAerodynamics (this);
Inertial = new FGInertial(this);
Models.resize(eNumStandardModels);
GroundCallback = new FGGroundCallback(Inertial->GetRefRadius());
// See the eModels enum specification in the header file. The order of the enums
// specifies the order of execution. The Models[] vector is the primary
// storage array for the list of models.
Models[ePropagate] = new FGPropagate(this);
Models[eInput] = new FGInput(this);
Models[eInertial] = new FGInertial(this);
Models[eAtmosphere] = new FGStandardAtmosphere(this);
Models[eWinds] = new FGWinds(this);
Models[eAuxiliary] = new FGAuxiliary(this);
Models[eSystems] = new FGFCS(this);
Models[ePropulsion] = new FGPropulsion(this);
Models[eAerodynamics] = new FGAerodynamics (this);
GroundReactions = new FGGroundReactions(this);
ExternalReactions = new FGExternalReactions(this);
BuoyantForces = new FGBuoyantForces(this);
Aircraft = new FGAircraft(this);
Propagate = new FGPropagate(this);
Auxiliary = new FGAuxiliary(this);
Input = new FGInput(this);
GroundCallback = new FGGroundCallback(((FGInertial*)Models[eInertial])->GetRefRadius());
// Schedule a model. The second arg (the integer) is the pass number. For
// instance, the atmosphere model could get executed every fifth pass it is called.
Schedule(Input, 1); // Input model is Models[0]
Schedule(Atmosphere, 1); // Input model is Models[1]
Schedule(FCS, 1); // Input model is Models[2]
Schedule(Propulsion, 1); // Input model is Models[3]
Schedule(MassBalance, 1); // Input model is Models[4]
Schedule(Aerodynamics, 1); // Input model is Models[5]
Schedule(Inertial, 1); // Input model is Models[6]
Schedule(GroundReactions, 1); // Input model is Models[7]
Schedule(ExternalReactions, 1); // Input model is Models[8]
Schedule(BuoyantForces, 1); // Input model is Models[9]
Schedule(Aircraft, 1); // Input model is Models[10]
Schedule(Propagate, 1); // Input model is Models[11]
Schedule(Auxiliary, 1); // Input model is Models[12]
Models[eGroundReactions] = new FGGroundReactions(this);
Models[eExternalReactions] = new FGExternalReactions(this);
Models[eBuoyantForces] = new FGBuoyantForces(this);
Models[eMassBalance] = new FGMassBalance(this);
Models[eAircraft] = new FGAircraft(this);
Models[eAccelerations] = new FGAccelerations(this);
// Initialize models so they can communicate with each other
// Assign the Model shortcuts for internal executive use only.
Propagate = (FGPropagate*)Models[ePropagate];
Inertial = (FGInertial*)Models[eInertial];
Atmosphere = (FGAtmosphere*)Models[eAtmosphere];
Winds = (FGWinds*)Models[eWinds];
Auxiliary = (FGAuxiliary*)Models[eAuxiliary];
FCS = (FGFCS*)Models[eSystems];
Propulsion = (FGPropulsion*)Models[ePropulsion];
Aerodynamics = (FGAerodynamics*)Models[eAerodynamics];
GroundReactions = (FGGroundReactions*)Models[eGroundReactions];
ExternalReactions = (FGExternalReactions*)Models[eExternalReactions];
BuoyantForces = (FGBuoyantForces*)Models[eBuoyantForces];
MassBalance = (FGMassBalance*)Models[eMassBalance];
Aircraft = (FGAircraft*)Models[eAircraft];
Accelerations = (FGAccelerations*)Models[eAccelerations];
vector <FGModel*>::iterator it;
for (it = Models.begin(); it != Models.end(); ++it) (*it)->InitModel();
// Initialize planet (environment) constants
LoadPlanetConstants();
// Initialize models
for (unsigned int i = 0; i < Models.size(); i++) {
LoadInputs(i);
Models[i]->InitModel();
}
IC = new FGInitialCondition(this);
@ -258,24 +255,14 @@ bool FGFDMExec::Allocate(void)
bool FGFDMExec::DeAllocate(void)
{
delete Input;
delete Atmosphere;
delete FCS;
delete Propulsion;
delete MassBalance;
delete Aerodynamics;
delete Inertial;
delete GroundReactions;
delete ExternalReactions;
delete BuoyantForces;
delete Aircraft;
delete Propagate;
delete Auxiliary;
delete Script;
for (unsigned int i=0; i<eNumStandardModels; i++) delete Models[i];
Models.clear();
for (unsigned i=0; i<Outputs.size(); i++) delete Outputs[i];
Outputs.clear();
delete Script;
delete IC;
delete Trim;
@ -283,23 +270,6 @@ bool FGFDMExec::DeAllocate(void)
Error = 0;
Input = 0;
Atmosphere = 0;
FCS = 0;
Propulsion = 0;
MassBalance = 0;
Aerodynamics = 0;
Inertial = 0;
GroundReactions = 0;
ExternalReactions = 0;
BuoyantForces = 0;
Aircraft = 0;
Propagate = 0;
Auxiliary = 0;
Script = 0;
Models.clear();
modelLoaded = false;
return modelLoaded;
}
@ -321,22 +291,252 @@ bool FGFDMExec::Run(void)
Debug(2);
for (unsigned int i=1; i<ChildFDMList.size(); i++) {
ChildFDMList[i]->AssignState(Propagate); // Transfer state to the child FDM
ChildFDMList[i]->AssignState( (FGPropagate*)Models[ePropagate] ); // Transfer state to the child FDM
ChildFDMList[i]->Run();
}
if (firstPass && !IntegrationSuspended()) {
// Outputs the initial conditions
for (unsigned int i = 0; i < Outputs.size(); i++)
Outputs[i]->Run(holding);
firstPass = false;
}
// returns true if success, false if complete
if (Script != 0 && !IntegrationSuspended()) success = Script->RunScript();
vector <FGModel*>::iterator it;
for (it = Models.begin(); it != Models.end(); ++it) (*it)->Run(holding);
IncrTime();
for (unsigned int i = 0; i < Models.size(); i++) {
LoadInputs(i);
Models[i]->Run(holding);
}
if (Terminate) success = false;
return (success);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGFDMExec::LoadInputs(unsigned int idx)
{
switch(idx) {
case ePropagate:
Propagate->in.vPQRidot = Accelerations->GetPQRidot();
Propagate->in.vQtrndot = Accelerations->GetQuaterniondot();
Propagate->in.vUVWidot = Accelerations->GetUVWidot();
Propagate->in.DeltaT = dT;
break;
case eInput:
break;
case eInertial:
Inertial->in.Radius = Propagate->GetRadius();
Inertial->in.Latitude = Propagate->GetLatitude();
break;
case eAtmosphere:
Atmosphere->in.altitudeASL = Propagate->GetAltitudeASL();
break;
case eWinds:
Winds->in.AltitudeASL = Propagate->GetAltitudeASL();
Winds->in.DistanceAGL = Propagate->GetDistanceAGL();
Winds->in.Tl2b = Propagate->GetTl2b();
Winds->in.Tw2b = Auxiliary->GetTw2b();
Winds->in.V = Auxiliary->GetVt();
Winds->in.totalDeltaT = dT * Winds->GetRate();
break;
case eAuxiliary:
Auxiliary->in.Pressure = Atmosphere->GetPressure();
Auxiliary->in.Density = Atmosphere->GetDensity();
Auxiliary->in.DensitySL = Atmosphere->GetDensitySL();
Auxiliary->in.PressureSL = Atmosphere->GetPressureSL();
Auxiliary->in.Temperature = Atmosphere->GetTemperature();
Auxiliary->in.SoundSpeed = Atmosphere->GetSoundSpeed();
Auxiliary->in.KinematicViscosity = Atmosphere->GetKinematicViscosity();
Auxiliary->in.DistanceAGL = Propagate->GetDistanceAGL();
Auxiliary->in.Mass = MassBalance->GetMass();
Auxiliary->in.Tl2b = Propagate->GetTl2b();
Auxiliary->in.Tb2l = Propagate->GetTb2l();
Auxiliary->in.vPQR = Propagate->GetPQR();
Auxiliary->in.vPQRdot = Accelerations->GetPQRdot();
Auxiliary->in.vUVW = Propagate->GetUVW();
Auxiliary->in.vUVWdot = Accelerations->GetUVWdot();
Auxiliary->in.vVel = Propagate->GetVel();
Auxiliary->in.vBodyAccel = Accelerations->GetBodyAccel();
Auxiliary->in.ToEyePt = MassBalance->StructuralToBody(Aircraft->GetXYZep());
Auxiliary->in.VRPBody = MassBalance->StructuralToBody(Aircraft->GetXYZvrp());
Auxiliary->in.RPBody = MassBalance->StructuralToBody(Aircraft->GetXYZrp());
Auxiliary->in.vFw = Aerodynamics->GetvFw();
Auxiliary->in.vLocation = Propagate->GetLocation();
Auxiliary->in.Latitude = Propagate->GetLatitude();
Auxiliary->in.Longitude = Propagate->GetLongitude();
Auxiliary->in.CosTht = Propagate->GetCosEuler(eTht);
Auxiliary->in.SinTht = Propagate->GetSinEuler(eTht);
Auxiliary->in.CosPhi = Propagate->GetCosEuler(ePhi);
Auxiliary->in.SinPhi = Propagate->GetSinEuler(ePhi);
Auxiliary->in.Psi = Propagate->GetEuler(ePsi);
Auxiliary->in.TotalWindNED = Winds->GetTotalWindNED();
Auxiliary->in.TurbPQR = Winds->GetTurbPQR();
Auxiliary->in.WindPsi = Winds->GetWindPsi();
Auxiliary->in.Vwind = Winds->GetTotalWindNED().Magnitude();
break;
case eSystems:
// Dynamic inputs come into the components that FCS manages through properties
break;
case ePropulsion:
Propulsion->in.SLPressure = Atmosphere->GetPressureSL();
Propulsion->in.Pressure = Atmosphere->GetPressure();
Propulsion->in.PressureRatio = Atmosphere->GetPressureRatio();
Propulsion->in.Temperature = Atmosphere->GetTemperature();
Propulsion->in.DensityRatio = Atmosphere->GetDensityRatio();
Propulsion->in.Density = Atmosphere->GetDensity();
Propulsion->in.Soundspeed = Atmosphere->GetSoundSpeed();
Propulsion->in.TotalPressure = Auxiliary->GetTotalPressure();
Propulsion->in.TotalTempearture = Auxiliary->GetTotalTemperature();
Propulsion->in.Vc = Auxiliary->GetVcalibratedKTS();
Propulsion->in.Vt = Auxiliary->GetVt();
Propulsion->in.qbar = Auxiliary->Getqbar();
Propulsion->in.TAT_c = Auxiliary->GetTAT_C();
Propulsion->in.AeroUVW = Auxiliary->GetAeroUVW();
Propulsion->in.AeroPQR = Auxiliary->GetAeroPQR();
Propulsion->in.alpha = Auxiliary->Getalpha();
Propulsion->in.beta = Auxiliary->Getbeta();
Propulsion->in.TotalDeltaT = dT * Propulsion->GetRate();
Propulsion->in.ThrottlePos = FCS->GetThrottlePos();
Propulsion->in.MixturePos = FCS->GetMixturePos();
Propulsion->in.ThrottleCmd = FCS->GetThrottleCmd();
Propulsion->in.MixtureCmd = FCS->GetMixtureCmd();
Propulsion->in.PropAdvance = FCS->GetPropAdvance();
Propulsion->in.PropFeather = FCS->GetPropFeather();
Propulsion->in.H_agl = Propagate->GetDistanceAGL();
Propulsion->in.PQR = Propagate->GetPQR();
break;
case eAerodynamics:
Aerodynamics->in.Alpha = Auxiliary->Getalpha();
Aerodynamics->in.Beta = Auxiliary->Getbeta();
Aerodynamics->in.Qbar = Auxiliary->Getqbar();
Aerodynamics->in.Vt = Auxiliary->GetVt();
Aerodynamics->in.Tb2w = Auxiliary->GetTb2w();
Aerodynamics->in.Tw2b = Auxiliary->GetTw2b();
Aerodynamics->in.RPBody = MassBalance->StructuralToBody(Aircraft->GetXYZrp());
break;
case eGroundReactions:
// There are no external inputs to this model.
GroundReactions->in.Vground = Auxiliary->GetVground();
GroundReactions->in.VcalibratedKts = Auxiliary->GetVcalibratedKTS();
GroundReactions->in.Temperature = Atmosphere->GetTemperature();
GroundReactions->in.TakeoffThrottle = (FCS->GetThrottlePos().size() > 0) ? (FCS->GetThrottlePos(0) > 0.90) : false;
GroundReactions->in.SteerPosDeg = FCS->GetSteerPosDeg();
GroundReactions->in.BrakePos = FCS->GetBrakePos();
GroundReactions->in.FCSGearPos = FCS->GetGearPos();
GroundReactions->in.EmptyWeight = MassBalance->GetEmptyWeight();
GroundReactions->in.Tb2l = Propagate->GetTb2l();
GroundReactions->in.Tec2l = Propagate->GetTec2l();
GroundReactions->in.Tec2b = Propagate->GetTec2b();
GroundReactions->in.PQR = Propagate->GetPQR();
GroundReactions->in.UVW = Propagate->GetUVW();
GroundReactions->in.DistanceAGL = Propagate->GetDistanceAGL();
GroundReactions->in.DistanceASL = Propagate->GetAltitudeASL();
GroundReactions->in.TotalDeltaT = dT * GroundReactions->GetRate();
GroundReactions->in.WOW = GroundReactions->GetWOW();
GroundReactions->in.Location = Propagate->GetLocation();
for (int i=0; i<GroundReactions->GetNumGearUnits(); i++) {
GroundReactions->in.vWhlBodyVec[i] = MassBalance->StructuralToBody(GroundReactions->GetGearUnit(i)->GetLocation());
}
break;
case eExternalReactions:
// There are no external inputs to this model.
break;
case eBuoyantForces:
BuoyantForces->in.Density = Atmosphere->GetDensity();
BuoyantForces->in.Pressure = Atmosphere->GetPressure();
BuoyantForces->in.Temperature = Atmosphere->GetTemperature();
BuoyantForces->in.gravity = Inertial->gravity();
break;
case eMassBalance:
MassBalance->in.GasInertia = BuoyantForces->GetGasMassInertia();
MassBalance->in.GasMass = BuoyantForces->GetGasMass();
MassBalance->in.GasMoment = BuoyantForces->GetGasMassMoment();
MassBalance->in.TanksWeight = Propulsion->GetTanksWeight();
MassBalance->in.TanksMoment = Propulsion->GetTanksMoment();
MassBalance->in.TankInertia = Propulsion->CalculateTankInertias();
break;
case eAircraft:
Aircraft->in.AeroForce = Aerodynamics->GetForces();
Aircraft->in.PropForce = Propulsion->GetForces();
Aircraft->in.GroundForce = GroundReactions->GetForces();
Aircraft->in.ExternalForce = ExternalReactions->GetForces();
Aircraft->in.BuoyantForce = BuoyantForces->GetForces();
Aircraft->in.AeroMoment = Aerodynamics->GetMoments();
Aircraft->in.PropMoment = Propulsion->GetMoments();
Aircraft->in.GroundMoment = GroundReactions->GetMoments();
Aircraft->in.ExternalMoment = ExternalReactions->GetMoments();
Aircraft->in.BuoyantMoment = BuoyantForces->GetMoments();
Aircraft->in.Weight = MassBalance->GetWeight();
Aircraft->in.Tl2b = Propagate->GetTl2b();
break;
case eAccelerations:
Accelerations->in.J = MassBalance->GetJ();
Accelerations->in.Jinv = MassBalance->GetJinv();
Accelerations->in.Ti2b = Propagate->GetTi2b();
Accelerations->in.Tb2i = Propagate->GetTb2i();
Accelerations->in.Tec2b = Propagate->GetTec2b();
Accelerations->in.Tl2b = Propagate->GetTl2b();
Accelerations->in.qAttitudeECI = Propagate->GetQuaternionECI();
Accelerations->in.Moment = Aircraft->GetMoments();
Accelerations->in.GroundMoment = GroundReactions->GetMoments();
Accelerations->in.Force = Aircraft->GetForces();
Accelerations->in.GroundForce = GroundReactions->GetForces();
Accelerations->in.GAccel = Inertial->GetGAccel(Propagate->GetRadius());
Accelerations->in.J2Grav = Inertial->GetGravityJ2(Propagate->GetLocation());
Accelerations->in.vPQRi = Propagate->GetPQRi();
Accelerations->in.vPQR = Propagate->GetPQR();
Accelerations->in.vUVW = Propagate->GetUVW();
Accelerations->in.vInertialPosition = Propagate->GetInertialPosition();
Accelerations->in.DeltaT = dT;
Accelerations->in.Mass = MassBalance->GetMass();
Accelerations->in.MultipliersList = GroundReactions->GetMultipliersList();
Accelerations->in.TerrainVelocity = Propagate->GetTerrainVelocity();
Accelerations->in.TerrainAngularVel = Propagate->GetTerrainAngularVelocity();
break;
default:
break;
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGFDMExec::LoadPlanetConstants(void)
{
Propagate->in.vOmegaPlanet = Inertial->GetOmegaPlanet();
Accelerations->in.vOmegaPlanet = Inertial->GetOmegaPlanet();
Propagate->in.RefRadius = Inertial->GetRefRadius();
Propagate->in.SemiMajor = Inertial->GetSemimajor();
Propagate->in.SemiMinor = Inertial->GetSemiminor();
Auxiliary->in.SLGravity = Inertial->SLgravity();
Auxiliary->in.ReferenceRadius = Inertial->GetRefRadius();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGFDMExec::LoadModelConstants(void)
{
Winds->in.wingspan = Aircraft->GetWingSpan();
FCS->in.NumGear = GroundReactions->GetNumGearUnits();
Aerodynamics->in.Wingarea = Aircraft->GetWingArea();
Aerodynamics->in.Wingchord = Aircraft->Getcbar();
Aerodynamics->in.Wingincidence = Aircraft->GetWingIncidence();
Aerodynamics->in.Wingspan = Aircraft->GetWingSpan();
Auxiliary->in.Wingspan = Aircraft->GetWingSpan();
Auxiliary->in.Wingchord = Aircraft->Getcbar();
for (int i=0; i<GroundReactions->GetNumGearUnits(); i++) {
GroundReactions->in.vWhlBodyVec[i] = MassBalance->StructuralToBody(GroundReactions->GetGearUnit(i)->GetLocation());
}
LoadPlanetConstants();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// This call will cause the sim time to reset to 0.0
@ -357,12 +557,15 @@ void FGFDMExec::Initialize(FGInitialCondition *FGIC)
Setsim_time(0.0);
Propagate->SetInitialState( FGIC );
LoadInputs(eAccelerations);
Accelerations->Run(false);
LoadInputs(ePropagate);
Propagate->InitializeDerivatives();
LoadInputs(eAtmosphere);
Atmosphere->Run(false);
Atmosphere->SetWindNED( FGIC->GetWindNFpsIC(),
FGIC->GetWindEFpsIC(),
FGIC->GetWindDFpsIC() );
Winds->SetWindNED( FGIC->GetWindNFpsIC(),
FGIC->GetWindEFpsIC(),
FGIC->GetWindDFpsIC() );
Auxiliary->Run(false);
}
@ -397,6 +600,23 @@ void FGFDMExec::ResetToInitialConditions(void)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGFDMExec::SetOutputFileName(const string& fname)
{
if (Outputs.size() > 0) Outputs[0]->SetOutputFileName(fname);
else return false;
return true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGFDMExec::GetOutputFileName(void)
{
if (Outputs.size() > 0) return Outputs[0]->GetOutputFileName();
else return string("");
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGFDMExec::SetGroundCallback(FGGroundCallback* p)
{
delete GroundCallback;
@ -408,6 +628,7 @@ void FGFDMExec::SetGroundCallback(FGGroundCallback* p)
vector <string> FGFDMExec::EnumerateFDMs(void)
{
vector <string> FDMList;
FGAircraft* Aircraft = (FGAircraft*)Models[eAircraft];
FDMList.push_back(Aircraft->GetAircraftName());
@ -493,7 +714,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
// Process the metrics element. This element is REQUIRED.
element = document->FindElement("metrics");
if (element) {
result = Aircraft->Load(element);
result = ((FGAircraft*)Models[eAircraft])->Load(element);
if (!result) {
cerr << endl << "Aircraft metrics element has problems in file " << aircraftCfgFileName << endl;
return result;
@ -506,7 +727,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
// Process the mass_balance element. This element is REQUIRED.
element = document->FindElement("mass_balance");
if (element) {
result = MassBalance->Load(element);
result = ((FGMassBalance*)Models[eMassBalance])->Load(element);
if (!result) {
cerr << endl << "Aircraft mass_balance element has problems in file " << aircraftCfgFileName << endl;
return result;
@ -519,11 +740,12 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
// Process the ground_reactions element. This element is REQUIRED.
element = document->FindElement("ground_reactions");
if (element) {
result = GroundReactions->Load(element);
result = ((FGGroundReactions*)Models[eGroundReactions])->Load(element);
if (!result) {
cerr << endl << "Aircraft ground_reactions element has problems in file " << aircraftCfgFileName << endl;
return result;
}
((FGFCS*)Models[eSystems])->AddGear(((FGGroundReactions*)Models[eGroundReactions])->GetNumGearUnits());
} else {
cerr << endl << "No ground_reactions element was found in the aircraft config file." << endl;
return false;
@ -532,7 +754,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
// Process the external_reactions element. This element is OPTIONAL.
element = document->FindElement("external_reactions");
if (element) {
result = ExternalReactions->Load(element);
result = ((FGExternalReactions*)Models[eExternalReactions])->Load(element);
if (!result) {
cerr << endl << "Aircraft external_reactions element has problems in file " << aircraftCfgFileName << endl;
return result;
@ -542,7 +764,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
// Process the buoyant_forces element. This element is OPTIONAL.
element = document->FindElement("buoyant_forces");
if (element) {
result = BuoyantForces->Load(element);
result = ((FGBuoyantForces*)Models[eBuoyantForces])->Load(element);
if (!result) {
cerr << endl << "Aircraft buoyant_forces element has problems in file " << aircraftCfgFileName << endl;
return result;
@ -552,17 +774,19 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
// Process the propulsion element. This element is OPTIONAL.
element = document->FindElement("propulsion");
if (element) {
result = Propulsion->Load(element);
result = ((FGPropulsion*)Models[ePropulsion])->Load(element);
if (!result) {
cerr << endl << "Aircraft propulsion element has problems in file " << aircraftCfgFileName << endl;
return result;
}
for (unsigned int i=0; i<((FGPropulsion*)Models[ePropulsion])->GetNumEngines(); i++)
((FGFCS*)Models[eSystems])->AddThrottle();
}
// Process the system element[s]. This element is OPTIONAL, and there may be more than one.
element = document->FindElement("system");
while (element) {
result = FCS->Load(element, FGFCS::stSystem);
result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stSystem);
if (!result) {
cerr << endl << "Aircraft system element has problems in file " << aircraftCfgFileName << endl;
return result;
@ -573,7 +797,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
// Process the autopilot element. This element is OPTIONAL.
element = document->FindElement("autopilot");
if (element) {
result = FCS->Load(element, FGFCS::stAutoPilot);
result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stAutoPilot);
if (!result) {
cerr << endl << "Aircraft autopilot element has problems in file " << aircraftCfgFileName << endl;
return result;
@ -583,7 +807,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
// Process the flight_control element. This element is OPTIONAL.
element = document->FindElement("flight_control");
if (element) {
result = FCS->Load(element, FGFCS::stFCS);
result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stFCS);
if (!result) {
cerr << endl << "Aircraft flight_control element has problems in file " << aircraftCfgFileName << endl;
return result;
@ -593,7 +817,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
// Process the aerodynamics element. This element is OPTIONAL, but almost always expected.
element = document->FindElement("aerodynamics");
if (element) {
result = Aerodynamics->Load(element);
result = ((FGAerodynamics*)Models[eAerodynamics])->Load(element);
if (!result) {
cerr << endl << "Aircraft aerodynamics element has problems in file " << aircraftCfgFileName << endl;
return result;
@ -605,7 +829,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
// Process the input element. This element is OPTIONAL.
element = document->FindElement("input");
if (element) {
result = Input->Load(element);
result = ((FGInput*)Models[eInput])->Load(element);
if (!result) {
cerr << endl << "Aircraft input element has problems in file " << aircraftCfgFileName << endl;
return result;
@ -616,13 +840,12 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
unsigned int idx=0;
typedef double (FGOutput::*iOPMF)(void) const;
typedef int (FGFDMExec::*iOPV)(void) const;
typedef void (FGFDMExec::*vOPI)(int) const;
element = document->FindElement("output");
while (element) {
if (debug_lvl > 0) cout << endl << " Output data set: " << idx << " ";
FGOutput* Output = new FGOutput(this);
Output->InitModel();
Schedule(Output, 1);
Schedule(Output);
result = Output->Load(element);
if (!result) {
cerr << endl << "Aircraft output element has problems in file " << aircraftCfgFileName << endl;
@ -647,11 +870,16 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
}
}
// Since all vehicle characteristics have been loaded, place the values in the Inputs
// structure for the FGModel-derived classes.
LoadModelConstants();
modelLoaded = true;
if (debug_lvl > 0) {
MassBalance->Run(false); // Update all mass properties for the report.
MassBalance->GetMassPropertiesReport();
LoadInputs(eMassBalance); // Update all input mass properties for the report.
Models[eMassBalance]->Run(false); // Update all mass properties for the report.
((FGMassBalance*)Models[eMassBalance])->GetMassPropertiesReport();
cout << endl << fgblue << highint
<< "End of vehicle configuration loading." << endl
@ -667,6 +895,8 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
<< fgdef << endl;
}
for (unsigned int i=0; i< Models.size(); i++) LoadInputs(i);
if (result) {
struct PropertyCatalogStructure masterPCS;
masterPCS.base_string = "";
@ -679,6 +909,13 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGFDMExec::GetPropulsionTankReport()
{
return ((FGPropulsion*)Models[ePropulsion])->GetPropulsionTankReport();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs)
{
struct PropertyCatalogStructure* pcsNew = new struct PropertyCatalogStructure;
@ -760,7 +997,7 @@ bool FGFDMExec::ReadPrologue(Element* el) // el for ReadPrologue is the document
if (!el) return false;
string AircraftName = el->GetAttributeValue("name");
Aircraft->SetAircraftName(AircraftName);
((FGAircraft*)Models[eAircraft])->SetAircraftName(AircraftName);
if (debug_lvl & 1) cout << underon << "Reading Aircraft Configuration File"
<< underoff << ": " << highint << AircraftName << normint << endl;
@ -899,7 +1136,7 @@ void FGFDMExec::EnableOutput(void)
void FGFDMExec::ForceOutput(int idx)
{
if (idx >= 0 && idx < Outputs.size()) Outputs[idx]->Print();
if (idx >= (int)0 && idx < (int)Outputs.size()) Outputs[idx]->Print();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -911,15 +1148,18 @@ bool FGFDMExec::SetOutputDirectives(const string& fname)
FGOutput* Output = new FGOutput(this);
Output->SetDirectivesFile(RootDir + fname);
Output->InitModel();
Schedule(Output, 1);
Schedule(Output);
result = Output->Load(0);
if (result) {
Output->Run(holding);
Outputs.push_back(Output);
typedef double (FGOutput::*iOPMF)(void) const;
string outputProp = CreateIndexedPropertyName("simulation/output",Outputs.size()-1);
instance->Tie(outputProp+"/log_rate_hz", Output, (iOPMF)0, &FGOutput::SetRate, false);
}
else
delete Output;
return result;
}
@ -943,38 +1183,6 @@ void FGFDMExec::DoTrim(int mode)
sim_time = saved_time;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGFDMExec::UseAtmosphereMSIS(void)
{
FGAtmosphere *oldAtmosphere = Atmosphere;
Atmosphere = new MSIS(this);
if (!Atmosphere->InitModel()) {
cerr << fgred << "MSIS Atmosphere model init failed" << fgdef << endl;
Error+=1;
}
Models[1] = Atmosphere; // Reassign the atmosphere model that has already been scheduled
// to the new atmosphere.
delete oldAtmosphere;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGFDMExec::UseAtmosphereMars(void)
{
/*
FGAtmosphere *oldAtmosphere = Atmosphere;
Atmosphere = new FGMars(this);
if (!Atmosphere->InitModel()) {
cerr << fgred << "Mars Atmosphere model init failed" << fgdef << endl;
Error+=1;
}
Models[1] = Atmosphere; // Reassign the atmosphere model that has already been scheduled
// to the new atmosphere.
delete oldAtmosphere;
*/
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
@ -1000,10 +1208,10 @@ void FGFDMExec::Debug(int from)
if (debug_lvl & 1 && IdFDM == 0) { // Standard console startup message output
if (from == 0) { // Constructor
cout << "\n\n " << highint << underon << "JSBSim Flight Dynamics Model v"
<< JSBSim_version << underoff << normint << endl;
cout << halfint << " [JSBSim-ML v" << needed_cfg_version << "]\n\n";
cout << normint << "JSBSim startup beginning ...\n\n";
cout << "\n\n "
<< "JSBSim Flight Dynamics Model v" << JSBSim_version << endl;
cout << " [JSBSim-ML v" << needed_cfg_version << "]\n\n";
cout << "JSBSim startup beginning ...\n\n";
} else if (from == 3) {
cout << "\n\nJSBSim startup complete\n\n";
}

View file

@ -44,8 +44,6 @@ INCLUDES
#include <vector>
#include <string>
#include "models/FGOutput.h"
#include "models/FGInput.h"
#include "initialization/FGTrim.h"
#include "FGJSBBase.h"
#include "input_output/FGPropertyManager.h"
@ -58,7 +56,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_FDMEXEC "$Id: FGFDMExec.h,v 1.64 2011/05/20 03:18:36 jberndt Exp $"
#define ID_FDMEXEC "$Id: FGFDMExec.h,v 1.71 2011/09/07 02:37:04 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -71,6 +69,8 @@ class FGTrim;
class FGAerodynamics;
class FGAircraft;
class FGAtmosphere;
class FGAccelerations;
class FGWinds;
class FGAuxiliary;
class FGBuoyantForces;
class FGExternalReactions;
@ -181,7 +181,7 @@ CLASS DOCUMENTATION
property actually maps toa function call of DoTrim().
@author Jon S. Berndt
@version $Revision: 1.64 $
@version $Revision: 1.71 $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -224,6 +224,25 @@ public:
/// Default destructor
~FGFDMExec();
// This list of enums is very important! The order in which models are listed here
// determines the order of execution of the models.
enum eModels { ePropagate=0,
eInput,
eInertial,
eAtmosphere,
eWinds,
eAuxiliary,
eSystems,
ePropulsion,
eAerodynamics,
eGroundReactions,
eExternalReactions,
eBuoyantForces,
eMassBalance,
eAircraft,
eAccelerations,
eNumStandardModels };
/** Unbind all tied JSBSim properties. */
void Unbind(void) {instance->Unbind();}
@ -236,8 +255,9 @@ public:
one is at this time not recommended.
@param model A pointer to the model being scheduled.
@param rate The rate at which to execute the model as described above.
Default is every frame (rate=1).
@return Currently returns 0 always. */
void Schedule(FGModel* model, int rate);
void Schedule(FGModel* model, int rate=1);
/** This function executes each scheduled model in succession.
@return true if successful, false if sim should be ended */
@ -309,31 +329,35 @@ public:
/// @name Top-level executive State and Model retrieval mechanism
//@{
/// Returns the FGAtmosphere pointer.
FGAtmosphere* GetAtmosphere(void) {return Atmosphere;}
FGAtmosphere* GetAtmosphere(void) {return (FGAtmosphere*)Models[eAtmosphere];}
/// Returns the FGAccelerations pointer.
FGAccelerations* GetAccelerations(void) {return (FGAccelerations*)Models[eAccelerations];}
/// Returns the FGWinds pointer.
FGWinds* GetWinds(void) {return (FGWinds*)Models[eWinds];}
/// Returns the FGFCS pointer.
FGFCS* GetFCS(void) {return FCS;}
FGFCS* GetFCS(void) {return (FGFCS*)Models[eSystems];}
/// Returns the FGPropulsion pointer.
FGPropulsion* GetPropulsion(void) {return Propulsion;}
FGPropulsion* GetPropulsion(void) {return (FGPropulsion*)Models[ePropulsion];}
/// Returns the FGAircraft pointer.
FGMassBalance* GetMassBalance(void) {return MassBalance;}
FGMassBalance* GetMassBalance(void) {return (FGMassBalance*)Models[eMassBalance];}
/// Returns the FGAerodynamics pointer
FGAerodynamics* GetAerodynamics(void){return Aerodynamics;}
FGAerodynamics* GetAerodynamics(void){return (FGAerodynamics*)Models[eAerodynamics];}
/// Returns the FGInertial pointer.
FGInertial* GetInertial(void) {return Inertial;}
FGInertial* GetInertial(void) {return (FGInertial*)Models[eInertial];}
/// Returns the FGGroundReactions pointer.
FGGroundReactions* GetGroundReactions(void) {return GroundReactions;}
FGGroundReactions* GetGroundReactions(void) {return (FGGroundReactions*)Models[eGroundReactions];}
/// Returns the FGExternalReactions pointer.
FGExternalReactions* GetExternalReactions(void) {return ExternalReactions;}
FGExternalReactions* GetExternalReactions(void) {return (FGExternalReactions*)Models[eExternalReactions];}
/// Returns the FGBuoyantForces pointer.
FGBuoyantForces* GetBuoyantForces(void) {return BuoyantForces;}
FGBuoyantForces* GetBuoyantForces(void) {return (FGBuoyantForces*)Models[eBuoyantForces];}
/// Returns the FGAircraft pointer.
FGAircraft* GetAircraft(void) {return Aircraft;}
FGAircraft* GetAircraft(void) {return (FGAircraft*)Models[eAircraft];}
/// Returns the FGPropagate pointer.
FGPropagate* GetPropagate(void) {return Propagate;}
FGPropagate* GetPropagate(void) {return (FGPropagate*)Models[ePropagate];}
/// Returns the FGAuxiliary pointer.
FGAuxiliary* GetAuxiliary(void) {return Auxiliary;}
FGAuxiliary* GetAuxiliary(void) {return (FGAuxiliary*)Models[eAuxiliary];}
/// Returns the FGInput pointer.
FGInput* GetInput(void) {return Input;}
FGInput* GetInput(void) {return (FGInput*)Models[eInput];}
/// Returns the FGGroundCallback pointer.
FGGroundCallback* GetGroundCallback(void) {return GroundCallback;}
/// Retrieves the script object
@ -408,19 +432,12 @@ public:
/** Sets (or overrides) the output filename
@param fname the name of the file to output data to
@return true if successful, false if there is no output specified for the flight model */
bool SetOutputFileName(const string& fname) {
if (Outputs.size() > 0) Outputs[0]->SetOutputFileName(fname);
else return false;
return true;
}
bool SetOutputFileName(const string& fname);
/** Retrieves the current output filename.
@return the name of the output file for the first output specified by the flight model.
If none is specified, the empty string is returned. */
string GetOutputFileName(void) {
if (Outputs.size() > 0) return Outputs[0]->GetOutputFileName();
else return string("");
}
string GetOutputFileName(void);
/** Executes trimming in the selected mode.
* @param mode Specifies how to trim:
@ -474,17 +491,13 @@ public:
vector<string>& GetPropertyCatalog(void) {return PropertyCatalog;}
/// Use the MSIS atmosphere model.
void UseAtmosphereMSIS(void);
/// Use the Mars atmosphere model. (Not operative yet.)
void UseAtmosphereMars(void);
void SetTrimStatus(bool status){ trim_status = status; }
bool GetTrimStatus(void) const { return trim_status; }
void SetTrimMode(int mode){ ta_mode = mode; }
int GetTrimMode(void) const { return ta_mode; }
string GetPropulsionTankReport();
/// Returns the cumulative simulation time in seconds.
double GetSimTime(void) const { return sim_time; }
@ -545,6 +558,7 @@ private:
bool Constructing;
bool modelLoaded;
bool IsChild;
bool firstPass;
string modelName;
string AircraftPath;
string FullAircraftPath;
@ -554,23 +568,26 @@ private:
string Release;
string RootDir;
// Standard Model pointers - shortcuts for internal executive use only.
FGPropagate* Propagate;
FGInertial* Inertial;
FGAtmosphere* Atmosphere;
FGWinds* Winds;
FGAuxiliary* Auxiliary;
FGFCS* FCS;
FGPropulsion* Propulsion;
FGAerodynamics* Aerodynamics;
FGGroundReactions* GroundReactions;
FGExternalReactions* ExternalReactions;
FGBuoyantForces* BuoyantForces;
FGMassBalance* MassBalance;
FGAircraft* Aircraft;
FGAccelerations* Accelerations;
bool trim_status;
int ta_mode;
FGGroundCallback* GroundCallback;
FGAtmosphere* Atmosphere;
FGFCS* FCS;
FGPropulsion* Propulsion;
FGMassBalance* MassBalance;
FGAerodynamics* Aerodynamics;
FGInertial* Inertial;
FGGroundReactions* GroundReactions;
FGExternalReactions* ExternalReactions;
FGBuoyantForces* BuoyantForces;
FGAircraft* Aircraft;
FGPropagate* Propagate;
FGAuxiliary* Auxiliary;
FGInput* Input;
FGScript* Script;
FGInitialCondition* IC;
FGTrim* Trim;
@ -591,6 +608,9 @@ private:
bool ReadChild(Element*);
bool ReadPrologue(Element*);
void ResetToInitialConditions(int mode);
void LoadInputs(unsigned int idx);
void LoadPlanetConstants(void);
void LoadModelConstants(void);
bool Allocate(void);
bool DeAllocate(void);
void Initialize(FGInitialCondition *FGIC);

View file

@ -44,7 +44,7 @@ INCLUDES
namespace JSBSim {
static const char *IdSrc = "$Id: FGJSBBase.cpp,v 1.30 2011/06/13 11:47:04 jberndt Exp $";
static const char *IdSrc = "$Id: FGJSBBase.cpp,v 1.31 2011/07/27 03:55:48 jberndt Exp $";
static const char *IdHdr = ID_JSBBASE;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -228,7 +228,8 @@ FGJSBBase::Message* FGJSBBase::ProcessNextMessage(void)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGJSBBase::disableHighLighting(void) {
void FGJSBBase::disableHighLighting(void)
{
highint[0]='\0';
halfint[0]='\0';
normint[0]='\0';

View file

@ -43,27 +43,20 @@ INCLUDES
#include <string>
#include <cmath>
using std::min;
using std::max;
#include "input_output/string_utilities.h"
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
#if defined(_MSC_VER) && (_MSC_VER < 1300)
namespace std
{
template <class T> inline T max(const T& a, const T& b)
{
return (a > b) ? a : b;
}
}
#endif
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_JSBBASE "$Id: FGJSBBase.h,v 1.32 2011/06/13 11:47:04 jberndt Exp $"
#define ID_JSBBASE "$Id: FGJSBBase.h,v 1.33 2011/06/27 03:14:25 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -79,7 +72,7 @@ CLASS DOCUMENTATION
* This class provides universal constants, utility functions, messaging
* functions, and enumerated constants to JSBSim.
@author Jon S. Berndt
@version $Id: FGJSBBase.h,v 1.32 2011/06/13 11:47:04 jberndt Exp $
@version $Id: FGJSBBase.h,v 1.33 2011/06/27 03:14:25 jberndt Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -269,7 +262,7 @@ public:
@return if the two values can be considered equal up to roundoff */
static bool EqualToRoundoff(double a, double b) {
double eps = 2.0*DBL_EPSILON;
return std::fabs(a - b) <= eps*std::max(std::fabs(a), std::fabs(b));
return std::fabs(a - b) <= eps * max(std::fabs(a), std::fabs(b));
}
/** Finite precision comparison.
@ -278,7 +271,7 @@ public:
@return if the two values can be considered equal up to roundoff */
static bool EqualToRoundoff(float a, float b) {
float eps = 2.0*FLT_EPSILON;
return std::fabs(a - b) <= eps*std::max(std::fabs(a), std::fabs(b));
return std::fabs(a - b) <= eps * max(std::fabs(a), std::fabs(b));
}
/** Finite precision comparison.

View file

@ -60,6 +60,8 @@
#include <FDM/JSBSim/models/FGLGear.h>
#include <FDM/JSBSim/models/FGGroundReactions.h>
#include <FDM/JSBSim/models/FGPropulsion.h>
#include <FDM/JSBSim/models/FGAccelerations.h>
#include <FDM/JSBSim/models/atmosphere/FGWinds.h>
#include <FDM/JSBSim/models/propulsion/FGEngine.h>
#include <FDM/JSBSim/models/propulsion/FGPiston.h>
#include <FDM/JSBSim/models/propulsion/FGTurbine.h>
@ -138,12 +140,11 @@ FGJSBsim::FGJSBsim( double dt )
{
bool result;
if( TURBULENCE_TYPE_NAMES.empty() ) {
TURBULENCE_TYPE_NAMES["ttNone"] = FGAtmosphere::ttNone;
TURBULENCE_TYPE_NAMES["ttStandard"] = FGAtmosphere::ttStandard;
// TURBULENCE_TYPE_NAMES["ttBerndt"] = FGAtmosphere::ttBerndt;
TURBULENCE_TYPE_NAMES["ttCulp"] = FGAtmosphere::ttCulp;
TURBULENCE_TYPE_NAMES["ttMilspec"] = FGAtmosphere::ttMilspec;
TURBULENCE_TYPE_NAMES["ttTustin"] = FGAtmosphere::ttTustin;
TURBULENCE_TYPE_NAMES["ttNone"] = FGWinds::ttNone;
TURBULENCE_TYPE_NAMES["ttStandard"] = FGWinds::ttStandard;
TURBULENCE_TYPE_NAMES["ttCulp"] = FGWinds::ttCulp;
TURBULENCE_TYPE_NAMES["ttMilspec"] = FGWinds::ttMilspec;
TURBULENCE_TYPE_NAMES["ttTustin"] = FGWinds::ttTustin;
}
// Set up the debugging level
@ -177,6 +178,7 @@ FGJSBsim::FGJSBsim( double dt )
fdmex->SetGroundCallback( new FGFSGroundCallback(this) );
Atmosphere = fdmex->GetAtmosphere();
Winds = fdmex->GetWinds();
FCS = fdmex->GetFCS();
MassBalance = fdmex->GetMassBalance();
Propulsion = fdmex->GetPropulsion();
@ -186,6 +188,7 @@ FGJSBsim::FGJSBsim( double dt )
Inertial = fdmex->GetInertial();
Aerodynamics = fdmex->GetAerodynamics();
GroundReactions = fdmex->GetGroundReactions();
Accelerations = fdmex->GetAccelerations();
fgic=fdmex->GetIC();
needTrim=true;
@ -307,7 +310,7 @@ FGJSBsim::FGJSBsim( double dt )
temperature = fgGetNode("/environment/temperature-degc",true);
pressure = fgGetNode("/environment/pressure-inhg",true);
density = fgGetNode("/environment/density-slugft3",true);
pressureSL = fgGetNode("/environment/pressure-sea-level-inhg",true);
ground_wind = fgGetNode("/environment/config/boundary/entry[0]/wind-speed-kt",true);
turbulence_gain = fgGetNode("/environment/turbulence/magnitude-norm",true);
turbulence_rate = fgGetNode("/environment/turbulence/rate-hz",true);
@ -354,19 +357,14 @@ void FGJSBsim::init()
// init method first.
if (fgGetBool("/environment/params/control-fdm-atmosphere")) {
Atmosphere->UseExternal();
Atmosphere->SetExTemperature(
9.0/5.0*(temperature->getDoubleValue()+273.15) );
Atmosphere->SetExPressure(pressure->getDoubleValue()*70.726566);
Atmosphere->SetExDensity(density->getDoubleValue());
Atmosphere->SetTemperature(temperature->getDoubleValue(), get_Altitude(), FGAtmosphere::eCelsius);
Atmosphere->SetPressureSL(pressureSL->getDoubleValue(), FGAtmosphere::eInchesHg);
// initialize to no turbulence, these values get set in the update loop
Atmosphere->SetTurbType(FGAtmosphere::ttNone);
Atmosphere->SetTurbGain(0.0);
Atmosphere->SetTurbRate(0.0);
Atmosphere->SetWindspeed20ft(0.0);
Atmosphere->SetProbabilityOfExceedence(0.0);
} else {
Atmosphere->UseInternal();
Winds->SetTurbType(FGWinds::ttNone);
Winds->SetTurbGain(0.0);
Winds->SetTurbRate(0.0);
Winds->SetWindspeed20ft(0.0);
Winds->SetProbabilityOfExceedence(0.0);
}
fgic->SetWindNEDFpsIC( -wind_from_north->getDoubleValue(),
@ -376,9 +374,9 @@ void FGJSBsim::init()
//Atmosphere->SetExTemperature(get_Static_temperature());
//Atmosphere->SetExPressure(get_Static_pressure());
//Atmosphere->SetExDensity(get_Density());
SG_LOG(SG_FLIGHT,SG_INFO,"T,p,rho: " << fdmex->GetAtmosphere()->GetTemperature()
<< ", " << fdmex->GetAtmosphere()->GetPressure()
<< ", " << fdmex->GetAtmosphere()->GetDensity() );
SG_LOG(SG_FLIGHT,SG_INFO,"T,p,rho: " << Atmosphere->GetTemperature()
<< ", " << Atmosphere->GetPressure()
<< ", " << Atmosphere->GetDensity() );
// deprecate egt_degf for egt-degf to have consistent naming
// TODO: remove this for 2.6.0
@ -394,7 +392,9 @@ void FGJSBsim::init()
FCS->SetDfPos( ofNorm, globals->get_controls()->get_flaps() );
needTrim = startup_trim->getBoolValue();
common_init();
fgic->SetSeaLevelRadiusFtIC( get_Sea_level_radius() );
copy_to_JSBsim();
fdmex->RunIC(); //loop JSBSim once w/o integrating
@ -407,16 +407,16 @@ void FGJSBsim::init()
}
}
if ( startup_trim->getBoolValue() ) {
if ( needTrim ) {
FGLocation cart(fgic->GetLongitudeRadIC(), fgic->GetLatitudeRadIC(),
fgic->GetSeaLevelRadiusFtIC() + fgic->GetAltitudeASLFtIC());
get_Sea_level_radius() + fgic->GetAltitudeASLFtIC());
double cart_pos[3], contact[3], d[3], vel[3], agl;
update_ground_cache(cart, cart_pos, 0.01);
get_agl_ft(fdmex->GetSimTime(), cart_pos, SG_METER_TO_FEET*2, contact,
d, vel, d, &agl);
double terrain_alt = sqrt(contact[0]*contact[0] + contact[1]*contact[1]
+ contact[2]*contact[2]) - fgic->GetSeaLevelRadiusFtIC();
+ contact[2]*contact[2]) - get_Sea_level_radius();
SG_LOG(SG_FLIGHT, SG_INFO, "Ready to trim, terrain elevation is: "
<< terrain_alt * SG_METER_TO_FEET );
@ -664,30 +664,27 @@ bool FGJSBsim::copy_to_JSBsim()
Propagate->SetSeaLevelRadius( get_Sea_level_radius() );
Atmosphere->SetExTemperature(
9.0/5.0*(temperature->getDoubleValue()+273.15) );
Atmosphere->SetExPressure(pressure->getDoubleValue()*70.726566);
Atmosphere->SetExDensity(density->getDoubleValue());
Atmosphere->SetTemperature(temperature->getDoubleValue(), get_Altitude(), FGAtmosphere::eCelsius);
Atmosphere->SetPressureSL(pressureSL->getDoubleValue(), FGAtmosphere::eInchesHg);
Atmosphere->SetTurbType((FGAtmosphere::tType)TURBULENCE_TYPE_NAMES[turbulence_model->getStringValue()]);
switch( Atmosphere->GetTurbType() ) {
// case FGAtmosphere::ttBerndt:
case FGAtmosphere::ttStandard:
case FGAtmosphere::ttCulp: {
Winds->SetTurbType((FGWinds::tType)TURBULENCE_TYPE_NAMES[turbulence_model->getStringValue()]);
switch( Winds->GetTurbType() ) {
case FGWinds::ttStandard:
case FGWinds::ttCulp: {
double tmp = turbulence_gain->getDoubleValue();
Atmosphere->SetTurbGain(tmp * tmp * 100.0);
Atmosphere->SetTurbRate(turbulence_rate->getDoubleValue());
Winds->SetTurbGain(tmp * tmp * 100.0);
Winds->SetTurbRate(turbulence_rate->getDoubleValue());
break;
}
case FGAtmosphere::ttMilspec:
case FGAtmosphere::ttTustin: {
case FGWinds::ttMilspec:
case FGWinds::ttTustin: {
// milspec turbulence: 3=light, 4=moderate, 6=severe turbulence
// turbulence_gain normalized: 0: none, 1/3: light, 2/3: moderate, 3/3: severe
double tmp = turbulence_gain->getDoubleValue();
Atmosphere->SetProbabilityOfExceedence(
Winds->SetProbabilityOfExceedence(
SGMiscd::roundToInt(TurbulenceSeverityTable.GetValue( tmp ) )
);
Atmosphere->SetWindspeed20ft(ground_wind->getDoubleValue());
Winds->SetWindspeed20ft(ground_wind->getDoubleValue());
break;
}
@ -695,9 +692,9 @@ bool FGJSBsim::copy_to_JSBsim()
break;
}
Atmosphere->SetWindNED( -wind_from_north->getDoubleValue(),
-wind_from_east->getDoubleValue(),
-wind_from_down->getDoubleValue() );
Winds->SetWindNED( -wind_from_north->getDoubleValue(),
-wind_from_east->getDoubleValue(),
-wind_from_down->getDoubleValue() );
// SG_LOG(SG_FLIGHT,SG_INFO, "Wind NED: "
// << get_V_north_airmass() << ", "
// << get_V_east_airmass() << ", "
@ -739,19 +736,19 @@ bool FGJSBsim::copy_from_JSBsim()
MassBalance->GetXYZcg(2),
MassBalance->GetXYZcg(3) );
_set_Accels_Body( Aircraft->GetBodyAccel(1),
Aircraft->GetBodyAccel(2),
Aircraft->GetBodyAccel(3) );
_set_Accels_Body( Accelerations->GetBodyAccel(1),
Accelerations->GetBodyAccel(2),
Accelerations->GetBodyAccel(3) );
_set_Accels_CG_Body_N ( Aircraft->GetNcg(1),
Aircraft->GetNcg(2),
Aircraft->GetNcg(3) );
_set_Accels_CG_Body_N ( Auxiliary->GetNcg(1),
Auxiliary->GetNcg(2),
Auxiliary->GetNcg(3) );
_set_Accels_Pilot_Body( Auxiliary->GetPilotAccel(1),
Auxiliary->GetPilotAccel(2),
Auxiliary->GetPilotAccel(3) );
_set_Nlf( Aircraft->GetNlf() );
_set_Nlf( Auxiliary->GetNlf() );
// Velocities
@ -788,8 +785,8 @@ bool FGJSBsim::copy_from_JSBsim()
// Positions of Visual Reference Point
FGLocation l = Auxiliary->GetLocationVRP();
_updateGeocentricPosition( l.GetLatitude(), l.GetLongitude(),
l.GetRadius() - get_Sea_level_radius() );
_updatePosition(SGGeoc::fromRadFt( l.GetLongitude(), l.GetLatitude(),
l.GetRadius() ));
_set_Altitude_AGL( Propagate->GetDistanceAGL() );
{
@ -812,7 +809,7 @@ bool FGJSBsim::copy_from_JSBsim()
_set_Gamma_vert_rad( Auxiliary->GetGamma() );
_set_Earth_position_angle( Inertial->GetEarthPositionAngle() );
_set_Earth_position_angle( Propagate->GetEarthPositionAngle() );
_set_Climb_Rate( Propagate->Gethdot() );
@ -1009,26 +1006,26 @@ bool FGJSBsim::ToggleDataLogging(bool state)
void FGJSBsim::set_Latitude(double lat)
{
static SGConstPropertyNode_ptr altitude = fgGetNode("/position/altitude-ft");
double alt;
double alt = altitude->getDoubleValue();
double sea_level_radius_meters, lat_geoc;
if ( altitude->getDoubleValue() > -9990 )
alt = altitude->getDoubleValue();
else
alt = 0.0;
if ( alt < -9990 ) alt = 0.0;
SG_LOG(SG_FLIGHT,SG_INFO,"FGJSBsim::set_Latitude: " << lat );
SG_LOG(SG_FLIGHT,SG_INFO," cur alt (ft) = " << alt );
sgGeodToGeoc( lat, alt * SG_FEET_TO_METER,
&sea_level_radius_meters, &lat_geoc );
_set_Sea_level_radius( sea_level_radius_meters * SG_METER_TO_FEET );
double sea_level_radius_ft = sea_level_radius_meters * SG_METER_TO_FEET;
_set_Sea_level_radius( sea_level_radius_ft );
if (needTrim) {
fgic->SetSeaLevelRadiusFtIC( sea_level_radius_meters * SG_METER_TO_FEET );
fgic->SetSeaLevelRadiusFtIC( sea_level_radius_ft );
fgic->SetLatitudeRadIC( lat_geoc );
}
else {
Propagate->SetSeaLevelRadius( sea_level_radius_ft );
Propagate->SetLatitude(lat_geoc);
FGInterface::set_Latitude(lat);
}
@ -1349,7 +1346,7 @@ bool FGJSBsim::update_ground_cache(FGLocation cart, double* cart_pos, double dt)
<< fgic->GetAltitudeASLFtIC());
SG_LOG(SG_FLIGHT, SG_WARN, "sea level radius = "
<< fgic->GetSeaLevelRadiusFtIC());
<< get_Sea_level_radius());
SG_LOG(SG_FLIGHT, SG_WARN, "latitude = "
<< fgic->GetLatitudeRadIC());

View file

@ -58,6 +58,7 @@ FORWARD DECLARATIONS
namespace JSBSim {
class FGAtmosphere;
class FGWinds;
class FGFCS;
class FGPropulsion;
class FGMassBalance;
@ -69,6 +70,7 @@ class FGAuxiliary;
class FGOutput;
class FGInitialCondition;
class FGLocation;
class FGAccelerations;
}
// Adding it here will cause a namespace clash in FlightGear -EMH-
@ -221,16 +223,18 @@ private:
JSBSim::FGInitialCondition *fgic;
bool needTrim;
JSBSim::FGAtmosphere* Atmosphere;
JSBSim::FGFCS* FCS;
JSBSim::FGPropulsion* Propulsion;
JSBSim::FGMassBalance* MassBalance;
JSBSim::FGAircraft* Aircraft;
JSBSim::FGPropagate* Propagate;
JSBSim::FGAuxiliary* Auxiliary;
JSBSim::FGAerodynamics* Aerodynamics;
JSBSim::FGAtmosphere* Atmosphere;
JSBSim::FGWinds* Winds;
JSBSim::FGFCS* FCS;
JSBSim::FGPropulsion* Propulsion;
JSBSim::FGMassBalance* MassBalance;
JSBSim::FGAircraft* Aircraft;
JSBSim::FGPropagate* Propagate;
JSBSim::FGAuxiliary* Auxiliary;
JSBSim::FGAerodynamics* Aerodynamics;
JSBSim::FGGroundReactions* GroundReactions;
JSBSim::FGInertial* Inertial;
JSBSim::FGInertial* Inertial;
JSBSim::FGAccelerations* Accelerations;
int runcount;
double trim_elev;
@ -269,7 +273,7 @@ private:
SGPropertyNode_ptr temperature;
SGPropertyNode_ptr pressure;
SGPropertyNode_ptr density;
SGPropertyNode_ptr pressureSL;
SGPropertyNode_ptr ground_wind;
SGPropertyNode_ptr turbulence_gain;
SGPropertyNode_ptr turbulence_rate;

View file

@ -44,6 +44,10 @@ you have chosen your IC's wisely) even after setting it up with this class.
INCLUDES
*******************************************************************************/
#include <iostream>
#include <fstream>
#include <cstdlib>
#include "FGInitialCondition.h"
#include "FGFDMExec.h"
#include "math/FGQuaternion.h"
@ -51,17 +55,15 @@ INCLUDES
#include "models/FGAtmosphere.h"
#include "models/FGPropagate.h"
#include "models/FGPropulsion.h"
#include "models/FGFCS.h"
#include "input_output/FGPropertyManager.h"
#include "input_output/string_utilities.h"
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGInitialCondition.cpp,v 1.63 2011/06/13 10:30:22 bcoconni Exp $";
static const char *IdSrc = "$Id: FGInitialCondition.cpp,v 1.69 2011/08/04 12:46:32 jberndt Exp $";
static const char *IdHdr = ID_INITIALCONDITION;
//******************************************************************************
@ -134,7 +136,7 @@ void FGInitialCondition::InitializeIC(void)
terrain_elevation = 0;
sea_level_radius = fdmex->GetInertial()->GetRefRadius();
position.SetPosition(0., 0., sea_level_radius);
position.SetEarthPositionAngle(fdmex->GetInertial()->GetEarthPositionAngle());
position.SetEarthPositionAngle(fdmex->GetPropagate()->GetEarthPositionAngle());
vUVW_NED.InitMatrix();
p=q=r=0;
vt=0;
@ -587,8 +589,9 @@ void FGInitialCondition::SetCrossWindKtsIC(double cross)
// Gram-Schmidt process is used to remove the existing cross wind component
_vWIND_NED -= DotProduct(_vWIND_NED, _vCROSS) * _vCROSS;
// which is now replaced by the new value.
_vWIND_NED += cross * _vCROSS;
// Which is now replaced by the new value. The input cross wind is expected
// in knots, so first convert to fps, which is the internal unit used.
_vWIND_NED += (cross * ktstofps) * _vCROSS;
_vt_NED = vUVW_NED + _vWIND_NED;
vt = _vt_NED.Magnitude();
@ -604,13 +607,19 @@ void FGInitialCondition::SetHeadWindKtsIC(double head)
{
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
FGColumnVector3 _vHEAD(cos(psi), sin(psi), 0.);
// This is a head wind, so the direction vector for the wind
// needs to be set opposite to the heading the aircraft
// is taking. So, the cos and sin of the heading (psi)
// are negated in the line below.
FGColumnVector3 _vHEAD(-cos(psi), -sin(psi), 0.);
// Gram-Schmidt process is used to remove the existing head wind component
_vWIND_NED -= DotProduct(_vWIND_NED, _vHEAD) * _vHEAD;
// which is now replaced by the new value.
_vWIND_NED += head * _vHEAD;
// Which is now replaced by the new value. The input head wind is expected
// in knots, so first convert to fps, which is the internal unit used.
_vWIND_NED += (head * ktstofps) * _vHEAD;
_vt_NED = vUVW_NED + _vWIND_NED;
vt = _vt_NED.Magnitude();
calcAeroAngles(_vt_NED);
@ -644,9 +653,9 @@ void FGInitialCondition::SetWindMagKtsIC(double mag)
double windMag = _vHEAD.Magnitude();
if (windMag > 0.001)
_vHEAD *= mag / windMag;
_vHEAD *= (mag*ktstofps) / windMag;
else
_vHEAD = FGColumnVector3(mag, 0., 0.);
_vHEAD = FGColumnVector3((mag*ktstofps), 0., 0.);
_vWIND_NED(eU) = _vHEAD(eU);
_vWIND_NED(eV) = _vHEAD(eV);
@ -1028,7 +1037,7 @@ bool FGInitialCondition::Load_v2(void)
{
FGColumnVector3 vOrient;
bool result = true;
FGColumnVector3 vOmegaEarth = FGColumnVector3(0.0, 0.0, fdmex->GetInertial()->omega());
FGColumnVector3 vOmegaEarth = fdmex->GetInertial()->GetOmegaPlanet();
if (document->FindElement("earth_position_angle"))
position.SetEarthPositionAngle(document->FindElementValueAsNumberConvertTo("earth_position_angle", "RAD"));
@ -1325,10 +1334,6 @@ void FGInitialCondition::bind(void)
&FGInitialCondition::GetAltitudeAGLFtIC,
&FGInitialCondition::SetAltitudeAGLFtIC,
true);
PropertyManager->Tie("ic/sea-level-radius-ft", this,
&FGInitialCondition::GetSeaLevelRadiusFtIC,
&FGInitialCondition::SetSeaLevelRadiusFtIC,
true);
PropertyManager->Tie("ic/terrain-elevation-ft", this,
&FGInitialCondition::GetTerrainElevationFtIC,
&FGInitialCondition::SetTerrainElevationFtIC,

View file

@ -54,7 +54,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_INITIALCONDITION "$Id: FGInitialCondition.h,v 1.27 2011/05/20 00:47:03 bcoconni Exp $"
#define ID_INITIALCONDITION "$Id: FGInitialCondition.h,v 1.28 2011/07/10 19:03:49 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -213,7 +213,7 @@ CLASS DOCUMENTATION
@property ic/r-rad_sec (read/write) Yaw rate initial condition in radians/second
@author Tony Peden
@version "$Id: FGInitialCondition.h,v 1.27 2011/05/20 00:47:03 bcoconni Exp $"
@version "$Id: FGInitialCondition.h,v 1.28 2011/07/10 19:03:49 jberndt Exp $"
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -237,7 +237,7 @@ public:
void SetVequivalentKtsIC(double ve);
/** Set true airspeed initial condition in knots.
@param vt True airspeed in knots */
@param vtrue True airspeed in knots */
void SetVtrueKtsIC(double vtrue) { SetVtrueFpsIC(vtrue*ktstofps); }
/** Set ground speed initial condition in knots.
@ -375,10 +375,6 @@ public:
@return Initial altitude AGL in feet */
double GetAltitudeAGLFtIC(void) const { return position.GetRadius() - sea_level_radius - terrain_elevation; }
/** Gets the initial sea level radius.
@return Initial sea level radius */
double GetSeaLevelRadiusFtIC(void) const { return sea_level_radius; }
/** Gets the initial terrain elevation.
@return Initial terrain elevation in feet */
double GetTerrainElevationFtIC(void) const { return terrain_elevation; }

View file

@ -43,19 +43,20 @@ INCLUDES
#include "models/FGAtmosphere.h"
#include "FGInitialCondition.h"
#include "FGTrimAxis.h"
#include "models/FGAircraft.h"
#include "models/FGPropulsion.h"
#include "models/FGAerodynamics.h"
#include "models/FGFCS.h"
#include "models/propulsion/FGEngine.h"
#include "models/FGAuxiliary.h"
#include "models/FGGroundReactions.h"
#include "models/FGPropagate.h"
#include "models/FGAccelerations.h"
using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGTrimAxis.cpp,v 1.10 2010/07/08 11:36:28 jberndt Exp $";
static const char *IdSrc = "$Id: FGTrimAxis.cpp,v 1.13 2011/07/28 12:48:19 jberndt Exp $";
static const char *IdHdr = ID_TRIMAXIS;
/*****************************************************************************/
@ -167,14 +168,14 @@ FGTrimAxis::~FGTrimAxis(void)
void FGTrimAxis::getState(void) {
switch(state) {
case tUdot: state_value=fdmex->GetPropagate()->GetUVWdot(1)-state_target; break;
case tVdot: state_value=fdmex->GetPropagate()->GetUVWdot(2)-state_target; break;
case tWdot: state_value=fdmex->GetPropagate()->GetUVWdot(3)-state_target; break;
case tQdot: state_value=fdmex->GetPropagate()->GetPQRdot(2)-state_target;break;
case tPdot: state_value=fdmex->GetPropagate()->GetPQRdot(1)-state_target; break;
case tRdot: state_value=fdmex->GetPropagate()->GetPQRdot(3)-state_target; break;
case tUdot: state_value=fdmex->GetAccelerations()->GetUVWdot(1)-state_target; break;
case tVdot: state_value=fdmex->GetAccelerations()->GetUVWdot(2)-state_target; break;
case tWdot: state_value=fdmex->GetAccelerations()->GetUVWdot(3)-state_target; break;
case tQdot: state_value=fdmex->GetAccelerations()->GetPQRdot(2)-state_target;break;
case tPdot: state_value=fdmex->GetAccelerations()->GetPQRdot(1)-state_target; break;
case tRdot: state_value=fdmex->GetAccelerations()->GetPQRdot(3)-state_target; break;
case tHmgt: state_value=computeHmgt()-state_target; break;
case tNlf: state_value=fdmex->GetAircraft()->GetNlf()-state_target; break;
case tNlf: state_value=fdmex->GetAuxiliary()->GetNlf()-state_target; break;
case tAll: break;
}
}
@ -423,9 +424,12 @@ void FGTrimAxis::setThrottlesPct(void) {
for(unsigned i=0;i<fdmex->GetPropulsion()->GetNumEngines();i++) {
tMin=fdmex->GetPropulsion()->GetEngine(i)->GetThrottleMin();
tMax=fdmex->GetPropulsion()->GetEngine(i)->GetThrottleMax();
//cout << "setThrottlespct: " << i << ", " << control_min << ", " << control_max << ", " << control_value;
// Both the main throttle setting in FGFCS and the copy of the position
// in the Propulsion::Inputs structure need to be set at this time.
fdmex->GetFCS()->SetThrottleCmd(i,tMin+control_value*(tMax-tMin));
//cout << "setThrottlespct: " << fdmex->GetFCS()->GetThrottleCmd(i) << endl;
fdmex->GetPropulsion()->in.ThrottlePos[i] = tMin +control_value*(tMax - tMin);
fdmex->RunIC(); //apply throttle change
fdmex->GetPropulsion()->GetSteadyState();
}

0
src/FDM/JSBSim/input_output/FGPropertyManager.cpp Executable file → Normal file
View file

18
src/FDM/JSBSim/input_output/FGScript.cpp Executable file → Normal file
View file

@ -41,20 +41,21 @@ COMMENTS, REFERENCES, and NOTES
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include "FGScript.h"
#include "input_output/FGXMLElement.h"
#include "input_output/FGXMLParse.h"
#include "initialization/FGTrim.h"
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include "models/FGInput.h"
using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGScript.cpp,v 1.46 2011/02/18 12:44:16 jberndt Exp $";
static const char *IdSrc = "$Id: FGScript.cpp,v 1.48 2011/09/07 02:36:04 jberndt Exp $";
static const char *IdHdr = ID_FGSCRIPT;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -379,7 +380,12 @@ bool FGScript::RunScript(void)
for (i=0; i<Events[ev_ctr].SetValue.size(); i++) {
Events[ev_ctr].OriginalValue[i] = Events[ev_ctr].SetParam[i]->getDoubleValue();
if (Events[ev_ctr].Functions[i] != 0) { // Parameter should be set to a function value
Events[ev_ctr].SetValue[i] = Events[ev_ctr].Functions[i]->GetValue();
try {
Events[ev_ctr].SetValue[i] = Events[ev_ctr].Functions[i]->GetValue();
} catch (string msg) {
std::cerr << std::endl << "A problem occurred in the execution of the script. " << msg << endl;
throw;
}
}
switch (Events[ev_ctr].Type[i]) {
case FG_VALUE:

View file

@ -37,18 +37,19 @@ SENTRY
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGJSBBase.h"
#include <vector>
#include "FGFDMExec.h"
#include "FGJSBBase.h"
#include "math/FGFunction.h"
#include "math/FGCondition.h"
#include <vector>
#include "input_output/FGXMLFileRead.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_FGSCRIPT "$Id: FGScript.h,v 1.20 2011/02/11 12:43:28 jberndt Exp $"
#define ID_FGSCRIPT "$Id: FGScript.h,v 1.21 2011/08/04 12:46:32 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -157,7 +158,7 @@ CLASS DOCUMENTATION
comes the &quot;run&quot; section, where the conditions are
described in &quot;event&quot; clauses.</p>
@author Jon S. Berndt
@version "$Id: FGScript.h,v 1.20 2011/02/11 12:43:28 jberndt Exp $"
@version "$Id: FGScript.h,v 1.21 2011/08/04 12:46:32 jberndt Exp $"
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

6
src/FDM/JSBSim/input_output/FGXMLElement.cpp Executable file → Normal file
View file

@ -42,7 +42,7 @@ FORWARD DECLARATIONS
namespace JSBSim {
static const char *IdSrc = "$Id: FGXMLElement.cpp,v 1.32 2011/02/13 00:42:45 jberndt Exp $";
static const char *IdSrc = "$Id: FGXMLElement.cpp,v 1.33 2011/08/05 12:28:20 jberndt Exp $";
static const char *IdHdr = ID_XMLELEMENT;
bool Element::converterIsInitialized = false;
@ -64,6 +64,8 @@ Element::Element(const string& nm)
// Length
convert["M"]["FT"] = 3.2808399;
convert["FT"]["M"] = 1.0/convert["M"]["FT"];
convert["CM"]["FT"] = 0.032808399;
convert["FT"]["CM"] = 1.0/convert["CM"]["FT"];
convert["KM"]["FT"] = 3280.8399;
convert["FT"]["KM"] = 1.0/convert["KM"]["FT"];
convert["FT"]["IN"] = 12.0;
@ -73,6 +75,8 @@ Element::Element(const string& nm)
// Area
convert["M2"]["FT2"] = convert["M"]["FT"]*convert["M"]["FT"];
convert["FT2"]["M2"] = 1.0/convert["M2"]["FT2"];
convert["CM2"]["FT2"] = convert["CM"]["FT"]*convert["CM"]["FT"];
convert["FT2"]["CM2"] = 1.0/convert["CM2"]["FT2"];
convert["M2"]["IN2"] = convert["M"]["IN"]*convert["M"]["IN"];
convert["IN2"]["M2"] = 1.0/convert["M2"]["IN2"];
convert["FT2"]["IN2"] = 144.0;

412
src/FDM/JSBSim/math/FGFunction.cpp Executable file → Normal file
View file

@ -43,13 +43,65 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGFunction.cpp,v 1.36 2011/04/05 20:20:21 andgi Exp $";
static const char *IdSrc = "$Id: FGFunction.cpp,v 1.42 2011/09/07 02:36:04 jberndt Exp $";
static const char *IdHdr = ID_FUNCTION;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
const std::string FGFunction::property_string = "property";
const std::string FGFunction::value_string = "value";
const std::string FGFunction::table_string = "table";
const std::string FGFunction::p_string = "p";
const std::string FGFunction::v_string = "v";
const std::string FGFunction::t_string = "t";
const std::string FGFunction::function_string = "function";
const std::string FGFunction::description_string = "description";
const std::string FGFunction::sum_string = "sum";
const std::string FGFunction::difference_string = "difference";
const std::string FGFunction::product_string = "product";
const std::string FGFunction::quotient_string = "quotient";
const std::string FGFunction::pow_string = "pow";
const std::string FGFunction::exp_string = "exp";
const std::string FGFunction::log2_string = "log2";
const std::string FGFunction::ln_string = "ln";
const std::string FGFunction::log10_string = "log10";
const std::string FGFunction::abs_string = "abs";
const std::string FGFunction::sign_string = "sign";
const std::string FGFunction::sin_string = "sin";
const std::string FGFunction::cos_string = "cos";
const std::string FGFunction::tan_string = "tan";
const std::string FGFunction::asin_string = "asin";
const std::string FGFunction::acos_string = "acos";
const std::string FGFunction::atan_string = "atan";
const std::string FGFunction::atan2_string = "atan2";
const std::string FGFunction::min_string = "min";
const std::string FGFunction::max_string = "max";
const std::string FGFunction::avg_string = "avg";
const std::string FGFunction::fraction_string = "fraction";
const std::string FGFunction::mod_string = "mod";
const std::string FGFunction::random_string = "random";
const std::string FGFunction::integer_string = "integer";
const std::string FGFunction::rotation_alpha_local_string = "rotation_alpha_local";
const std::string FGFunction::rotation_beta_local_string = "rotation_beta_local";
const std::string FGFunction::rotation_gamma_local_string = "rotation_gamma_local";
const std::string FGFunction::rotation_bf_to_wf_string = "rotation_bf_to_wf";
const std::string FGFunction::rotation_wf_to_bf_string = "rotation_wf_to_bf";
const std::string FGFunction::lessthan_string = "lt";
const std::string FGFunction::lessequal_string = "le";
const std::string FGFunction::greatthan_string = "gt";
const std::string FGFunction::greatequal_string = "ge";
const std::string FGFunction::equal_string = "eq";
const std::string FGFunction::notequal_string = "nq";
const std::string FGFunction::and_string = "and";
const std::string FGFunction::or_string = "or";
const std::string FGFunction::not_string = "not";
const std::string FGFunction::ifthen_string = "ifthen";
const std::string FGFunction::switch_string = "switch";
FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& prefix)
: PropertyManager(propMan), Prefix(prefix)
{
@ -59,40 +111,6 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
cachedValue = -HUGE_VAL;
invlog2val = 1.0/log10(2.0);
property_string = "property";
value_string = "value";
table_string = "table";
p_string = "p";
v_string = "v";
t_string = "t";
function_string = "function";
description_string = "description";
sum_string = "sum";
difference_string = "difference";
product_string = "product";
quotient_string = "quotient";
pow_string = "pow";
exp_string = "exp";
log2_string = "log2";
ln_string = "ln";
log10_string = "log10";
abs_string = "abs";
sin_string = "sin";
cos_string = "cos";
tan_string = "tan";
asin_string = "asin";
acos_string = "acos";
atan_string = "atan";
atan2_string = "atan2";
min_string = "min";
max_string = "max";
avg_string = "avg";
fraction_string = "fraction";
mod_string = "mod";
random_string = "random";
integer_string = "integer";
Name = el->GetAttributeValue("name");
operation = el->GetName();
@ -116,6 +134,8 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
Type = eLog10;
} else if (operation == abs_string) {
Type = eAbs;
} else if (operation == sign_string) {
Type = eSign;
} else if (operation == sin_string) {
Type = eSin;
} else if (operation == exp_string) {
@ -146,6 +166,38 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
Type = eMod;
} else if (operation == random_string) {
Type = eRandom;
} else if (operation == rotation_alpha_local_string) {
Type = eRotation_alpha_local;
} else if (operation == rotation_beta_local_string) {
Type = eRotation_beta_local;
} else if (operation == rotation_gamma_local_string) {
Type = eRotation_gamma_local;
} else if (operation == rotation_bf_to_wf_string) {
Type = eRotation_bf_to_wf;
} else if (operation == rotation_wf_to_bf_string) {
Type = eRotation_wf_to_bf;
} else if (operation == lessthan_string) {
Type = eLT;
} else if (operation == lessequal_string) {
Type = eLE;
} else if (operation == greatthan_string) {
Type = eGT;
} else if (operation == greatequal_string) {
Type = eGE;
} else if (operation == equal_string) {
Type = eEQ;
} else if (operation == notequal_string) {
Type = eNE;
} else if (operation == and_string) {
Type = eAND;
} else if (operation == or_string) {
Type = eOR;
} else if (operation == not_string) {
Type = eNOT;
} else if (operation == ifthen_string) {
Type = eIfThen;
} else if (operation == switch_string) {
Type = eSwitch;
} else if (operation != description_string) {
cerr << "Bad operation " << operation << " detected in configuration file" << endl;
}
@ -197,6 +249,7 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
operation == ln_string ||
operation == log10_string ||
operation == abs_string ||
operation == sign_string ||
operation == sin_string ||
operation == cos_string ||
operation == tan_string ||
@ -210,7 +263,23 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
operation == integer_string ||
operation == mod_string ||
operation == random_string ||
operation == avg_string )
operation == avg_string ||
operation == rotation_alpha_local_string||
operation == rotation_beta_local_string||
operation == rotation_gamma_local_string||
operation == rotation_bf_to_wf_string||
operation == rotation_wf_to_bf_string ||
operation == lessthan_string ||
operation == lessequal_string ||
operation == greatthan_string ||
operation == greatequal_string ||
operation == equal_string ||
operation == notequal_string ||
operation == and_string ||
operation == or_string ||
operation == not_string ||
operation == ifthen_string ||
operation == switch_string)
{
Parameters.push_back(new FGFunction(PropertyManager, element, Prefix));
} else if (operation != description_string) {
@ -245,6 +314,18 @@ void FGFunction::cacheValue(bool cache)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
unsigned int FGFunction::GetBinary(double val) const
{
val = fabs(val);
if (val < 1E-9) return 0;
else if (val-1 < 1E-9) return 1;
else {
throw("Malformed conditional check in function definition.");
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGFunction::GetValue(void) const
{
unsigned int i;
@ -300,6 +381,9 @@ double FGFunction::GetValue(void) const
case eAbs:
temp = fabs(temp);
break;
case eSign:
temp = temp < 0 ? -1:1; // 0.0 counts as positive.
break;
case eSin:
temp = sin(temp);
break;
@ -350,6 +434,262 @@ double FGFunction::GetValue(void) const
case eRandom:
temp = GaussianRandomNumber();
break;
case eLT:
temp = (temp < Parameters[1]->GetValue())?1:0;
break;
case eLE:
temp = (temp <= Parameters[1]->GetValue())?1:0;
break;
case eGT:
temp = (temp > Parameters[1]->GetValue())?1:0;
break;
case eGE:
temp = (temp >= Parameters[1]->GetValue())?1:0;
break;
case eEQ:
temp = (temp == Parameters[1]->GetValue())?1:0;
break;
case eNE:
temp = (temp != Parameters[1]->GetValue())?1:0;
break;
case eAND:
{
bool flag = (GetBinary(temp) != 0u);
for (i=1; i<Parameters.size() && flag; i++) {
flag = (GetBinary(Parameters[i]->GetValue()) != 0);
}
temp = flag ? 1 : 0;
}
break;
case eOR:
{
bool flag = (GetBinary(temp) != 0);
for (i=1; i<Parameters.size() && !flag; i++) {
flag = (GetBinary(Parameters[i]->GetValue()) != 0);
}
temp = flag ? 1 : 0;
}
break;
case eNOT:
temp = (GetBinary(temp) != 0) ? 0 : 1;
break;
case eIfThen:
{
i = Parameters.size();
if (i != 3) {
if (GetBinary(temp) == 1) {
temp = Parameters[1]->GetValue();
} else {
temp = Parameters[2]->GetValue();
}
} else {
throw("Malformed if/then function statement");
}
}
break;
case eSwitch:
{
unsigned int n = Parameters.size()-1;
i = int(temp+0.5);
if (i >= 0u && i < n) {
temp = Parameters[i+1]->GetValue();
} else {
throw(string("The switch function index selected a value above the range of supplied values"
" - not enough values were supplied."));
}
}
break;
case eRotation_alpha_local:
if (Parameters.size()==6) // calculates local angle of attack for skydiver body component
//Euler angles from the intermediate body frame to the local body frame must be from a z-y-x axis rotation order
{
double alpha = Parameters[0]->GetValue()*degtorad;
double beta = Parameters[1]->GetValue()*degtorad;
double gamma = Parameters[2]->GetValue()*degtorad;
double phi = Parameters[3]->GetValue()*degtorad;
double theta = Parameters[4]->GetValue()*degtorad;
double psi = Parameters[5]->GetValue()*degtorad;
double cphi2 = cos(-phi/2), ctht2 = cos(-theta/2), cpsi2 = cos(-psi/2);
double sphi2 = sin(-phi/2), stht2 = sin(-theta/2), spsi2 = sin(-psi/2);
double calpha2 = cos(-alpha/2), salpha2 = sin(-alpha/2);
double cbeta2 = cos(beta/2), sbeta2 = sin(beta/2);
double cgamma2 = cos(-gamma/2), sgamma2 = sin(-gamma/2);
//calculate local body frame to the intermediate body frame rotation quaternion
double At = cphi2*ctht2*cpsi2 - sphi2*stht2*spsi2;
double Ax = cphi2*stht2*spsi2 + sphi2*ctht2*cpsi2;
double Ay = cphi2*stht2*cpsi2 - sphi2*ctht2*spsi2;
double Az = cphi2*ctht2*spsi2 + sphi2*stht2*cpsi2;
//calculate the intermediate body frame to global wind frame rotation quaternion
double Bt = calpha2*cbeta2*cgamma2 - salpha2*sbeta2*sgamma2;
double Bx = calpha2*cbeta2*sgamma2 + salpha2*sbeta2*cgamma2;
double By = calpha2*sbeta2*sgamma2 + salpha2*cbeta2*cgamma2;
double Bz = calpha2*sbeta2*cgamma2 - salpha2*cbeta2*sgamma2;
//multiply quaternions
double Ct = At*Bt - Ax*Bx - Ay*By - Az*Bz;
double Cx = At*Bx + Ax*Bt + Ay*Bz - Az*By;
double Cy = At*By - Ax*Bz + Ay*Bt + Az*Bx;
double Cz = At*Bz + Ax*By - Ay*Bx + Az*Bt;
//calculate alpha_local
temp = -atan2(2*(Cy*Ct-Cx*Cz),(Ct*Ct+Cx*Cx-Cy*Cy-Cz*Cz));
temp *= radtodeg;
} else {
temp = 1;
}
break;
case eRotation_beta_local:
if (Parameters.size()==6) // calculates local angle of sideslip for skydiver body component
//Euler angles from the intermediate body frame to the local body frame must be from a z-y-x axis rotation order
{
double alpha = Parameters[0]->GetValue()*degtorad; //angle of attack of intermediate body frame
double beta = Parameters[1]->GetValue()*degtorad; //sideslip angle of intermediate body frame
double gamma = Parameters[2]->GetValue()*degtorad; //roll angle of intermediate body frame
double phi = Parameters[3]->GetValue()*degtorad; //x-axis Euler angle from the intermediate body frame to the local body frame
double theta = Parameters[4]->GetValue()*degtorad; //y-axis Euler angle from the intermediate body frame to the local body frame
double psi = Parameters[5]->GetValue()*degtorad; //z-axis Euler angle from the intermediate body frame to the local body frame
double cphi2 = cos(-phi/2), ctht2 = cos(-theta/2), cpsi2 = cos(-psi/2);
double sphi2 = sin(-phi/2), stht2 = sin(-theta/2), spsi2 = sin(-psi/2);
double calpha2 = cos(-alpha/2), salpha2 = sin(-alpha/2);
double cbeta2 = cos(beta/2), sbeta2 = sin(beta/2);
double cgamma2 = cos(-gamma/2), sgamma2 = sin(-gamma/2);
//calculate local body frame to the intermediate body frame rotation quaternion
double At = cphi2*ctht2*cpsi2 - sphi2*stht2*spsi2;
double Ax = cphi2*stht2*spsi2 + sphi2*ctht2*cpsi2;
double Ay = cphi2*stht2*cpsi2 - sphi2*ctht2*spsi2;
double Az = cphi2*ctht2*spsi2 + sphi2*stht2*cpsi2;
//calculate the intermediate body frame to global wind frame rotation quaternion
double Bt = calpha2*cbeta2*cgamma2 - salpha2*sbeta2*sgamma2;
double Bx = calpha2*cbeta2*sgamma2 + salpha2*sbeta2*cgamma2;
double By = calpha2*sbeta2*sgamma2 + salpha2*cbeta2*cgamma2;
double Bz = calpha2*sbeta2*cgamma2 - salpha2*cbeta2*sgamma2;
//multiply quaternions
double Ct = At*Bt - Ax*Bx - Ay*By - Az*Bz;
double Cx = At*Bx + Ax*Bt + Ay*Bz - Az*By;
double Cy = At*By - Ax*Bz + Ay*Bt + Az*Bx;
double Cz = At*Bz + Ax*By - Ay*Bx + Az*Bt;
//calculate beta_local
temp = asin(2*(Cx*Cy+Cz*Ct));
temp *= radtodeg;
}
else //
{temp = 1;}
break;
case eRotation_gamma_local:
if (Parameters.size()==6) // calculates local angle of attack for skydiver body component
//Euler angles from the intermediate body frame to the local body frame must be from a z-y-x axis rotation order
{
double alpha = Parameters[0]->GetValue()*degtorad; //angle of attack of intermediate body frame
double beta = Parameters[1]->GetValue()*degtorad; //sideslip angle of intermediate body frame
double gamma = Parameters[2]->GetValue()*degtorad; //roll angle of intermediate body frame
double phi = Parameters[3]->GetValue()*degtorad; //x-axis Euler angle from the intermediate body frame to the local body frame
double theta = Parameters[4]->GetValue()*degtorad; //y-axis Euler angle from the intermediate body frame to the local body frame
double psi = Parameters[5]->GetValue()*degtorad; //z-axis Euler angle from the intermediate body frame to the local body frame
double cphi2 = cos(-phi/2), ctht2 = cos(-theta/2), cpsi2 = cos(-psi/2);
double sphi2 = sin(-phi/2), stht2 = sin(-theta/2), spsi2 = sin(-psi/2);
double calpha2 = cos(-alpha/2), salpha2 = sin(-alpha/2);
double cbeta2 = cos(beta/2), sbeta2 = sin(beta/2);
double cgamma2 = cos(-gamma/2), sgamma2 = sin(-gamma/2);
//calculate local body frame to the intermediate body frame rotation quaternion
double At = cphi2*ctht2*cpsi2 - sphi2*stht2*spsi2;
double Ax = cphi2*stht2*spsi2 + sphi2*ctht2*cpsi2;
double Ay = cphi2*stht2*cpsi2 - sphi2*ctht2*spsi2;
double Az = cphi2*ctht2*spsi2 + sphi2*stht2*cpsi2;
//calculate the intermediate body frame to global wind frame rotation quaternion
double Bt = calpha2*cbeta2*cgamma2 - salpha2*sbeta2*sgamma2;
double Bx = calpha2*cbeta2*sgamma2 + salpha2*sbeta2*cgamma2;
double By = calpha2*sbeta2*sgamma2 + salpha2*cbeta2*cgamma2;
double Bz = calpha2*sbeta2*cgamma2 - salpha2*cbeta2*sgamma2;
//multiply quaternions
double Ct = At*Bt - Ax*Bx - Ay*By - Az*Bz;
double Cx = At*Bx + Ax*Bt + Ay*Bz - Az*By;
double Cy = At*By - Ax*Bz + Ay*Bt + Az*Bx;
double Cz = At*Bz + Ax*By - Ay*Bx + Az*Bt;
//calculate local roll anlge
temp = -atan2(2*(Cx*Ct-Cz*Cy),(Ct*Ct-Cx*Cx+Cy*Cy-Cz*Cz));
temp *= radtodeg;
}
else //
{temp = 1;}
break;
case eRotation_bf_to_wf:
if (Parameters.size()==7) // transforms the input vector from a body frame to a wind frame. The origin of the vector remains the same.
{
double rx = Parameters[0]->GetValue(); //x component of input vector
double ry = Parameters[1]->GetValue(); //y component of input vector
double rz = Parameters[2]->GetValue(); //z component of input vector
double alpha = Parameters[3]->GetValue()*degtorad; //angle of attack of the body frame
double beta = Parameters[4]->GetValue()*degtorad; //sideslip angle of the body frame
double gamma = Parameters[5]->GetValue()*degtorad; //roll angle of the body frame
double index = Parameters[6]->GetValue();
double calpha2 = cos(-alpha/2), salpha2 = sin(-alpha/2);
double cbeta2 = cos(beta/2), sbeta2 = sin(beta/2);
double cgamma2 = cos(-gamma/2), sgamma2 = sin(-gamma/2);
//calculate the body frame to wind frame quaternion
double qt = calpha2*cbeta2*cgamma2 - salpha2*sbeta2*sgamma2;
double qx = calpha2*cbeta2*sgamma2 + salpha2*sbeta2*cgamma2;
double qy = calpha2*sbeta2*sgamma2 + salpha2*cbeta2*cgamma2;
double qz = calpha2*sbeta2*cgamma2 - salpha2*cbeta2*sgamma2;
//calculate the quaternion conjugate
double qstart = qt;
double qstarx = -qx;
double qstary = -qy;
double qstarz = -qz;
//multiply quaternions v*q
double vqt = -rx*qx - ry*qy - rz*qz;
double vqx = rx*qt + ry*qz - rz*qy;
double vqy = -rx*qz + ry*qt + rz*qx;
double vqz = rx*qy - ry*qx + rz*qt;
//multiply quaternions qstar*vq
double Cx = qstart*vqx + qstarx*vqt + qstary*vqz - qstarz*vqy;
double Cy = qstart*vqy - qstarx*vqz + qstary*vqt + qstarz*vqx;
double Cz = qstart*vqz + qstarx*vqy - qstary*vqx + qstarz*vqt;
if (index == 1) temp = Cx;
else if (index ==2) temp = Cy;
else temp = Cz;
}
else //
{temp = 1;}
break;
case eRotation_wf_to_bf:
if (Parameters.size()==7) // transforms the input vector from q wind frame to a body frame. The origin of the vector remains the same.
{
double rx = Parameters[0]->GetValue(); //x component of input vector
double ry = Parameters[1]->GetValue(); //y component of input vector
double rz = Parameters[2]->GetValue(); //z component of input vector
double alpha = Parameters[3]->GetValue()*degtorad; //angle of attack of the body frame
double beta = Parameters[4]->GetValue()*degtorad; //sideslip angle of the body frame
double gamma = Parameters[5]->GetValue()*degtorad; //roll angle of the body frame
double index = Parameters[6]->GetValue();
double calpha2 = cos(alpha/2), salpha2 = sin(alpha/2);
double cbeta2 = cos(-beta/2), sbeta2 = sin(-beta/2);
double cgamma2 = cos(gamma/2), sgamma2 = sin(gamma/2);
//calculate the wind frame to body frame quaternion
double qt = cgamma2*cbeta2*calpha2 + sgamma2*sbeta2*salpha2;
double qx = -cgamma2*sbeta2*salpha2 + sgamma2*cbeta2*calpha2;
double qy = cgamma2*cbeta2*salpha2 - sgamma2*sbeta2*calpha2;
double qz = cgamma2*sbeta2*calpha2 + sgamma2*cbeta2*salpha2;
//calculate the quaternion conjugate
double qstart = qt;
double qstarx = -qx;
double qstary = -qy;
double qstarz = -qz;
//multiply quaternions v*q
double vqt = -rx*qx - ry*qy - rz*qz;
double vqx = rx*qt + ry*qz - rz*qy;
double vqy = -rx*qz + ry*qt + rz*qx;
double vqz = rx*qy - ry*qx + rz*qt;
//multiply quaternions qstar*vq
double Cx = qstart*vqx + qstarx*vqt + qstary*vqz - qstarz*vqy;
double Cy = qstart*vqy - qstarx*vqz + qstary*vqt + qstarz*vqx;
double Cz = qstart*vqz + qstarx*vqy - qstary*vqx + qstarz*vqt;
if (index == 1) temp = Cx;
else if (index ==2) temp = Cy;
else temp = Cz;
}
else //
{temp = 1;}
break;
default:
cerr << "Unknown function operation type" << endl;
break;

View file

@ -42,7 +42,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_FUNCTION "$Id: FGFunction.h,v 1.21 2009/11/18 04:49:02 jberndt Exp $"
#define ID_FUNCTION "$Id: FGFunction.h,v 1.24 2011/08/06 13:10:00 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -86,6 +86,17 @@ A function definition consists of an operation, a value, a table, or a property
- avg (takes n args)
- fraction
- mod
- lt (less than, takes 2 args)
- le (less equal, takes 2 args)
- gt (greater than, takes 2 args)
- ge (greater than, takes 2 args)
- eq (equal, takes 2 args)
- nq (not equal, takes 2 args)
- and (takes n args)
- or (takes n args)
- not (takes 1 args)
- if-then (takes 2-3 args)
- switch (takes 2 or more args)
- random (Gaussian random number)
- integer
@ -198,43 +209,65 @@ private:
bool cached;
double invlog2val;
std::string Prefix;
std::string description_string;
std::string property_string;
std::string value_string;
std::string table_string;
std::string p_string;
std::string v_string;
std::string t_string;
std::string function_string;
std::string sum_string;
std::string difference_string;
std::string product_string;
std::string quotient_string;
std::string pow_string;
std::string exp_string;
std::string log2_string;
std::string ln_string;
std::string log10_string;
std::string abs_string;
std::string sin_string;
std::string cos_string;
std::string tan_string;
std::string asin_string;
std::string acos_string;
std::string atan_string;
std::string atan2_string;
std::string min_string;
std::string max_string;
std::string avg_string;
std::string fraction_string;
std::string mod_string;
std::string random_string;
std::string integer_string;
static const std::string description_string;
static const std::string property_string;
static const std::string value_string;
static const std::string table_string;
static const std::string p_string;
static const std::string v_string;
static const std::string t_string;
static const std::string function_string;
static const std::string sum_string;
static const std::string difference_string;
static const std::string product_string;
static const std::string quotient_string;
static const std::string pow_string;
static const std::string exp_string;
static const std::string log2_string;
static const std::string ln_string;
static const std::string log10_string;
static const std::string abs_string;
static const std::string sign_string;
static const std::string sin_string;
static const std::string cos_string;
static const std::string tan_string;
static const std::string asin_string;
static const std::string acos_string;
static const std::string atan_string;
static const std::string atan2_string;
static const std::string min_string;
static const std::string max_string;
static const std::string avg_string;
static const std::string fraction_string;
static const std::string mod_string;
static const std::string random_string;
static const std::string integer_string;
static const std::string rotation_alpha_local_string;
static const std::string rotation_beta_local_string;
static const std::string rotation_gamma_local_string;
static const std::string rotation_bf_to_wf_string;
static const std::string rotation_wf_to_bf_string;
static const std::string lessthan_string;
static const std::string lessequal_string;
static const std::string greatthan_string;
static const std::string greatequal_string;
static const std::string equal_string;
static const std::string notequal_string;
static const std::string and_string;
static const std::string or_string;
static const std::string not_string;
static const std::string ifthen_string;
static const std::string switch_string;
double cachedValue;
enum functionType {eTopLevel=0, eProduct, eDifference, eSum, eQuotient, ePow,
eExp, eAbs, eSin, eCos, eTan, eASin, eACos, eATan, eATan2,
eMin, eMax, eAvg, eFrac, eInteger, eMod, eRandom, eLog2, eLn, eLog10} Type;
eExp, eAbs, eSign, eSin, eCos, eTan, eASin, eACos, eATan, eATan2,
eMin, eMax, eAvg, eFrac, eInteger, eMod, eRandom, eLog2, eLn,
eLog10, eLT, eLE, eGE, eGT, eEQ, eNE, eAND, eOR, eNOT,
eIfThen, eSwitch, eRotation_alpha_local, eRotation_beta_local,
eRotation_gamma_local, eRotation_bf_to_wf, eRotation_wf_to_bf} Type;
std::string Name;
unsigned int GetBinary(double) const;
void bind(void);
void Debug(int from);
};

View file

@ -48,7 +48,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_LOCATION "$Id: FGLocation.h,v 1.27 2010/11/29 12:33:58 jberndt Exp $"
#define ID_LOCATION "$Id: FGLocation.h,v 1.28 2011/08/04 12:46:32 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -142,7 +142,7 @@ CLASS DOCUMENTATION
@see W. C. Durham "Aircraft Dynamics & Control", section 2.2
@author Mathias Froehlich
@version $Id: FGLocation.h,v 1.27 2010/11/29 12:33:58 jberndt Exp $
@version $Id: FGLocation.h,v 1.28 2011/08/04 12:46:32 jberndt Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -229,6 +229,13 @@ public:
respect to the Inertial (ECI) frame in radians. */
void SetEarthPositionAngle(double EPA) {epa = EPA; mCacheValid = false;}
/** Increments the Earth position angle.
This is the relative orientation of the ECEF frame with respect to the
Inertial frame.
@param delta delta to the Earth fixed frame (ECEF) rotation offset about the axis with
respect to the Inertial (ECI) frame in radians. */
void IncrementEarthPositionAngle(double delta) {epa += delta; mCacheValid = false;}
/** Get the longitude.
@return the longitude in rad of the location represented with this
class instance. The returned values are in the range between
@ -290,6 +297,8 @@ public:
return -mTec2l(3,3)/cLat;
}
double GetEPA() const {return epa;}
/** Get the distance from the center of the earth.
@return the distance of the location represented with this class
instance to the center of the earth in ft. The radius value is

View file

@ -44,7 +44,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_MODELFUNCTIONS "$Id: FGModelFunctions.h,v 1.3 2010/11/17 03:18:37 jberndt Exp $"
#define ID_MODELFUNCTIONS "$Id: FGModelFunctions.h,v 1.4 2011/06/21 04:41:54 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -76,7 +76,7 @@ DECLARATION: FGModelFunctions
class FGModelFunctions : public FGJSBBase
{
public:
~FGModelFunctions();
virtual ~FGModelFunctions();
void RunPreFunctions(void);
void RunPostFunctions(void);
bool Load(Element* el, FGPropertyManager* PropertyManager, std::string prefix="");

0
src/FDM/JSBSim/math/FGParameter.h Executable file → Normal file
View file

0
src/FDM/JSBSim/math/FGPropertyValue.cpp Executable file → Normal file
View file

0
src/FDM/JSBSim/math/FGPropertyValue.h Executable file → Normal file
View file

View file

@ -1,10 +1,10 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGGradient.h
Author:
Date started:
Header: LaGrangeMultiplier.h
Author: Bertrand Coconnier
Date started: 07/01/11
------------- Copyright (C) -------------
------------- Copyright (C) 2011 Bertrand Coconnier -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
@ -23,28 +23,22 @@
Further information about the GNU Lesser General Public License can also be found on
the world wide web at http://www.gnu.org.
HISTORY
--------------------------------------------------------------------------------
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifndef FGGRADIENT_H
#define FGGRADIENT_H
#ifndef LAGRANGEMULTIPLIER_H
#define LAGRANGEMULTIPLIER_H
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFCSComponent.h"
#include "input_output/FGXMLElement.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_GRADIENT "$Id: FGGradient.h,v 1.5 2009/10/02 10:30:09 jberndt Exp $"
#define ID_LAGRANGEMULTIPLIER "$Id: LagrangeMultiplier.h,v 1.2 2011/08/21 15:13:22 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -52,29 +46,22 @@ FORWARD DECLARATIONS
namespace JSBSim {
class FGFCS;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Encapsulates a gradient component for the flight control system.
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGGradient : public FGFCSComponent
{
public:
FGGradient(FGFCS* fcs, Element* element);
~FGGradient();
bool Run (void);
private:
void Debug(int from);
struct LagrangeMultiplier {
FGColumnVector3 ForceJacobian;
FGColumnVector3 MomentJacobian;
double Min;
double Max;
double value;
};
}
} // namespace
#endif

View file

@ -6,6 +6,6 @@ libMath_a_SOURCES = FGColumnVector3.cpp FGFunction.cpp FGLocation.cpp FGMatrix33
noinst_HEADERS = FGColumnVector3.h FGFunction.h FGLocation.h FGMatrix33.h \
FGParameter.h FGPropertyValue.h FGQuaternion.h FGRealValue.h FGTable.h \
FGCondition.h FGRungeKutta.h FGModelFunctions.h
FGCondition.h FGRungeKutta.h FGModelFunctions.h LagrangeMultiplier.h
INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim

View file

@ -0,0 +1,397 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Module: FGAccelerations.cpp
Author: Jon S. Berndt
Date started: 07/12/11
Purpose: Calculates derivatives of rotational and translational rates, and
of the attitude quaternion.
Called by: FGFDMExec
------------- Copyright (C) 2011 Jon S. Berndt (jon@jsbsim.org) -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser 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 Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU Lesser General Public License can also be found on
the world wide web at http://www.gnu.org.
FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------
This class encapsulates the calculation of the derivatives of the state vectors
UVW and PQR - the translational and rotational rates relative to the planet
fixed frame. The derivatives relative to the inertial frame are also calculated
as a side effect. Also, the derivative of the attitude quaterion is also calculated.
HISTORY
--------------------------------------------------------------------------------
07/12/11 JSB Created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
COMMENTS, REFERENCES, and NOTES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[1] Stevens and Lewis, "Aircraft Control and Simulation", Second edition (2004)
Wiley
[2] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
NASA-Ames", NASA CR-2497, January 1975
[3] Erin Catto, "Iterative Dynamics with Temporal Coherence", February 22, 2005
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGAccelerations.h"
#include "FGFDMExec.h"
#include "input_output/FGPropertyManager.h"
using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGAccelerations.cpp,v 1.8 2011/08/30 20:49:04 bcoconni Exp $";
static const char *IdHdr = ID_ACCELERATIONS;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGAccelerations::FGAccelerations(FGFDMExec* fdmex)
: FGModel(fdmex)
{
Debug(0);
Name = "FGAccelerations";
gravType = gtWGS84;
vPQRidot.InitMatrix();
vUVWidot.InitMatrix();
vGravAccel.InitMatrix();
vBodyAccel.InitMatrix();
vQtrndot = FGQuaternion(0,0,0);
bind();
Debug(0);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGAccelerations::~FGAccelerations(void)
{
Debug(1);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGAccelerations::InitModel(void)
{
vPQRidot.InitMatrix();
vUVWidot.InitMatrix();
vGravAccel.InitMatrix();
vBodyAccel.InitMatrix();
vQtrndot = FGQuaternion(0,0,0);
return true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/*
Purpose: Called on a schedule to calculate derivatives.
*/
bool FGAccelerations::Run(bool Holding)
{
if (FGModel::Run(Holding)) return true; // Fast return if we have nothing to do ...
if (Holding) return false;
RunPreFunctions();
CalculatePQRdot(); // Angular rate derivative
CalculateUVWdot(); // Translational rate derivative
CalculateQuatdot(); // Angular orientation derivative
ResolveFrictionForces(in.DeltaT * rate); // Update rate derivatives with friction forces
RunPostFunctions();
Debug(2);
return false;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Compute body frame rotational accelerations based on the current body moments
//
// vPQRdot is the derivative of the absolute angular velocity of the vehicle
// (body rate with respect to the inertial frame), expressed in the body frame,
// where the derivative is taken in the body frame.
// J is the inertia matrix
// Jinv is the inverse inertia matrix
// vMoments is the moment vector in the body frame
// in.vPQRi is the total inertial angular velocity of the vehicle
// expressed in the body frame.
// Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
// Second edition (2004), eqn 1.5-16e (page 50)
void FGAccelerations::CalculatePQRdot(void)
{
// Compute body frame rotational accelerations based on the current body
// moments and the total inertial angular velocity expressed in the body
// frame.
vPQRidot = in.Jinv * (in.Moment - in.vPQRi * (in.J * in.vPQRi));
vPQRdot = vPQRidot - in.vPQRi * (in.Ti2b * in.vOmegaPlanet);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Compute the quaternion orientation derivative
//
// vQtrndot is the quaternion derivative.
// Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
// Second edition (2004), eqn 1.5-16b (page 50)
void FGAccelerations::CalculateQuatdot(void)
{
// Compute quaternion orientation derivative on current body rates
vQtrndot = in.qAttitudeECI.GetQDot(in.vPQRi);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// This set of calculations results in the body and inertial frame accelerations
// being computed.
// Compute body and inertial frames accelerations based on the current body
// forces including centripetal and coriolis accelerations for the former.
// in.vOmegaPlanet is the Earth angular rate - expressed in the inertial frame -
// so it has to be transformed to the body frame. More completely,
// in.vOmegaPlanet is the rate of the ECEF frame relative to the Inertial
// frame (ECI), expressed in the Inertial frame.
// in.Force is the total force on the vehicle in the body frame.
// in.vPQR is the vehicle body rate relative to the ECEF frame, expressed
// in the body frame.
// in.vUVW is the vehicle velocity relative to the ECEF frame, expressed
// in the body frame.
// Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
// Second edition (2004), eqns 1.5-13 (pg 48) and 1.5-16d (page 50)
void FGAccelerations::CalculateUVWdot(void)
{
vBodyAccel = in.Force / in.Mass;
vUVWdot = vBodyAccel - (in.vPQR + 2.0 * (in.Ti2b * in.vOmegaPlanet)) * in.vUVW;
// Include Centripetal acceleration.
vUVWdot -= in.Ti2b * (in.vOmegaPlanet * (in.vOmegaPlanet * in.vInertialPosition));
// Include Gravitation accel
switch (gravType) {
case gtStandard:
vGravAccel = in.Tl2b * FGColumnVector3( 0.0, 0.0, in.GAccel );
break;
case gtWGS84:
vGravAccel = in.Tec2b * in.J2Grav;
break;
}
vUVWdot += vGravAccel;
vUVWidot = in.Tb2i * (vBodyAccel + vGravAccel);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Resolves the contact forces just before integrating the EOM.
// This routine is using Lagrange multipliers and the projected Gauss-Seidel
// (PGS) method.
// Reference: See Erin Catto, "Iterative Dynamics with Temporal Coherence",
// February 22, 2005
// In JSBSim there is only one rigid body (the aircraft) and there can be
// multiple points of contact between the aircraft and the ground. As a
// consequence our matrix J*M^-1*J^T is not sparse and the algorithm described
// in Catto's paper has been adapted accordingly.
// The friction forces are resolved in the body frame relative to the origin
// (Earth center).
void FGAccelerations::ResolveFrictionForces(double dt)
{
const double invMass = 1.0 / in.Mass;
const FGMatrix33& Jinv = in.Jinv;
FGColumnVector3 vdot, wdot;
vector<LagrangeMultiplier*>& multipliers = *in.MultipliersList;
int n = multipliers.size();
vFrictionForces.InitMatrix();
vFrictionMoments.InitMatrix();
// If no gears are in contact with the ground then return
if (!n) return;
vector<double> a(n*n); // Will contain J*M^-1*J^T
vector<double> rhs(n);
// Assemble the linear system of equations
for (int i=0; i < n; i++) {
FGColumnVector3 v1 = invMass * multipliers[i]->ForceJacobian;
FGColumnVector3 v2 = Jinv * multipliers[i]->MomentJacobian; // Should be J^-T but J is symmetric and so is J^-1
for (int j=0; j < i; j++)
a[i*n+j] = a[j*n+i]; // Takes advantage of the symmetry of J^T*M^-1*J
for (int j=i; j < n; j++)
a[i*n+j] = DotProduct(v1, multipliers[j]->ForceJacobian)
+ DotProduct(v2, multipliers[j]->MomentJacobian);
}
// Assemble the RHS member
// Translation
vdot = vUVWdot;
if (dt > 0.) // Zeroes out the relative movement between aircraft and ground
vdot += (in.vUVW - in.Tec2b * in.TerrainVelocity) / dt;
// Rotation
wdot = vPQRdot;
if (dt > 0.) // Zeroes out the relative movement between aircraft and ground
wdot += (in.vPQR - in.Tec2b * in.TerrainAngularVel) / dt;
// Prepare the linear system for the Gauss-Seidel algorithm :
// 1. Compute the right hand side member 'rhs'
// 2. Divide every line of 'a' and 'rhs' by a[i,i]. This is in order to save
// a division computation at each iteration of Gauss-Seidel.
for (int i=0; i < n; i++) {
double d = 1.0 / a[i*n+i];
rhs[i] = -(DotProduct(multipliers[i]->ForceJacobian, vdot)
+DotProduct(multipliers[i]->MomentJacobian, wdot))*d;
for (int j=0; j < n; j++)
a[i*n+j] *= d;
}
// Resolve the Lagrange multipliers with the projected Gauss-Seidel method
for (int iter=0; iter < 50; iter++) {
double norm = 0.;
for (int i=0; i < n; i++) {
double lambda0 = multipliers[i]->value;
double dlambda = rhs[i];
for (int j=0; j < n; j++)
dlambda -= a[i*n+j]*multipliers[j]->value;
multipliers[i]->value = Constrain(multipliers[i]->Min, lambda0+dlambda, multipliers[i]->Max);
dlambda = multipliers[i]->value - lambda0;
norm += fabs(dlambda);
}
if (norm < 1E-5) break;
}
// Calculate the total friction forces and moments
for (int i=0; i< n; i++) {
double lambda = multipliers[i]->value;
vFrictionForces += lambda * multipliers[i]->ForceJacobian;
vFrictionMoments += lambda * multipliers[i]->MomentJacobian;
}
FGColumnVector3 accel = invMass * vFrictionForces;
FGColumnVector3 omegadot = Jinv * vFrictionMoments;
vBodyAccel += accel;
vUVWdot += accel;
vUVWidot += in.Tb2i * accel;
vPQRdot += omegadot;
vPQRidot += omegadot;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGAccelerations::InitializeDerivatives(void)
{
// Make an initial run and set past values
CalculatePQRdot(); // Angular rate derivative
CalculateUVWdot(); // Translational rate derivative
CalculateQuatdot(); // Angular orientation derivative
ResolveFrictionForces(0.); // Update rate derivatives with friction forces
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGAccelerations::bind(void)
{
typedef double (FGAccelerations::*PMF)(int) const;
PropertyManager->Tie("accelerations/pdot-rad_sec2", this, eP, (PMF)&FGAccelerations::GetPQRdot);
PropertyManager->Tie("accelerations/qdot-rad_sec2", this, eQ, (PMF)&FGAccelerations::GetPQRdot);
PropertyManager->Tie("accelerations/rdot-rad_sec2", this, eR, (PMF)&FGAccelerations::GetPQRdot);
PropertyManager->Tie("accelerations/udot-ft_sec2", this, eU, (PMF)&FGAccelerations::GetUVWdot);
PropertyManager->Tie("accelerations/vdot-ft_sec2", this, eV, (PMF)&FGAccelerations::GetUVWdot);
PropertyManager->Tie("accelerations/wdot-ft_sec2", this, eW, (PMF)&FGAccelerations::GetUVWdot);
PropertyManager->Tie("simulation/gravity-model", &gravType);
PropertyManager->Tie("forces/fbx-total-lbs", this, eX, (PMF)&FGAccelerations::GetForces);
PropertyManager->Tie("forces/fby-total-lbs", this, eY, (PMF)&FGAccelerations::GetForces);
PropertyManager->Tie("forces/fbz-total-lbs", this, eZ, (PMF)&FGAccelerations::GetForces);
PropertyManager->Tie("moments/l-total-lbsft", this, eL, (PMF)&FGAccelerations::GetMoments);
PropertyManager->Tie("moments/m-total-lbsft", this, eM, (PMF)&FGAccelerations::GetMoments);
PropertyManager->Tie("moments/n-total-lbsft", this, eN, (PMF)&FGAccelerations::GetMoments);
PropertyManager->Tie("moments/l-gear-lbsft", this, eL, (PMF)&FGAccelerations::GetGroundMoments);
PropertyManager->Tie("moments/m-gear-lbsft", this, eM, (PMF)&FGAccelerations::GetGroundMoments);
PropertyManager->Tie("moments/n-gear-lbsft", this, eN, (PMF)&FGAccelerations::GetGroundMoments);
PropertyManager->Tie("forces/fbx-gear-lbs", this, eX, (PMF)&FGAccelerations::GetGroundForces);
PropertyManager->Tie("forces/fby-gear-lbs", this, eY, (PMF)&FGAccelerations::GetGroundForces);
PropertyManager->Tie("forces/fbz-gear-lbs", this, eZ, (PMF)&FGAccelerations::GetGroundForces);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
// out the normally expected messages, essentially echoing
// the config files as they are read. If the environment
// variable is not set, debug_lvl is set to 1 internally
// 0: This requests JSBSim not to output any messages
// whatsoever.
// 1: This value explicity requests the normal JSBSim
// startup messages
// 2: This value asks for a message to be printed out when
// a class is instantiated
// 4: When this value is set, a message is displayed when a
// FGModel object executes its Run() method
// 8: When this value is set, various runtime state variables
// are printed out periodically
// 16: When set various parameters are sanity checked and
// a message is printed out when they go out of bounds
void FGAccelerations::Debug(int from)
{
if (debug_lvl <= 0) return;
if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
if (from == 0) cout << "Instantiated: FGAccelerations" << endl;
if (from == 1) cout << "Destroyed: FGAccelerations" << endl;
}
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
}
if (debug_lvl & 8 && from == 2) { // Runtime state variables
}
if (debug_lvl & 16) { // Sanity checking
}
if (debug_lvl & 64) {
if (from == 0) { // Constructor
cout << IdSrc << endl;
cout << IdHdr << endl;
}
}
}
}

View file

@ -0,0 +1,230 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGAccelerations.h
Author: Jon S. Berndt
Date started: 07/12/11
------------- Copyright (C) 2011 Jon S. Berndt (jon@jsbsim.org) -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser 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 Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU Lesser General Public License can also be found on
the world wide web at http://www.gnu.org.
HISTORY
--------------------------------------------------------------------------------
07/12/11 JSB Created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifndef FGACCELERATIONS_H
#define FGACCELERATIONS_H
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <vector>
#include "models/FGModel.h"
#include "math/FGColumnVector3.h"
#include "math/LagrangeMultiplier.h"
#include "math/FGMatrix33.h"
#include "math/FGQuaternion.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_ACCELERATIONS "$Id: FGAccelerations.h,v 1.7 2011/08/21 15:46:48 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
namespace JSBSim {
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Handles the calculation of accelerations.
-Calculate the angular accelerations
-Calculate the translational accelerations
-Calculate the angular rate
-Calculate the translational velocity
@author Jon S. Berndt, Mathias Froehlich, Bertrand Coconnier
@version $Id: FGAccelerations.h,v 1.7 2011/08/21 15:46:48 bcoconni Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGAccelerations : public FGModel {
public:
/** Constructor.
@param Executive a pointer to the parent executive object */
FGAccelerations(FGFDMExec* Executive);
/// Destructor
~FGAccelerations();
/// These define the indices use to select the gravitation models.
enum eGravType {gtStandard, gtWGS84};
/** Initializes the FGAccelerations class after instantiation and prior to first execution.
The base class FGModel::InitModel is called first, initializing pointers to the
other FGModel objects (and others). */
bool InitModel(void);
/** Runs the state propagation model; called by the Executive
Can pass in a value indicating if the executive is directing the simulation to Hold.
@param Holding if true, the executive has been directed to hold the sim from
advancing time. Some models may ignore this flag, such as the Input
model, which may need to be active to listen on a socket for the
"Resume" command to be given.
@return false if no error */
bool Run(bool Holding);
const FGQuaternion& GetQuaterniondot(void) const {return vQtrndot;}
/** Retrieves the body axis acceleration.
Retrieves the computed body axis accelerations based on the
applied forces and accounting for a rotating body frame.
The vector returned is represented by an FGColumnVector reference. The vector
for the acceleration in Body frame is organized (Ax, Ay, Az). The vector
is 1-based, so that the first element can be retrieved using the "()" operator.
In other words, vUVWdot(1) is Ax. Various convenience enumerators are defined
in FGJSBBase. The relevant enumerators for the vector returned by this call are,
eX=1, eY=2, eZ=3.
units ft/sec^2
@return Body axis translational acceleration in ft/sec^2.
*/
const FGColumnVector3& GetUVWdot(void) const { return vUVWdot; }
const FGColumnVector3& GetUVWidot(void) const { return vUVWidot; }
/** Retrieves the body axis angular acceleration vector.
Retrieves the body axis angular acceleration vector in rad/sec^2. The
angular acceleration vector is determined from the applied forces and
accounts for a rotating frame.
The vector returned is represented by an FGColumnVector reference. The vector
for the angular acceleration in Body frame is organized (Pdot, Qdot, Rdot). The vector
is 1-based, so that the first element can be retrieved using the "()" operator.
In other words, vPQRdot(1) is Pdot. Various convenience enumerators are defined
in FGJSBBase. The relevant enumerators for the vector returned by this call are,
eP=1, eQ=2, eR=3.
units rad/sec^2
@return The angular acceleration vector.
*/
const FGColumnVector3& GetPQRdot(void) const {return vPQRdot;}
const FGColumnVector3& GetPQRidot(void) const {return vPQRidot;}
/** Retrieves a body frame acceleration component.
Retrieves a body frame acceleration component. The acceleration returned
is extracted from the vUVWdot vector (an FGColumnVector). The vector for
the acceleration in Body frame is organized (Ax, Ay, Az). The vector is
1-based. In other words, GetUVWdot(1) returns Ax. Various convenience
enumerators are defined in FGJSBBase. The relevant enumerators for the
acceleration returned by this call are, eX=1, eY=2, eZ=3.
units ft/sec^2
@param idx the index of the acceleration component desired (1-based).
@return The body frame acceleration component.
*/
double GetUVWdot(int idx) const { return vUVWdot(idx); }
FGColumnVector3& GetBodyAccel(void) { return vBodyAccel; }
double GetBodyAccel(int idx) const { return vBodyAccel(idx); }
/** Retrieves a body frame angular acceleration component.
Retrieves a body frame angular acceleration component. The angular
acceleration returned is extracted from the vPQRdot vector (an
FGColumnVector). The vector for the angular acceleration in Body frame
is organized (Pdot, Qdot, Rdot). The vector is 1-based. In other words,
GetPQRdot(1) returns Pdot (roll acceleration). Various convenience
enumerators are defined in FGJSBBase. The relevant enumerators for the
angular acceleration returned by this call are, eP=1, eQ=2, eR=3.
units rad/sec^2
@param axis the index of the angular acceleration component desired (1-based).
@return The body frame angular acceleration component.
*/
double GetPQRdot(int axis) const {return vPQRdot(axis);}
double GetMoments(int idx) const { return in.Moment(idx) + vFrictionMoments(idx); }
double GetForces(int idx) const { return in.Force(idx) + vFrictionForces(idx); }
double GetGroundMoments(int idx) const { return in.GroundMoment(idx) + vFrictionMoments(idx); }
double GetGroundForces(int idx) const { return in.GroundForce(idx) + vFrictionForces(idx); }
void InitializeDerivatives(void);
void DumpState(void);
struct Inputs {
FGMatrix33 J;
FGMatrix33 Jinv;
FGMatrix33 Ti2b;
FGMatrix33 Tb2i;
FGMatrix33 Tec2b;
FGMatrix33 Tl2b;
FGQuaternion qAttitudeECI;
FGColumnVector3 Moment;
FGColumnVector3 GroundMoment;
FGColumnVector3 Force;
FGColumnVector3 GroundForce;
FGColumnVector3 J2Grav;
FGColumnVector3 vPQRi;
FGColumnVector3 vPQR;
FGColumnVector3 vUVW;
FGColumnVector3 vInertialPosition;
FGColumnVector3 vOmegaPlanet;
FGColumnVector3 TerrainVelocity;
FGColumnVector3 TerrainAngularVel;
double DeltaT;
double Mass;
double GAccel;
std::vector<LagrangeMultiplier*> *MultipliersList;
} in;
private:
FGColumnVector3 vPQRdot, vPQRidot;
FGColumnVector3 vUVWdot, vUVWidot;
FGQuaternion vQtrndot;
FGColumnVector3 vBodyAccel;
FGColumnVector3 vGravAccel;
FGColumnVector3 vFrictionForces;
FGColumnVector3 vFrictionMoments;
int gravType;
void CalculatePQRdot(void);
void CalculateQuatdot(void);
void CalculateUVWdot(void);
void ResolveFrictionForces(double dt);
void bind(void);
void Debug(int from);
};
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif

View file

@ -40,19 +40,15 @@ INCLUDES
#include <sstream>
#include <iomanip>
#include <cstdlib>
#include <FGFDMExec.h>
#include "FGFDMExec.h"
#include "FGAerodynamics.h"
#include "FGPropagate.h"
#include "FGAircraft.h"
#include "FGAuxiliary.h"
#include "FGMassBalance.h"
#include "input_output/FGPropertyManager.h"
using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGAerodynamics.cpp,v 1.38 2011/05/20 03:18:36 jberndt Exp $";
static const char *IdSrc = "$Id: FGAerodynamics.cpp,v 1.41 2011/08/04 12:46:32 jberndt Exp $";
static const char *IdHdr = ID_AERODYNAMICS;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -139,36 +135,31 @@ bool FGAerodynamics::Run(bool Holding)
if (Holding) return false; // if paused don't execute
unsigned int axis_ctr, ctr;
const double alpha=FDMExec->GetAuxiliary()->Getalpha();
const double twovel=2*FDMExec->GetAuxiliary()->GetVt();
const double qbar = FDMExec->GetAuxiliary()->Getqbar();
const double wingarea = FDMExec->GetAircraft()->GetWingArea(); // TODO: Make these constants constant!
const double wingspan = FDMExec->GetAircraft()->GetWingSpan();
const double wingchord = FDMExec->GetAircraft()->Getcbar();
const double wingincidence = FDMExec->GetAircraft()->GetWingIncidence();
const double twovel=2*in.Vt;
RunPreFunctions();
// calculate some oft-used quantities for speed
if (twovel != 0) {
bi2vel = wingspan / twovel;
ci2vel = wingchord / twovel;
bi2vel = in.Wingspan / twovel;
ci2vel = in.Wingchord / twovel;
}
alphaw = alpha + wingincidence;
qbar_area = wingarea * qbar;
alphaw = in.Alpha + in.Wingincidence;
qbar_area = in.Wingarea * in.Qbar;
if (alphaclmax != 0) {
if (alpha > 0.85*alphaclmax) {
impending_stall = 10*(alpha/alphaclmax - 0.85);
if (in.Alpha > 0.85*alphaclmax) {
impending_stall = 10*(in.Alpha/alphaclmax - 0.85);
} else {
impending_stall = 0;
}
}
if (alphahystmax != 0.0 && alphahystmin != 0.0) {
if (alpha > alphahystmax) {
if (in.Alpha > alphahystmax) {
stall_hyst = 1;
} else if (alpha < alphahystmin) {
} else if (in.Alpha < alphahystmin) {
stall_hyst = 0;
}
}
@ -188,16 +179,16 @@ bool FGAerodynamics::Run(bool Holding)
switch (axisType) {
case atBodyXYZ: // Forces already in body axes; no manipulation needed
vFw = GetTb2w()*vFnative;
vFw = in.Tb2w*vFnative;
vForces = vFnative;
break;
case atLiftDrag: // Copy forces into wind axes
vFw = vFnative;
vFw(eDrag)*=-1; vFw(eLift)*=-1;
vForces = GetTw2b()*vFw;
vForces = in.Tw2b*vFw;
break;
case atAxialNormal: // Convert native forces into Axial|Normal|Side system
vFw = GetTb2w()*vFnative;
vFw = in.Tb2w*vFnative;
vFnative(eX)*=-1; vFnative(eZ)*=-1;
vForces = vFnative;
break;
@ -207,19 +198,23 @@ bool FGAerodynamics::Run(bool Holding)
exit(-1);
}
// Calculate aerodynamic reference point shift, if any
if (AeroRPShift) vDeltaRP(eX) = AeroRPShift->GetValue()*wingchord*12.0;
// Calculate lift coefficient squared
if ( qbar > 0) {
clsq = vFw(eLift) / (wingarea*qbar);
if ( in.Qbar > 0) {
clsq = vFw(eLift) / (in.Wingarea*in.Qbar);
clsq *= clsq;
}
// Calculate lift Lift over Drag
if ( fabs(vFw(eDrag)) > 0.0) lod = fabs( vFw(eLift) / vFw(eDrag) );
vDXYZcg = FDMExec->GetMassBalance()->StructuralToBody(FDMExec->GetAircraft()->GetXYZrp() + vDeltaRP);
// Calculate aerodynamic reference point shift, if any. The shift
// takes place in the body axis. That is, if the shift is negative,
// it is towards the back (tail) of the vehicle. The AeroRPShift
// function should be non-dimensionalized by the wing chord. The
// calculated vDeltaRP will be in feet.
if (AeroRPShift) vDeltaRP(eX) = AeroRPShift->GetValue()*in.Wingchord;
vDXYZcg = in.RPBody + vDeltaRP;
vMoments = vDXYZcg*vForces; // M = r X F
@ -234,75 +229,6 @@ bool FGAerodynamics::Run(bool Holding)
return false;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// From Stevens and Lewis, "Aircraft Control and Simulation", 3rd Ed., the
// transformation from body to wind axes is defined (where "a" is alpha and "B"
// is beta):
//
// cos(a)*cos(B) sin(B) sin(a)*cos(B)
// -cos(a)*sin(B) cos(B) -sin(a)*sin(B)
// -sin(a) 0 cos(a)
//
// The transform from wind to body axes is then,
//
// cos(a)*cos(B) -cos(a)*sin(B) -sin(a)
// sin(B) cos(B) 0
// sin(a)*cos(B) -sin(a)*sin(B) cos(a)
FGMatrix33& FGAerodynamics::GetTw2b(void)
{
double ca, cb, sa, sb;
double alpha = FDMExec->GetAuxiliary()->Getalpha();
double beta = FDMExec->GetAuxiliary()->Getbeta();
ca = cos(alpha);
sa = sin(alpha);
cb = cos(beta);
sb = sin(beta);
mTw2b(1,1) = ca*cb;
mTw2b(1,2) = -ca*sb;
mTw2b(1,3) = -sa;
mTw2b(2,1) = sb;
mTw2b(2,2) = cb;
mTw2b(2,3) = 0.0;
mTw2b(3,1) = sa*cb;
mTw2b(3,2) = -sa*sb;
mTw2b(3,3) = ca;
return mTw2b;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGMatrix33& FGAerodynamics::GetTb2w(void)
{
double alpha,beta;
double ca, cb, sa, sb;
alpha = FDMExec->GetAuxiliary()->Getalpha();
beta = FDMExec->GetAuxiliary()->Getbeta();
ca = cos(alpha);
sa = sin(alpha);
cb = cos(beta);
sb = sin(beta);
mTb2w(1,1) = ca*cb;
mTb2w(1,2) = sb;
mTb2w(1,3) = sa*cb;
mTb2w(2,1) = -ca*sb;
mTb2w(2,2) = cb;
mTb2w(2,3) = -sa*sb;
mTb2w(3,1) = -sa;
mTb2w(3,2) = 0.0;
mTb2w(3,3) = ca;
return mTb2w;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGAerodynamics::Load(Element *element)
@ -318,6 +244,7 @@ bool FGAerodynamics::Load(Element *element)
if (!fname.empty()) {
file = FDMExec->GetFullAircraftPath() + separator + fname;
document = LoadXMLDocument(file);
if (document == 0L) return false;
} else {
document = element;
}

View file

@ -52,7 +52,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_AERODYNAMICS "$Id: FGAerodynamics.h,v 1.23 2011/05/20 03:18:36 jberndt Exp $"
#define ID_AERODYNAMICS "$Id: FGAerodynamics.h,v 1.25 2011/08/04 12:46:32 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -109,7 +109,7 @@ CLASS DOCUMENTATION
Systems may NOT be combined, or a load error will occur.
@author Jon S. Berndt, Tony Peden
@version $Revision: 1.23 $
@version $Revision: 1.25 $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -202,18 +202,22 @@ public:
aero functions */
std::string GetAeroFunctionValues(const std::string& delimeter) const;
/** Calculates and returns the wind-to-body axis transformation matrix.
@return a reference to the wind-to-body transformation matrix.
*/
FGMatrix33& GetTw2b(void);
/** Calculates and returns the body-to-wind axis transformation matrix.
@return a reference to the wind-to-body transformation matrix.
*/
FGMatrix33& GetTb2w(void);
std::vector <FGFunction*> * GetAeroFunctions(void) const { return AeroFunctions; }
struct Inputs {
double Alpha;
double Beta;
double Vt;
double Qbar;
double Wingarea;
double Wingspan;
double Wingchord;
double Wingincidence;
FGColumnVector3 RPBody;
FGMatrix33 Tb2w;
FGMatrix33 Tw2b;
} in;
private:
enum eAxisType {atNone, atLiftDrag, atAxialNormal, atBodyXYZ} axisType;
typedef std::map<std::string,int> AxisIndex;
@ -227,8 +231,6 @@ private:
FGColumnVector3 vMoments;
FGColumnVector3 vDXYZcg;
FGColumnVector3 vDeltaRP;
FGMatrix33 mTw2b;
FGMatrix33 mTb2w;
double alphaclmax, alphaclmin;
double alphahystmax, alphahystmin;
double impending_stall, stall_hyst;

View file

@ -44,15 +44,7 @@ INCLUDES
#include <cmath>
#include "FGAircraft.h"
#include "FGMassBalance.h"
#include "FGInertial.h"
#include "FGGroundReactions.h"
#include "FGExternalReactions.h"
#include "FGBuoyantForces.h"
#include "FGAerodynamics.h"
#include "FGFDMExec.h"
#include "FGPropagate.h"
#include "FGPropulsion.h"
#include "input_output/FGPropertyManager.h"
using namespace std;
@ -67,7 +59,7 @@ DEFINITIONS
GLOBAL DATA
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
static const char *IdSrc = "$Id: FGAircraft.cpp,v 1.31 2011/05/20 03:18:36 jberndt Exp $";
static const char *IdSrc = "$Id: FGAircraft.cpp,v 1.33 2011/08/21 15:06:38 bcoconni Exp $";
static const char *IdHdr = ID_AIRCRAFT;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -78,6 +70,8 @@ FGAircraft::FGAircraft(FGFDMExec* fdmex) : FGModel(fdmex)
{
Name = "FGAircraft";
WingSpan = 0.0;
WingArea = 0.0;
cbar = 0.0;
HTailArea = VTailArea = 0.0;
HTailArm = VTailArm = 0.0;
lbarh = lbarv = 0.0;
@ -115,32 +109,24 @@ bool FGAircraft::Run(bool Holding)
vForces.InitMatrix();
if (!HoldDown) {
vForces += FDMExec->GetAerodynamics()->GetForces();
vForces += FDMExec->GetPropulsion()->GetForces();
vForces += FDMExec->GetGroundReactions()->GetForces();
vForces += FDMExec->GetExternalReactions()->GetForces();
vForces += FDMExec->GetBuoyantForces()->GetForces();
vForces += in.AeroForce;
vForces += in.PropForce;
vForces += in.GroundForce;
vForces += in.ExternalForce;
vForces += in.BuoyantForce;
} else {
const FGMatrix33& mTl2b = FDMExec->GetPropagate()->GetTl2b();
vForces = mTl2b * FGColumnVector3(0,0,-FDMExec->GetMassBalance()->GetWeight());
vForces = in.Tl2b * FGColumnVector3(0,0,-in.Weight);
}
vMoments.InitMatrix();
if (!HoldDown) {
vMoments += FDMExec->GetAerodynamics()->GetMoments();
vMoments += FDMExec->GetPropulsion()->GetMoments();
vMoments += FDMExec->GetGroundReactions()->GetMoments();
vMoments += FDMExec->GetExternalReactions()->GetMoments();
vMoments += FDMExec->GetBuoyantForces()->GetMoments();
vMoments += in.AeroMoment;
vMoments += in.PropMoment;
vMoments += in.GroundMoment;
vMoments += in.ExternalMoment;
vMoments += in.BuoyantMoment;
}
vBodyAccel = vForces/FDMExec->GetMassBalance()->GetMass();
vNcg = vBodyAccel/FDMExec->GetInertial()->SLgravity();
vNwcg = FDMExec->GetAerodynamics()->GetTb2w() * vNcg;
vNwcg(3) = 1.0 - vNwcg(3);
RunPostFunctions();
return false;
@ -148,16 +134,6 @@ bool FGAircraft::Run(bool Holding)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGAircraft::GetNlf(void) const
{
if (FDMExec->GetMassBalance()->GetWeight() != 0)
return (-FDMExec->GetAerodynamics()->GetvFw(3))/FDMExec->GetMassBalance()->GetWeight();
else
return 0.;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGAircraft::Load(Element* el)
{
string element_name;
@ -240,14 +216,7 @@ void FGAircraft::bind(void)
PropertyManager->Tie("metrics/visualrefpoint-x-in", this, eX, (PMF)&FGAircraft::GetXYZvrp);
PropertyManager->Tie("metrics/visualrefpoint-y-in", this, eY, (PMF)&FGAircraft::GetXYZvrp);
PropertyManager->Tie("metrics/visualrefpoint-z-in", this, eZ, (PMF)&FGAircraft::GetXYZvrp);
PropertyManager->Tie("forces/fbx-total-lbs", this, eX, (PMF)&FGAircraft::GetForces);
PropertyManager->Tie("forces/fby-total-lbs", this, eY, (PMF)&FGAircraft::GetForces);
PropertyManager->Tie("forces/fbz-total-lbs", this, eZ, (PMF)&FGAircraft::GetForces);
PropertyManager->Tie("forces/load-factor", this, &FGAircraft::GetNlf);
PropertyManager->Tie("forces/hold-down", this, &FGAircraft::GetHoldDown, &FGAircraft::SetHoldDown);
PropertyManager->Tie("moments/l-total-lbsft", this, eL, (PMF)&FGAircraft::GetMoments);
PropertyManager->Tie("moments/m-total-lbsft", this, eM, (PMF)&FGAircraft::GetMoments);
PropertyManager->Tie("moments/n-total-lbsft", this, eN, (PMF)&FGAircraft::GetMoments);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -44,12 +44,13 @@ INCLUDES
#include "FGModel.h"
#include "input_output/FGXMLElement.h"
#include "math/FGColumnVector3.h"
#include "math/FGMatrix33.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_AIRCRAFT "$Id: FGAircraft.h,v 1.17 2011/05/20 03:18:36 jberndt Exp $"
#define ID_AIRCRAFT "$Id: FGAircraft.h,v 1.18 2011/07/10 20:18:14 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -90,7 +91,7 @@ CLASS DOCUMENTATION
@endcode
@author Jon S. Berndt
@version $Id: FGAircraft.h,v 1.17 2011/05/20 03:18:36 jberndt Exp $
@version $Id: FGAircraft.h,v 1.18 2011/07/10 20:18:14 jberndt Exp $
@see Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
School, January 1994
@ -159,10 +160,6 @@ public:
double GetMoments(int idx) const { return vMoments(idx); }
const FGColumnVector3& GetForces(void) const { return vForces; }
double GetForces(int idx) const { return vForces(idx); }
FGColumnVector3& GetBodyAccel(void) { return vBodyAccel; }
double GetBodyAccel(int idx) const { return vBodyAccel(idx); }
const FGColumnVector3& GetNcg(void) const { return vNcg; }
double GetNcg(int idx) const { return vNcg(idx); }
const FGColumnVector3& GetXYZrp(void) const { return vXYZrp; }
const FGColumnVector3& GetXYZvrp(void) const { return vXYZvrp; }
const FGColumnVector3& GetXYZep(void) const { return vXYZep; }
@ -177,13 +174,24 @@ public:
void SetWingArea(double S) {WingArea = S;}
double GetNlf(void) const;
FGColumnVector3& GetNwcg(void) { return vNwcg; }
void bind(void);
void unbind(void);
struct Inputs {
FGColumnVector3 AeroForce;
FGColumnVector3 PropForce;
FGColumnVector3 GroundForce;
FGColumnVector3 ExternalForce;
FGColumnVector3 BuoyantForce;
FGColumnVector3 AeroMoment;
FGColumnVector3 PropMoment;
FGColumnVector3 GroundMoment;
FGColumnVector3 ExternalMoment;
FGColumnVector3 BuoyantMoment;
FGMatrix33 Tl2b;
double Weight;
} in;
private:
FGColumnVector3 vMoments;
FGColumnVector3 vForces;
@ -191,9 +199,6 @@ private:
FGColumnVector3 vXYZvrp;
FGColumnVector3 vXYZep;
FGColumnVector3 vDXYZcg;
FGColumnVector3 vBodyAccel;
FGColumnVector3 vNcg;
FGColumnVector3 vNwcg;
double WingArea, WingSpan, cbar, WingIncidence;
double HTailArea, VTailArea, HTailArm, VTailArm;

View file

@ -1,13 +1,12 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Module: FGAtmosphere.cpp
Author: Jon Berndt
Implementation of 1959 Standard Atmosphere added by Tony Peden
Date started: 11/24/98
Purpose: Models the atmosphere
Called by: FGSimExec
Author: Jon Berndt, Tony Peden
Date started: 6/2011
Purpose: Models an atmosphere interface class
Called by: FGFDMExec
------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) -------------
------------- Copyright (C) 2011 Jon S. Berndt (jon@jsbsim.org) -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
@ -28,92 +27,43 @@
FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------
Models the atmosphere. The equation used below was determined by a third order
curve fit using Excel. The data is from the ICAO atmosphere model.
This models a base atmosphere class to serve as a common interface to any derived
atmosphere models.
HISTORY
--------------------------------------------------------------------------------
11/24/98 JSB Created
07/23/99 TP Added implementation of 1959 Standard Atmosphere
Moved calculation of Mach number to FGPropagate
Later updated to '76 model
6/18/2011 Started Jon S. Berndt
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
COMMENTS, REFERENCES, and NOTES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[1] Anderson, John D. "Introduction to Flight, Third Edition", McGraw-Hill,
1989, ISBN 0-07-001641-0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGAtmosphere.h"
#include "FGAircraft.h"
#include "FGPropagate.h"
#include "FGInertial.h"
#include "FGAuxiliary.h"
#include "FGFDMExec.h"
#include "input_output/FGPropertyManager.h"
#include <iostream>
#include <iomanip>
#include <cstdlib>
using namespace std;
#include "FGFDMExec.h"
#include "FGAtmosphere.h"
namespace JSBSim {
static const char *IdSrc = "$Id: FGAtmosphere.cpp,v 1.45 2011/05/20 03:18:36 jberndt Exp $";
static const char *IdSrc = "$Id: FGAtmosphere.cpp,v 1.49 2011/09/11 11:36:04 bcoconni Exp $";
static const char *IdHdr = ID_ATMOSPHERE;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGAtmosphere::FGAtmosphere(FGFDMExec* fdmex) : FGModel(fdmex)
FGAtmosphere::FGAtmosphere(FGFDMExec* fdmex) : FGModel(fdmex),
PressureAltitude(0.0), // ft
DensityAltitude(0.0), // ft
SutherlandConstant(198.72), // deg Rankine
Beta(2.269690E-08) // slug/(sec ft R^0.5)
{
Name = "FGAtmosphere";
lastIndex = 0;
h = 0.0;
psiw = 0.0;
htab[0]=0;
htab[1]= 36089.0;
htab[2]= 65617.0;
htab[3]=104987.0;
htab[4]=154199.0;
htab[5]=167322.0;
htab[6]=232940.0;
htab[7]=278385.0; //ft.
MagnitudedAccelDt = MagnitudeAccel = Magnitude = 0.0;
SetTurbType( ttMilspec );
TurbGain = 1.0;
TurbRate = 10.0;
Rhythmicity = 0.1;
spike = target_time = strength = 0.0;
wind_from_clockwise = 0.0;
SutherlandConstant = 198.72; // deg Rankine
Beta = 2.269690E-08; // slug/(sec ft R^0.5)
T_dev_sl = T_dev = delta_T = 0.0;
StandardTempOnly = false;
first_pass = true;
vGustNED.InitMatrix();
vTurbulenceNED.InitMatrix();
// Milspec turbulence model
windspeed_at_20ft = 0.;
probability_of_exceedence_index = 0;
POE_Table = new FGTable(7,12);
// this is Figure 7 from p. 49 of MIL-F-8785C
// rows: probability of exceedance curve index, cols: altitude in ft
*POE_Table
<< 500.0 << 1750.0 << 3750.0 << 7500.0 << 15000.0 << 25000.0 << 35000.0 << 45000.0 << 55000.0 << 65000.0 << 75000.0 << 80000.0
<< 1 << 3.2 << 2.2 << 1.5 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0
<< 2 << 4.2 << 3.6 << 3.3 << 1.6 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0
<< 3 << 6.6 << 6.9 << 7.4 << 6.7 << 4.6 << 2.7 << 0.4 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0
<< 4 << 8.6 << 9.6 << 10.6 << 10.1 << 8.0 << 6.6 << 5.0 << 4.2 << 2.7 << 0.0 << 0.0 << 0.0
<< 5 << 11.8 << 13.0 << 16.0 << 15.1 << 11.6 << 9.7 << 8.1 << 8.2 << 7.9 << 4.9 << 3.2 << 2.1
<< 6 << 15.6 << 17.6 << 23.0 << 23.6 << 22.1 << 20.0 << 16.0 << 15.1 << 12.1 << 7.9 << 6.2 << 5.1
<< 7 << 18.7 << 21.5 << 28.4 << 30.2 << 30.7 << 31.0 << 25.2 << 23.1 << 17.5 << 10.7 << 8.4 << 7.2;
bind();
Debug(0);
@ -123,7 +73,6 @@ FGAtmosphere::FGAtmosphere(FGFDMExec* fdmex) : FGModel(fdmex)
FGAtmosphere::~FGAtmosphere()
{
delete(POE_Table);
Debug(1);
}
@ -131,17 +80,16 @@ FGAtmosphere::~FGAtmosphere()
bool FGAtmosphere::InitModel(void)
{
UseInternal(); // this is the default
Calculate(0.0);
SLtemperature = Temperature = 518.67;
SLpressure = Pressure = 2116.22;
SLdensity = Density = Pressure/(Reng*Temperature);
SLsoundspeed = Soundspeed = sqrt(SHRatio*Reng*(Temperature));
Calculate(h);
StdSLtemperature = SLtemperature = 518.67;
StdSLpressure = SLpressure = 2116.22;
StdSLdensity = SLdensity = 0.00237767;
StdSLsoundspeed = SLsoundspeed = sqrt(SHRatio*Reng*StdSLtemperature);
rSLtemperature = 1.0/StdSLtemperature;
rSLpressure = 1.0/StdSLpressure;
rSLdensity = 1.0/StdSLdensity;
rSLsoundspeed = 1.0/StdSLsoundspeed;
rSLtemperature = 1/SLtemperature ;
rSLpressure = 1/SLpressure ;
rSLdensity = 1/SLdensity ;
rSLsoundspeed = 1/SLsoundspeed ;
return true;
}
@ -155,15 +103,7 @@ bool FGAtmosphere::Run(bool Holding)
RunPreFunctions();
T_dev = 0.0;
h = FDMExec->GetPropagate()->GetAltitudeASL();
if (!useExternal) {
Calculate(h);
CalculateDerived();
} else {
CalculateDerived();
}
Calculate(in.altitudeASL);
RunPostFunctions();
@ -172,537 +112,108 @@ bool FGAtmosphere::Run(bool Holding)
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// See reference 1
void FGAtmosphere::Calculate(double altitude)
{
double slope, reftemp, refpress;
int i = lastIndex;
Temperature = GetTemperature(altitude);
Pressure = GetPressure(altitude);
Density = Pressure/(Reng*Temperature);
Soundspeed = sqrt(SHRatio*Reng*(Temperature));
PressureAltitude = altitude;
DensityAltitude = altitude;
if (altitude < htab[lastIndex]) {
if (altitude <= 0) {
i = 0;
altitude=0;
} else {
i = lastIndex-1;
while (htab[i] > altitude) i--;
}
} else if (altitude > htab[lastIndex+1]) {
if (altitude >= htab[7]) {
i = 7;
altitude = htab[7];
} else {
i = lastIndex+1;
while (htab[i+1] < altitude) i++;
}
}
switch(i) {
case 0: // Sea level
slope = -0.00356616; // R/ft.
reftemp = 518.67; // in degrees Rankine, 288.15 Kelvin
refpress = 2116.22; // psf
//refdens = 0.00237767; // slugs/cubic ft.
break;
case 1: // 36089 ft. or 11 km
slope = 0;
reftemp = 389.97; // in degrees Rankine, 216.65 Kelvin
refpress = 472.763;
//refdens = 0.000706032;
break;
case 2: // 65616 ft. or 20 km
slope = 0.00054864;
reftemp = 389.97; // in degrees Rankine, 216.65 Kelvin
refpress = 114.636;
//refdens = 0.000171306;
break;
case 3: // 104986 ft. or 32 km
slope = 0.001536192;
reftemp = 411.57; // in degrees Rankine, 228.65 Kelvin
refpress = 18.128;
//refdens = 1.18422e-05;
break;
case 4: // 154199 ft. 47 km
slope = 0;
reftemp = 487.17; // in degrees Rankine, 270.65 Kelvin
refpress = 2.316;
//refdens = 4.00585e-7;
break;
case 5: // 167322 ft. or 51 km
slope = -0.001536192;
reftemp = 487.17; // in degrees Rankine, 270.65 Kelvin
refpress = 1.398;
//refdens = 8.17102e-7;
break;
case 6: // 232940 ft. or 71 km
slope = -0.00109728;
reftemp = 386.368; // in degrees Rankine, 214.649 Kelvin
refpress = 0.0826;
//refdens = 8.77702e-9;
break;
case 7: // 278385 ft. or 84.8520 km
slope = 0;
reftemp = 336.5; // in degrees Rankine, 186.94 Kelvin
refpress = 0.00831;
//refdens = 2.19541e-10;
break;
default: // sea level
slope = -0.00356616; // R/ft.
reftemp = 518.67; // in degrees Rankine, 288.15 Kelvin
refpress = 2116.22; // psf
//refdens = 0.00237767; // slugs/cubic ft.
break;
}
// If delta_T is set, then that is our temperature deviation at any altitude.
// If not, then we'll estimate a deviation based on the sea level deviation (if set).
if(!StandardTempOnly) {
T_dev = 0.0;
if (delta_T != 0.0) {
T_dev = delta_T;
} else {
if ((altitude < 36089.239) && (T_dev_sl != 0.0)) {
T_dev = T_dev_sl * ( 1.0 - (altitude/36089.239));
}
}
reftemp+=T_dev;
}
if (slope == 0) {
intTemperature = reftemp;
intPressure = refpress*exp(-FDMExec->GetInertial()->SLgravity()/(reftemp*Reng)*(altitude-htab[i]));
intDensity = intPressure/(Reng*intTemperature);
} else {
intTemperature = reftemp+slope*(altitude-htab[i]);
intPressure = refpress*pow(intTemperature/reftemp,-FDMExec->GetInertial()->SLgravity()/(slope*Reng));
intDensity = intPressure/(Reng*intTemperature);
}
lastIndex=i;
Viscosity = Beta * pow(Temperature, 1.5) / (SutherlandConstant + Temperature);
KinematicViscosity = Viscosity / Density;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Calculate parameters derived from T, P and rho
// Sum gust and turbulence values in NED frame into the wind vector.
void FGAtmosphere::CalculateDerived(void)
void FGAtmosphere::SetPressureSL(double pressure, ePressure unit)
{
T_dev = (*temperature) - GetTemperature(h);
double press = ConvertToPSF(pressure, unit);
if (T_dev == 0.0) density_altitude = h;
else density_altitude = 518.67/0.00356616 * (1.0 - pow(GetDensityRatio(),0.235));
if (turbType != ttNone) Turbulence();
vTotalWindNED = vWindNED + vGustNED + vTurbulenceNED;
// psiw (Wind heading) is the direction the wind is blowing towards
if (vWindNED(eX) != 0.0) psiw = atan2( vWindNED(eY), vWindNED(eX) );
if (psiw < 0) psiw += 2*M_PI;
soundspeed = sqrt(SHRatio*Reng*(*temperature));
intViscosity = Beta * pow(intTemperature, 1.5) / (SutherlandConstant + intTemperature);
intKinematicViscosity = intViscosity / intDensity;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Get the standard atmospheric properties at a specified altitude
void FGAtmosphere::GetStdAtmosphere(double altitude) {
StandardTempOnly = true;
Calculate(altitude);
StandardTempOnly = false;
atmosphere.Temperature = intTemperature;
atmosphere.Pressure = intPressure;
atmosphere.Density = intDensity;
// Reset the internal atmospheric state
Calculate(h);
SLpressure = press;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Get the standard pressure at a specified altitude
// Get the modeled density at a specified altitude
double FGAtmosphere::GetPressure(double altitude) {
GetStdAtmosphere(altitude);
return atmosphere.Pressure;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Get the standard temperature at a specified altitude
double FGAtmosphere::GetTemperature(double altitude) {
GetStdAtmosphere(altitude);
return atmosphere.Temperature;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Get the standard density at a specified altitude
double FGAtmosphere::GetDensity(double altitude) {
GetStdAtmosphere(altitude);
return atmosphere.Density;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// square a value, but preserve the original sign
static inline double square_signed (double value)
double FGAtmosphere::GetDensity(double altitude) const
{
if (value < 0)
return value * value * -1;
else
return value * value;
return GetPressure(altitude)/(Reng * GetTemperature(altitude));
}
/// simply square a value
static inline double sqr(double x) { return x*x; }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// psi is the angle that the wind is blowing *towards*
// This function sets the sea level temperature.
// Internally, the Rankine scale is used for calculations, so any temperature
// supplied must be converted to that unit.
void FGAtmosphere::SetWindspeed(double speed)
void FGAtmosphere::SetTemperatureSL(double t, eTemperature unit)
{
if (vWindNED.Magnitude() == 0.0) {
psiw = 0.0;
vWindNED(eNorth) = speed;
} else {
vWindNED(eNorth) = speed * cos(psiw);
vWindNED(eEast) = speed * sin(psiw);
vWindNED(eDown) = 0.0;
}
SLtemperature = ConvertToRankine(t, unit);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGAtmosphere::GetWindspeed(void) const
double FGAtmosphere::ConvertToRankine(double t, eTemperature unit) const
{
return vWindNED.Magnitude();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// psi is the angle that the wind is blowing *towards*
void FGAtmosphere::SetWindPsi(double dir)
{
double mag = GetWindspeed();
psiw = dir;
SetWindspeed(mag);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGAtmosphere::Turbulence(void)
{
const double DeltaT = rate*FDMExec->GetDeltaT();
const double wingspan = FDMExec->GetAircraft()->GetWingSpan();
const double HOverBMAC = FDMExec->GetAuxiliary()->GetHOverBMAC();
const FGMatrix33& Tl2b = FDMExec->GetPropagate()->GetTl2b();
const double HTailArm = FDMExec->GetAircraft()->GetHTailArm();
const double VTailArm = FDMExec->GetAircraft()->GetVTailArm();
switch (turbType) {
case ttStandard: {
// TurbGain = TurbGain * TurbGain * 100.0; // what is this!?
vDirectiondAccelDt(eX) = 1 - 2.0*(double(rand())/double(RAND_MAX));
vDirectiondAccelDt(eY) = 1 - 2.0*(double(rand())/double(RAND_MAX));
vDirectiondAccelDt(eZ) = 1 - 2.0*(double(rand())/double(RAND_MAX));
MagnitudedAccelDt = 1 - 2.0*(double(rand())/double(RAND_MAX)) - Magnitude;
// Scale the magnitude so that it moves
// away from the peaks
MagnitudedAccelDt = ((MagnitudedAccelDt - Magnitude) /
(1 + fabs(Magnitude)));
MagnitudeAccel += MagnitudedAccelDt*TurbRate*DeltaT;
Magnitude += MagnitudeAccel*DeltaT;
Magnitude = fabs(Magnitude);
vDirectiondAccelDt.Normalize();
// deemphasise non-vertical forces
vDirectiondAccelDt(eX) = square_signed(vDirectiondAccelDt(eX));
vDirectiondAccelDt(eY) = square_signed(vDirectiondAccelDt(eY));
vDirectionAccel += vDirectiondAccelDt*TurbRate*DeltaT;
vDirectionAccel.Normalize();
vDirection += vDirectionAccel*DeltaT;
vDirection.Normalize();
// Diminish turbulence within three wingspans
// of the ground
vTurbulenceNED = TurbGain * Magnitude * vDirection;
if (HOverBMAC < 3.0)
vTurbulenceNED *= (HOverBMAC / 3.0) * (HOverBMAC / 3.0);
// I don't believe these next two statements calculate the proper gradient over
// the aircraft body. One reason is because this has no relationship with the
// orientation or velocity of the aircraft, which it must have. What is vTurbulenceGrad
// supposed to represent? And the direction and magnitude of the turbulence can change,
// so both accelerations need to be accounted for, no?
// Need to determine the turbulence change in body axes between two time points.
vTurbulenceGrad = TurbGain*MagnitudeAccel * vDirection;
vBodyTurbGrad = Tl2b*vTurbulenceGrad;
if (wingspan > 0) {
vTurbPQR(eP) = vBodyTurbGrad(eY)/wingspan;
} else {
vTurbPQR(eP) = vBodyTurbGrad(eY)/30.0;
}
// if (HTailArm != 0.0)
// vTurbPQR(eQ) = vBodyTurbGrad(eZ)/HTailArm;
// else
// vTurbPQR(eQ) = vBodyTurbGrad(eZ)/10.0;
if (VTailArm > 0)
vTurbPQR(eR) = vBodyTurbGrad(eX)/VTailArm;
else
vTurbPQR(eR) = vBodyTurbGrad(eX)/10.0;
// Clear the horizontal forces
// actually felt by the plane, now
// that we've used them to calculate
// moments.
// Why? (JSB)
// vTurbulenceNED(eX) = 0.0;
// vTurbulenceNED(eY) = 0.0;
double targetTemp=0; // in degrees Rankine
switch(unit) {
case eFahrenheit:
targetTemp = t + 459.67;
break;
}
case ttCulp: {
vTurbPQR(eP) = wind_from_clockwise;
if (TurbGain == 0.0) return;
// keep the inputs within allowable limts for this model
if (TurbGain < 0.0) TurbGain = 0.0;
if (TurbGain > 1.0) TurbGain = 1.0;
if (TurbRate < 0.0) TurbRate = 0.0;
if (TurbRate > 30.0) TurbRate = 30.0;
if (Rhythmicity < 0.0) Rhythmicity = 0.0;
if (Rhythmicity > 1.0) Rhythmicity = 1.0;
// generate a sine wave corresponding to turbulence rate in hertz
double time = FDMExec->GetSimTime();
double sinewave = sin( time * TurbRate * 6.283185307 );
double random = 0.0;
if (target_time == 0.0) {
strength = random = 1 - 2.0*(double(rand())/double(RAND_MAX));
target_time = time + 0.71 + (random * 0.5);
}
if (time > target_time) {
spike = 1.0;
target_time = 0.0;
}
// max vertical wind speed in fps, corresponds to TurbGain = 1.0
double max_vs = 40;
vTurbulenceNED(1) = vTurbulenceNED(2) = vTurbulenceNED(3) = 0.0;
double delta = strength * max_vs * TurbGain * (1-Rhythmicity) * spike;
// Vertical component of turbulence.
vTurbulenceNED(3) = sinewave * max_vs * TurbGain * Rhythmicity;
vTurbulenceNED(3)+= delta;
if (HOverBMAC < 3.0)
vTurbulenceNED(3) *= HOverBMAC * 0.3333;
// Yaw component of turbulence.
vTurbulenceNED(1) = sin( delta * 3.0 );
vTurbulenceNED(2) = cos( delta * 3.0 );
// Roll component of turbulence. Clockwise vortex causes left roll.
vTurbPQR(eP) += delta * 0.04;
spike = spike * 0.9;
case eCelsius:
targetTemp = t*9.0/5.0 + 32.0 + 459.67;
break;
case eRankine:
targetTemp = t;
break;
case eKelvin:
targetTemp = t*9.0/5.0;
break;
}
case ttMilspec:
case ttTustin: {
double V = FDMExec->GetAuxiliary()->GetVt(); // true airspeed in ft/s
// an index of zero means turbulence is disabled
// airspeed occurs as divisor in the code below
if (probability_of_exceedence_index == 0 || V == 0) {
vTurbulenceNED(1) = vTurbulenceNED(2) = vTurbulenceNED(3) = 0.0;
vTurbPQR(1) = vTurbPQR(2) = vTurbPQR(3) = 0.0;
return;
}
// Turbulence model according to MIL-F-8785C (Flying Qualities of Piloted Aircraft)
double
h = FDMExec->GetPropagate()->GetDistanceAGL(),
b_w = wingspan,
L_u, L_w, sig_u, sig_w;
if (b_w == 0.) b_w = 30.;
// clip height functions at 10 ft
if (h <= 10.) h = 10;
// Scale lengths L and amplitudes sigma as function of height
if (h <= 1000) {
L_u = h/pow(0.177 + 0.000823*h, 1.2); // MIL-F-8785c, Fig. 10, p. 55
L_w = h;
sig_w = 0.1*windspeed_at_20ft;
sig_u = sig_w/pow(0.177 + 0.000823*h, 0.4); // MIL-F-8785c, Fig. 11, p. 56
} else if (h <= 2000) {
// linear interpolation between low altitude and high altitude models
L_u = L_w = 1000 + (h-1000.)/1000.*750.;
sig_u = sig_w = 0.1*windspeed_at_20ft
+ (h-1000.)/1000.*(POE_Table->GetValue(probability_of_exceedence_index, h) - 0.1*windspeed_at_20ft);
} else {
L_u = L_w = 1750.; // MIL-F-8785c, Sec. 3.7.2.1, p. 48
sig_u = sig_w = POE_Table->GetValue(probability_of_exceedence_index, h);
}
// keep values from last timesteps
// TODO maybe use deque?
static double
xi_u_km1 = 0, nu_u_km1 = 0,
xi_v_km1 = 0, xi_v_km2 = 0, nu_v_km1 = 0, nu_v_km2 = 0,
xi_w_km1 = 0, xi_w_km2 = 0, nu_w_km1 = 0, nu_w_km2 = 0,
xi_p_km1 = 0, nu_p_km1 = 0,
xi_q_km1 = 0, xi_r_km1 = 0;
double
T_V = DeltaT, // for compatibility of nomenclature
sig_p = 1.9/sqrt(L_w*b_w)*sig_w, // Yeager1998, eq. (8)
sig_q = sqrt(M_PI/2/L_w/b_w), // eq. (14)
sig_r = sqrt(2*M_PI/3/L_w/b_w), // eq. (17)
L_p = sqrt(L_w*b_w)/2.6, // eq. (10)
tau_u = L_u/V, // eq. (6)
tau_w = L_w/V, // eq. (3)
tau_p = L_p/V, // eq. (9)
tau_q = 4*b_w/M_PI/V, // eq. (13)
tau_r =3*b_w/M_PI/V, // eq. (17)
nu_u = GaussianRandomNumber(),
nu_v = GaussianRandomNumber(),
nu_w = GaussianRandomNumber(),
nu_p = GaussianRandomNumber(),
xi_u=0, xi_v=0, xi_w=0, xi_p=0, xi_q=0, xi_r=0;
// values of turbulence NED velocities
if (turbType == ttTustin) {
// the following is the Tustin formulation of Yeager's report
double
omega_w = V/L_w, // hidden in nomenclature p. 3
omega_v = V/L_u, // this is defined nowhere
C_BL = 1/tau_u/tan(T_V/2/tau_u), // eq. (19)
C_BLp = 1/tau_p/tan(T_V/2/tau_p), // eq. (22)
C_BLq = 1/tau_q/tan(T_V/2/tau_q), // eq. (24)
C_BLr = 1/tau_r/tan(T_V/2/tau_r); // eq. (26)
// all values calculated so far are strictly positive, except for
// the random numbers nu_*. This means that in the code below, all
// divisors are strictly positive, too, and no floating point
// exception should occur.
xi_u = -(1 - C_BL*tau_u)/(1 + C_BL*tau_u)*xi_u_km1
+ sig_u*sqrt(2*tau_u/T_V)/(1 + C_BL*tau_u)*(nu_u + nu_u_km1); // eq. (18)
xi_v = -2*(sqr(omega_v) - sqr(C_BL))/sqr(omega_v + C_BL)*xi_v_km1
- sqr(omega_v - C_BL)/sqr(omega_v + C_BL) * xi_v_km2
+ sig_u*sqrt(3*omega_v/T_V)/sqr(omega_v + C_BL)*(
(C_BL + omega_v/sqrt(3.))*nu_v
+ 2/sqrt(3.)*omega_v*nu_v_km1
+ (omega_v/sqrt(3.) - C_BL)*nu_v_km2); // eq. (20) for v
xi_w = -2*(sqr(omega_w) - sqr(C_BL))/sqr(omega_w + C_BL)*xi_w_km1
- sqr(omega_w - C_BL)/sqr(omega_w + C_BL) * xi_w_km2
+ sig_w*sqrt(3*omega_w/T_V)/sqr(omega_w + C_BL)*(
(C_BL + omega_w/sqrt(3.))*nu_w
+ 2/sqrt(3.)*omega_w*nu_w_km1
+ (omega_w/sqrt(3.) - C_BL)*nu_w_km2); // eq. (20) for w
xi_p = -(1 - C_BLp*tau_p)/(1 + C_BLp*tau_p)*xi_p_km1
+ sig_p*sqrt(2*tau_p/T_V)/(1 + C_BLp*tau_p) * (nu_p + nu_p_km1); // eq. (21)
xi_q = -(1 - 4*b_w*C_BLq/M_PI/V)/(1 + 4*b_w*C_BLq/M_PI/V) * xi_q_km1
+ C_BLq/V/(1 + 4*b_w*C_BLq/M_PI/V) * (xi_w - xi_w_km1); // eq. (23)
xi_r = - (1 - 3*b_w*C_BLr/M_PI/V)/(1 + 3*b_w*C_BLr/M_PI/V) * xi_r_km1
+ C_BLr/V/(1 + 3*b_w*C_BLr/M_PI/V) * (xi_v - xi_v_km1); // eq. (25)
} else if (turbType == ttMilspec) {
// the following is the MIL-STD-1797A formulation
// as cited in Yeager's report
xi_u = (1 - T_V/tau_u) *xi_u_km1 + sig_u*sqrt(2*T_V/tau_u)*nu_u; // eq. (30)
xi_v = (1 - 2*T_V/tau_u)*xi_v_km1 + sig_u*sqrt(4*T_V/tau_u)*nu_v; // eq. (31)
xi_w = (1 - 2*T_V/tau_w)*xi_w_km1 + sig_w*sqrt(4*T_V/tau_w)*nu_w; // eq. (32)
xi_p = (1 - T_V/tau_p) *xi_p_km1 + sig_p*sqrt(2*T_V/tau_p)*nu_p; // eq. (33)
xi_q = (1 - T_V/tau_q) *xi_q_km1 + M_PI/4/b_w*(xi_w - xi_w_km1); // eq. (34)
xi_r = (1 - T_V/tau_r) *xi_r_km1 + M_PI/3/b_w*(xi_v - xi_v_km1); // eq. (35)
}
// rotate by wind azimuth and assign the velocities
double cospsi = cos(psiw), sinpsi = sin(psiw);
vTurbulenceNED(1) = cospsi*xi_u + sinpsi*xi_v;
vTurbulenceNED(2) = -sinpsi*xi_u + cospsi*xi_v;
vTurbulenceNED(3) = xi_w;
vTurbPQR(1) = cospsi*xi_p + sinpsi*xi_q;
vTurbPQR(2) = -sinpsi*xi_p + cospsi*xi_q;
vTurbPQR(3) = xi_r;
// vTurbPQR is in the body fixed frame, not NED
vTurbPQR = Tl2b*vTurbPQR;
// hand on the values for the next timestep
xi_u_km1 = xi_u; nu_u_km1 = nu_u;
xi_v_km2 = xi_v_km1; xi_v_km1 = xi_v; nu_v_km2 = nu_v_km1; nu_v_km1 = nu_v;
xi_w_km2 = xi_w_km1; xi_w_km1 = xi_w; nu_w_km2 = nu_w_km1; nu_w_km1 = nu_w;
xi_p_km1 = xi_p; nu_p_km1 = nu_p;
xi_q_km1 = xi_q;
xi_r_km1 = xi_r;
}
default:
break;
}
return targetTemp;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGAtmosphere::UseExternal(void)
double FGAtmosphere::ConvertToPSF(double p, ePressure unit) const
{
temperature=&exTemperature;
pressure=&exPressure;
density=&exDensity;
useExternal=true;
}
double targetPressure=0; // Pressure in PSF
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
switch(unit) {
case ePSF:
targetPressure = p;
break;
case eMillibars:
targetPressure = p*2.08854342;
break;
case ePascals:
targetPressure = p*0.0208854342;
break;
case eInchesHg:
targetPressure = p*70.7180803;
break;
default:
throw("Undefined pressure unit given");
}
void FGAtmosphere::UseInternal(void)
{
temperature=&intTemperature;
pressure=&intPressure;
density=&intDensity;
useExternal=false;
return targetPressure;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGAtmosphere::bind(void)
{
typedef double (FGAtmosphere::*PMF)(int) const;
typedef double (FGAtmosphere::*PMFv)(void) const;
typedef int (FGAtmosphere::*PMFt)(void) const;
typedef void (FGAtmosphere::*PMFd)(int,double);
typedef void (FGAtmosphere::*PMFi)(int);
PropertyManager->Tie("atmosphere/T-R", this, (PMFv)&FGAtmosphere::GetTemperature);
PropertyManager->Tie("atmosphere/rho-slugs_ft3", this, (PMFv)&FGAtmosphere::GetDensity);
PropertyManager->Tie("atmosphere/P-psf", this, (PMFv)&FGAtmosphere::GetPressure);
typedef double (FGAtmosphere::*PMFi)(int) const;
typedef void (FGAtmosphere::*PMF)(int, double);
PropertyManager->Tie("atmosphere/T-R", this, &FGAtmosphere::GetTemperature);
PropertyManager->Tie("atmosphere/rho-slugs_ft3", this, &FGAtmosphere::GetDensity);
PropertyManager->Tie("atmosphere/P-psf", this, &FGAtmosphere::GetPressure);
PropertyManager->Tie("atmosphere/a-fps", this, &FGAtmosphere::GetSoundSpeed);
PropertyManager->Tie("atmosphere/T-sl-R", this, &FGAtmosphere::GetTemperatureSL);
PropertyManager->Tie("atmosphere/rho-sl-slugs_ft3", this, &FGAtmosphere::GetDensitySL);
@ -712,53 +223,8 @@ void FGAtmosphere::bind(void)
PropertyManager->Tie("atmosphere/sigma", this, &FGAtmosphere::GetDensityRatio);
PropertyManager->Tie("atmosphere/delta", this, &FGAtmosphere::GetPressureRatio);
PropertyManager->Tie("atmosphere/a-ratio", this, &FGAtmosphere::GetSoundSpeedRatio);
PropertyManager->Tie("atmosphere/psiw-rad", this, &FGAtmosphere::GetWindPsi, &FGAtmosphere::SetWindPsi);
PropertyManager->Tie("atmosphere/delta-T", this, &FGAtmosphere::GetDeltaT, &FGAtmosphere::SetDeltaT);
PropertyManager->Tie("atmosphere/T-sl-dev-F", this, &FGAtmosphere::GetSLTempDev, &FGAtmosphere::SetSLTempDev);
PropertyManager->Tie("atmosphere/density-altitude", this, &FGAtmosphere::GetDensityAltitude);
PropertyManager->Tie("atmosphere/wind-north-fps", this, eNorth, (PMF)&FGAtmosphere::GetWindNED,
(PMFd)&FGAtmosphere::SetWindNED);
PropertyManager->Tie("atmosphere/wind-east-fps", this, eEast, (PMF)&FGAtmosphere::GetWindNED,
(PMFd)&FGAtmosphere::SetWindNED);
PropertyManager->Tie("atmosphere/wind-down-fps", this, eDown, (PMF)&FGAtmosphere::GetWindNED,
(PMFd)&FGAtmosphere::SetWindNED);
PropertyManager->Tie("atmosphere/wind-mag-fps", this, &FGAtmosphere::GetWindspeed,
&FGAtmosphere::SetWindspeed);
PropertyManager->Tie("atmosphere/total-wind-north-fps", this, eNorth, (PMF)&FGAtmosphere::GetTotalWindNED);
PropertyManager->Tie("atmosphere/total-wind-east-fps", this, eEast, (PMF)&FGAtmosphere::GetTotalWindNED);
PropertyManager->Tie("atmosphere/total-wind-down-fps", this, eDown, (PMF)&FGAtmosphere::GetTotalWindNED);
PropertyManager->Tie("atmosphere/gust-north-fps", this, eNorth, (PMF)&FGAtmosphere::GetGustNED,
(PMFd)&FGAtmosphere::SetGustNED);
PropertyManager->Tie("atmosphere/gust-east-fps", this, eEast, (PMF)&FGAtmosphere::GetGustNED,
(PMFd)&FGAtmosphere::SetGustNED);
PropertyManager->Tie("atmosphere/gust-down-fps", this, eDown, (PMF)&FGAtmosphere::GetGustNED,
(PMFd)&FGAtmosphere::SetGustNED);
PropertyManager->Tie("atmosphere/turb-north-fps", this, eNorth, (PMF)&FGAtmosphere::GetTurbNED,
(PMFd)&FGAtmosphere::SetTurbNED);
PropertyManager->Tie("atmosphere/turb-east-fps", this, eEast, (PMF)&FGAtmosphere::GetTurbNED,
(PMFd)&FGAtmosphere::SetTurbNED);
PropertyManager->Tie("atmosphere/turb-down-fps", this, eDown, (PMF)&FGAtmosphere::GetTurbNED,
(PMFd)&FGAtmosphere::SetTurbNED);
PropertyManager->Tie("atmosphere/p-turb-rad_sec", this,1, (PMF)&FGAtmosphere::GetTurbPQR);
PropertyManager->Tie("atmosphere/q-turb-rad_sec", this,2, (PMF)&FGAtmosphere::GetTurbPQR);
PropertyManager->Tie("atmosphere/r-turb-rad_sec", this,3, (PMF)&FGAtmosphere::GetTurbPQR);
PropertyManager->Tie("atmosphere/turb-type", this, (PMFt)&FGAtmosphere::GetTurbType, (PMFi)&FGAtmosphere::SetTurbType);
PropertyManager->Tie("atmosphere/turb-rate", this, &FGAtmosphere::GetTurbRate, &FGAtmosphere::SetTurbRate);
PropertyManager->Tie("atmosphere/turb-gain", this, &FGAtmosphere::GetTurbGain, &FGAtmosphere::SetTurbGain);
PropertyManager->Tie("atmosphere/turb-rhythmicity", this, &FGAtmosphere::GetRhythmicity,
&FGAtmosphere::SetRhythmicity);
PropertyManager->Tie("atmosphere/turbulence/milspec/windspeed_at_20ft_AGL-fps",
this, &FGAtmosphere::GetWindspeed20ft,
&FGAtmosphere::SetWindspeed20ft);
PropertyManager->Tie("atmosphere/turbulence/milspec/severity",
this, &FGAtmosphere::GetProbabilityOfExceedence,
&FGAtmosphere::SetProbabilityOfExceedence);
PropertyManager->Tie("atmosphere/pressure-altitude", this, &FGAtmosphere::GetPressureAltitude);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -789,8 +255,8 @@ void FGAtmosphere::Debug(int from)
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
if (from == 0) cout << "Instantiated: FGAtmosphere" << endl;
if (from == 1) cout << "Destroyed: FGAtmosphere" << endl;
if (from == 0) std::cout << "Instantiated: FGAtmosphere" << std::endl;
if (from == 1) std::cout << "Destroyed: FGAtmosphere" << std::endl;
}
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
}
@ -798,23 +264,12 @@ void FGAtmosphere::Debug(int from)
}
if (debug_lvl & 16) { // Sanity checking
}
if (debug_lvl & 128) { // Turbulence
if (first_pass && from == 2) {
first_pass = false;
cout << "vTurbulenceNED(X), vTurbulenceNED(Y), vTurbulenceNED(Z), "
<< "vTurbulenceGrad(X), vTurbulenceGrad(Y), vTurbulenceGrad(Z), "
<< "vDirection(X), vDirection(Y), vDirection(Z), "
<< "Magnitude, "
<< "vTurbPQR(P), vTurbPQR(Q), vTurbPQR(R), " << endl;
}
if (from == 2) {
cout << vTurbulenceNED << ", " << vTurbulenceGrad << ", " << vDirection << ", " << Magnitude << ", " << vTurbPQR << endl;
}
if (debug_lvl & 128) { //
}
if (debug_lvl & 64) {
if (from == 0) { // Constructor
cout << IdSrc << endl;
cout << IdHdr << endl;
std::cout << IdSrc << std::endl;
std::cout << IdHdr << std::endl;
}
}
}

View file

@ -2,10 +2,9 @@
Header: FGAtmosphere.h
Author: Jon Berndt
Implementation of 1959 Standard Atmosphere added by Tony Peden
Date started: 11/24/98
Date started: 6/2011
------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) -------------
------------- Copyright (C) 2011 Jon S. Berndt (jon@jsbsim.org) -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
@ -26,10 +25,7 @@
HISTORY
--------------------------------------------------------------------------------
11/24/98 JSB Created
07/23/99 TP Added implementation of 1959 Standard Atmosphere
Moved calculation of Mach number to FGPropagate
Updated to '76 model
5/2011 JSB Created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
@ -42,15 +38,14 @@ SENTRY
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGModel.h"
#include "math/FGColumnVector3.h"
#include "math/FGTable.h"
#include <vector>
#include "models/FGModel.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_ATMOSPHERE "$Id: FGAtmosphere.h,v 1.26 2011/05/20 03:18:36 jberndt Exp $"
#define ID_ATMOSPHERE "$Id: FGAtmosphere.h,v 1.29 2011/07/10 20:18:14 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -62,62 +57,24 @@ namespace JSBSim {
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Models the 1976 Standard Atmosphere.
@author Tony Peden, Jon Berndt
@version $Id: FGAtmosphere.h,v 1.26 2011/05/20 03:18:36 jberndt Exp $
@see Anderson, John D. "Introduction to Flight, Third Edition", McGraw-Hill,
1989, ISBN 0-07-001641-0
/** Models an empty, abstract base atmosphere class.
Additionally, various turbulence models are available. They are specified
via the property <tt>atmosphere/turb-type</tt>. The following models are
available:
- 0: ttNone (turbulence disabled)
- 1: ttStandard
- 2: ttBerndt
- 3: ttCulp
- 4: ttMilspec (Dryden spectrum)
- 5: ttTustin (Dryden spectrum)
The Milspec and Tustin models are described in the Yeager report cited below.
They both use a Dryden spectrum model whose parameters (scale lengths and intensities)
are modelled according to MIL-F-8785C. Parameters are modelled differently
for altitudes below 1000ft and above 2000ft, for altitudes in between they
are interpolated linearly.
The two models differ in the implementation of the transfer functions
described in the milspec.
To use one of these two models, set <tt>atmosphere/turb-type</tt> to 4 resp. 5,
and specify values for <tt>atmosphere/turbulence/milspec/windspeed_at_20ft_AGL-fps<tt>
and <tt>atmosphere/turbulence/milspec/severity<tt> (the latter corresponds to
the probability of exceedence curves from Fig.&nbsp;7 of the milspec, allowable
range is 0 (disabled) to 7). <tt>atmosphere/psiw-rad</tt> is respected as well;
note that you have to specify a positive wind magnitude to prevent psiw from
being reset to zero.
Reference values (cf. figures 7 and 9 from the milspec):
<table>
<tr><td><b>Intensity</b></td>
<td><b><tt>windspeed_at_20ft_AGL-fps</tt></b></td>
<td><b><tt>severity</tt></b></td></tr>
<tr><td>light</td>
<td>25 (15 knots)</td>
<td>3</td></tr>
<tr><td>moderate</td>
<td>50 (30 knots)</td>
<td>4</td></tr>
<tr><td>severe</td>
<td>75 (45 knots)</td>
<td>6</td></tr>
</table>
@see Yeager, Jessie C.: "Implementation and Testing of Turbulence Models for
the F18-HARV" (<a
href="http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19980028448_1998081596.pdf">
pdf</a>), NASA CR-1998-206937, 1998
@see MIL-F-8785C: Military Specification: Flying Qualities of Piloted Aircraft
<h2> Properties </h2>
@property atmosphere/T-R The current modeled temperature in degrees Rankine.
@property atmosphere/rho-slugs_ft3
@property atmosphere/P-psf
@property atmosphere/a-fps
@property atmosphere/T-sl-R
@property atmosphere/rho-sl-slugs_ft3
@property atmosphere/P-sl-psf
@property atmosphere/a-sl-fps
@property atmosphere/theta
@property atmosphere/sigma
@property atmosphere/delta
@property atmosphere/a-ratio
@author Jon Berndt
@version $Id: FGAtmosphere.h,v 1.29 2011/07/10 20:18:14 jberndt Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -127,11 +84,19 @@ CLASS DECLARATION
class FGAtmosphere : public FGModel {
public:
/// Enums for specifying temperature units.
enum eTemperature {eNoTempUnit=0, eFahrenheit, eCelsius, eRankine, eKelvin};
/// Enums for specifying pressure units.
enum ePressure {eNoPressUnit=0, ePSF, eMillibars, ePascals, eInchesHg};
/// Constructor
FGAtmosphere(FGFDMExec*);
/// Destructor
~FGAtmosphere();
/** Runs the Atmosphere model; called by the Executive
virtual ~FGAtmosphere();
/** Runs the atmosphere forces model; called by the Executive.
Can pass in a value indicating if the executive is directing the simulation to Hold.
@param Holding if true, the executive has been directed to hold the sim from
advancing time. Some models may ignore this flag, such as the Input
@ -139,210 +104,137 @@ public:
"Resume" command to be given.
@return false if no error */
bool Run(bool Holding);
bool InitModel(void);
enum tType {ttNone, ttStandard, ttCulp, ttMilspec, ttTustin} turbType;
/// Returns the temperature in degrees Rankine.
virtual double GetTemperature(void) const {return *temperature;}
/** Returns the density in slugs/ft^3.
<i>This function may <b>only</b> be used if Run() is called first.</i> */
virtual double GetDensity(void) const {return *density;}
// *************************************************************************
/// @name Temperature access functions.
/// There are several ways to get the temperature, and several modeled temperature
/// values that can be retrieved.
// @{
/// Returns the actual, modeled temperature at the current altitude in degrees Rankine.
/// @return Modeled temperature in degrees Rankine.
virtual double GetTemperature() const {return Temperature;}
/// Returns the actual modeled temperature in degrees Rankine at a specified altitude.
/// @param altitude The altitude above sea level (ASL) in feet.
/// @return Modeled temperature in degrees Rankine at the specified altitude.
virtual double GetTemperature(double altitude) const = 0;
/// Returns the actual, modeled sea level temperature in degrees Rankine.
/// @return The modeled temperature in degrees Rankine at sea level.
virtual double GetTemperatureSL() const { return GetTemperature(0.0); }
/// Returns the ratio of the at-current-altitude temperature as modeled
/// over the sea level value.
virtual double GetTemperatureRatio() const { return GetTemperature()*rSLtemperature; }
/// Returns the ratio of the temperature as modeled at the supplied altitude
/// over the sea level value.
virtual double GetTemperatureRatio(double h) const { return GetTemperature(h)*rSLtemperature; }
/// Sets the Sea Level temperature.
/// @param t the temperature value in the unit provided.
/// @param unit the unit of the temperature.
virtual void SetTemperatureSL(double t, eTemperature unit=eFahrenheit);
/// Sets the temperature at the supplied altitude.
/// @param t The temperature value in the unit provided.
/// @param h The altitude in feet above sea level.
/// @param unit The unit of the temperature.
virtual void SetTemperature(double t, double h, eTemperature unit=eFahrenheit) = 0;
//@}
// *************************************************************************
/// @name Pressure access functions.
//@{
/// Returns the pressure in psf.
virtual double GetPressure(void) const {return *pressure;}
/// Returns the standard pressure at a specified altitude
virtual double GetPressure(double altitude);
/// Returns the standard temperature at a specified altitude
virtual double GetTemperature(double altitude);
/// Returns the standard density at a specified altitude
virtual double GetDensity(double altitude);
/// Returns the speed of sound in ft/sec.
virtual double GetSoundSpeed(void) const {return soundspeed;}
/// Returns the absolute viscosity.
virtual double GetAbsoluteViscosity(void) const {return intViscosity;}
/// Returns the kinematic viscosity.
virtual double GetKinematicViscosity(void) const {return intKinematicViscosity;}
virtual double GetPressure(void) const {return Pressure;}
/// Returns the pressure at a specified altitude in psf.
virtual double GetPressure(double altitude) const = 0;
/// Returns the sea level temperature in degrees Rankine.
virtual double GetTemperatureSL(void) const { return SLtemperature; }
/// Returns the sea level density in slugs/ft^3
virtual double GetDensitySL(void) const { return SLdensity; }
/// Returns the sea level pressure in psf.
virtual double GetPressureSL(void) const { return SLpressure; }
/// Returns the ratio of at-altitude pressure over the sea level value.
virtual double GetPressureRatio(void) const { return Pressure*rSLpressure; }
/** Sets the sea level pressure for modeling.
@param pressure The pressure in the units specified (PSF by default).
@param unit the unit of measure that the specified pressure is
supplied in.*/
virtual void SetPressureSL(double pressure, ePressure unit=ePSF);
//@}
// *************************************************************************
/// @name Density access functions.
//@{
/** Returns the density in slugs/ft^3.
This function may only be used if Run() is called first. */
virtual double GetDensity(void) const {return Density;}
/** Returns the density in slugs/ft^3 at a given altitude in ft. */
virtual double GetDensity(double altitude) const;
/// Returns the sea level density in slugs/ft^3
virtual double GetDensitySL(void) const { return SLdensity; }
/// Returns the ratio of at-altitude density over the sea level value.
virtual double GetDensityRatio(void) const { return Density*rSLdensity; }
//@}
// *************************************************************************
/// @name Speed of sound access functions.
//@{
/// Returns the speed of sound in ft/sec.
virtual double GetSoundSpeed(void) const {return Soundspeed;}
/// Returns the sea level speed of sound in ft/sec.
virtual double GetSoundSpeedSL(void) const { return SLsoundspeed; }
/// Returns the ratio of at-altitude temperature over the sea level value.
virtual double GetTemperatureRatio(void) const { return (*temperature)*rSLtemperature; }
/// Returns the ratio of at-altitude density over the sea level value.
virtual double GetDensityRatio(void) const { return (*density)*rSLdensity; }
/// Returns the ratio of at-altitude pressure over the sea level value.
virtual double GetPressureRatio(void) const { return (*pressure)*rSLpressure; }
/// Returns the ratio of at-altitude sound speed over the sea level value.
virtual double GetSoundSpeedRatio(void) const { return soundspeed*rSLsoundspeed; }
virtual double GetSoundSpeedRatio(void) const { return Soundspeed*rSLsoundspeed; }
//@}
/// Tells the simulator to use an externally calculated atmosphere model.
virtual void UseExternal(void);
/// Tells the simulator to use the internal atmosphere model.
virtual void UseInternal(void); //this is the default
/// Gets the boolean that tells if the external atmosphere model is being used.
virtual bool External(void) { return useExternal; }
// *************************************************************************
/// @name Viscosity access functions.
//@{
/// Returns the absolute viscosity.
virtual double GetAbsoluteViscosity(void) const {return Viscosity;}
/// Provides the external atmosphere model with an interface to set the temperature.
virtual void SetExTemperature(double t) { exTemperature=t; }
/// Provides the external atmosphere model with an interface to set the density.
virtual void SetExDensity(double d) { exDensity=d; }
/// Provides the external atmosphere model with an interface to set the pressure.
virtual void SetExPressure(double p) { exPressure=p; }
/// Returns the kinematic viscosity.
virtual double GetKinematicViscosity(void) const {return KinematicViscosity;}
//@}
/// Sets the temperature deviation at sea-level in degrees Fahrenheit
virtual void SetSLTempDev(double d) { T_dev_sl = d; }
/// Gets the temperature deviation at sea-level in degrees Fahrenheit
virtual double GetSLTempDev(void) const { return T_dev_sl; }
/// Sets the current delta-T in degrees Fahrenheit
virtual void SetDeltaT(double d) { delta_T = d; }
/// Gets the current delta-T in degrees Fahrenheit
virtual double GetDeltaT(void) const { return delta_T; }
/// Gets the at-altitude temperature deviation in degrees Fahrenheit
virtual double GetTempDev(void) const { return T_dev; }
/// Gets the density altitude in feet
virtual double GetDensityAltitude(void) const { return density_altitude; }
virtual double GetDensityAltitude() const {return DensityAltitude;}
// TOTAL WIND access functions (wind + gust + turbulence)
virtual double GetPressureAltitude() const {return PressureAltitude;}
/// Retrieves the total wind components in NED frame.
virtual const FGColumnVector3& GetTotalWindNED(void) const { return vTotalWindNED; }
/// Retrieves a total wind component in NED frame.
virtual double GetTotalWindNED(int idx) const {return vTotalWindNED(idx);}
// WIND access functions
/// Sets the wind components in NED frame.
virtual void SetWindNED(double wN, double wE, double wD) { vWindNED(1)=wN; vWindNED(2)=wE; vWindNED(3)=wD;}
/// Sets a wind component in NED frame.
virtual void SetWindNED(int idx, double wind) { vWindNED(idx)=wind;}
/// Retrieves the wind components in NED frame.
virtual FGColumnVector3& GetWindNED(void) { return vWindNED; }
/// Retrieves a wind component in NED frame.
virtual double GetWindNED(int idx) const {return vWindNED(idx);}
/** Retrieves the direction that the wind is coming from.
The direction is defined as north=0 and increases counterclockwise.
The wind heading is returned in radians.*/
virtual double GetWindPsi(void) const { return psiw; }
/** Sets the direction that the wind is coming from.
The direction is defined as north=0 and increases counterclockwise to 2*pi (radians). The
vertical component of wind is assumed to be zero - and is forcibly set to zero. This function
sets the vWindNED vector components based on the supplied direction. The magnitude of
the wind set in the vector is preserved (assuming the vertical component is non-zero).
@param dir wind direction in the horizontal plane, in radians.*/
virtual void SetWindPsi(double dir);
virtual void SetWindspeed(double speed);
virtual double GetWindspeed(void) const;
// GUST access functions
/// Sets a gust component in NED frame.
virtual void SetGustNED(int idx, double gust) { vGustNED(idx)=gust;}
/// Sets a turbulence component in NED frame.
virtual void SetTurbNED(int idx, double turb) { vTurbulenceNED(idx)=turb;}
/// Sets the gust components in NED frame.
virtual void SetGustNED(double gN, double gE, double gD) { vGustNED(eNorth)=gN; vGustNED(eEast)=gE; vGustNED(eDown)=gD;}
/// Retrieves a gust component in NED frame.
virtual double GetGustNED(int idx) const {return vGustNED(idx);}
/// Retrieves a turbulence component in NED frame.
virtual double GetTurbNED(int idx) const {return vTurbulenceNED(idx);}
/// Retrieves the gust components in NED frame.
virtual FGColumnVector3& GetGustNED(void) {return vGustNED;}
/** Turbulence models available: ttNone, ttStandard, ttBerndt, ttCulp, ttMilspec, ttTustin */
virtual void SetTurbType(tType tt) {turbType = tt;}
virtual tType GetTurbType() const {return turbType;}
virtual void SetTurbGain(double tg) {TurbGain = tg;}
virtual double GetTurbGain() const {return TurbGain;}
virtual void SetTurbRate(double tr) {TurbRate = tr;}
virtual double GetTurbRate() const {return TurbRate;}
virtual void SetRhythmicity(double r) {Rhythmicity=r;}
virtual double GetRhythmicity() const {return Rhythmicity;}
virtual double GetTurbPQR(int idx) const {return vTurbPQR(idx);}
virtual double GetTurbMagnitude(void) const {return Magnitude;}
virtual const FGColumnVector3& GetTurbDirection(void) const {return vDirection;}
virtual const FGColumnVector3& GetTurbPQR(void) const {return vTurbPQR;}
virtual void SetWindspeed20ft(double ws) { windspeed_at_20ft = ws;}
virtual double GetWindspeed20ft() const { return windspeed_at_20ft;}
/// allowable range: 0-7, 3=light, 4=moderate, 6=severe turbulence
virtual void SetProbabilityOfExceedence( int idx) {probability_of_exceedence_index = idx;}
virtual int GetProbabilityOfExceedence() const { return probability_of_exceedence_index;}
struct Inputs {
double altitudeASL;
} in;
protected:
double rho;
double SLtemperature, SLdensity, SLpressure, SLsoundspeed; // Sea level conditions
double Temperature, Density, Pressure, Soundspeed; // Current actual conditions at altitude
double rSLtemperature, rSLdensity, rSLpressure, rSLsoundspeed; // Reciprocal of sea level conditions
struct atmType {double Temperature; double Pressure; double Density;};
int lastIndex;
double h;
double htab[8];
double StdSLtemperature,StdSLdensity,StdSLpressure,StdSLsoundspeed;
double rSLtemperature,rSLdensity,rSLpressure,rSLsoundspeed; //reciprocals
double SLtemperature,SLdensity,SLpressure,SLsoundspeed;
double *temperature, *density, *pressure;
double soundspeed;
bool useExternal;
double exTemperature,exDensity,exPressure;
double intTemperature, intDensity, intPressure;
double SutherlandConstant, Beta, intViscosity, intKinematicViscosity;
double T_dev_sl, T_dev, delta_T, density_altitude;
atmType atmosphere;
bool StandardTempOnly;
bool first_pass;
double PressureAltitude;
double DensityAltitude;
double MagnitudedAccelDt, MagnitudeAccel, Magnitude;
double TurbGain;
double TurbRate;
double Rhythmicity;
double wind_from_clockwise;
double spike, target_time, strength;
FGColumnVector3 vDirectiondAccelDt;
FGColumnVector3 vDirectionAccel;
FGColumnVector3 vDirection;
FGColumnVector3 vTurbulenceGrad;
FGColumnVector3 vBodyTurbGrad;
FGColumnVector3 vTurbPQR;
const double SutherlandConstant, Beta;
double Viscosity, KinematicViscosity;
// Dryden turbulence model
double windspeed_at_20ft; ///< in ft/s
int probability_of_exceedence_index; ///< this is bound as the severity property
FGTable *POE_Table; ///< probability of exceedence table
double psiw;
FGColumnVector3 vTotalWindNED;
FGColumnVector3 vWindNED;
FGColumnVector3 vGustNED;
FGColumnVector3 vTurbulenceNED;
/// Calculate the atmosphere for the given altitude, including effects of temperature deviation.
/// Calculate the atmosphere for the given altitude.
void Calculate(double altitude);
/// Calculate atmospheric properties other than the basic T, P and rho.
void CalculateDerived(void);
/// Get T, P and rho for a standard atmosphere at the given altitude.
void GetStdAtmosphere(double altitude);
void Turbulence(void);
// Converts to Rankine from one of several unit systems.
virtual double ConvertToRankine(double t, eTemperature unit) const;
// Converts to PSF (pounds per square foot) from one of several unit systems.
virtual double ConvertToPSF(double t, ePressure unit=ePSF) const;
virtual void bind(void);
void Debug(int from);
};

313
src/FDM/JSBSim/models/FGAuxiliary.cpp Executable file → Normal file
View file

@ -40,26 +40,17 @@ HISTORY
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGAuxiliary.h"
#include "FGAerodynamics.h"
#include "FGPropagate.h"
#include "FGAtmosphere.h"
#include "FGFDMExec.h"
#include "FGAircraft.h"
#include "FGInertial.h"
#include "FGExternalReactions.h"
#include "FGBuoyantForces.h"
#include "FGGroundReactions.h"
#include "FGPropulsion.h"
#include "FGMassBalance.h"
#include "input_output/FGPropertyManager.h"
#include <iostream>
#include "FGAuxiliary.h"
#include "FGFDMExec.h"
#include "input_output/FGPropertyManager.h"
using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGAuxiliary.cpp,v 1.49 2011/05/20 03:18:36 jberndt Exp $";
static const char *IdSrc = "$Id: FGAuxiliary.cpp,v 1.53 2011/08/17 23:56:01 jberndt Exp $";
static const char *IdHdr = ID_AUXILIARY;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -70,9 +61,8 @@ CLASS IMPLEMENTATION
FGAuxiliary::FGAuxiliary(FGFDMExec* fdmex) : FGModel(fdmex)
{
Name = "FGAuxiliary";
pt = p = psl = 1.0;
rho = rhosl = 1.0;
tat = sat = 1.0;
pt = 1.0;
tat = 1.0;
tatc = RankineToCelsius(tat);
vcas = veas = 0.0;
@ -91,13 +81,11 @@ FGAuxiliary::FGAuxiliary(FGFDMExec* fdmex) : FGModel(fdmex)
vPilotAccel.InitMatrix();
vPilotAccelN.InitMatrix();
vToEyePt.InitMatrix();
vAeroUVW.InitMatrix();
vAeroPQR.InitMatrix();
vMachUVW.InitMatrix();
vEuler.InitMatrix();
vEulerRates.InitMatrix();
vAircraftAccel.InitMatrix();
bind();
@ -108,11 +96,8 @@ FGAuxiliary::FGAuxiliary(FGFDMExec* fdmex) : FGModel(fdmex)
bool FGAuxiliary::InitModel(void)
{
pt = p = FDMExec->GetAtmosphere()->GetPressure();
rho = FDMExec->GetAtmosphere()->GetDensity();
rhosl = FDMExec->GetAtmosphere()->GetDensitySL();
psl = FDMExec->GetAtmosphere()->GetPressureSL();
tat = sat = FDMExec->GetAtmosphere()->GetTemperature();
pt = in.Pressure;
tat = in.Temperature;
tatc = RankineToCelsius(tat);
vcas = veas = 0.0;
@ -131,13 +116,11 @@ bool FGAuxiliary::InitModel(void)
vPilotAccel.InitMatrix();
vPilotAccelN.InitMatrix();
vToEyePt.InitMatrix();
vAeroUVW.InitMatrix();
vAeroPQR.InitMatrix();
vMachUVW.InitMatrix();
vEuler.InitMatrix();
vEulerRates.InitMatrix();
vAircraftAccel.InitMatrix();
return true;
}
@ -160,139 +143,118 @@ bool FGAuxiliary::Run(bool Holding)
RunPreFunctions();
const double density = FDMExec->GetAtmosphere()->GetDensity();
const double soundspeed = FDMExec->GetAtmosphere()->GetSoundSpeed();
const double DistanceAGL = FDMExec->GetPropagate()->GetDistanceAGL();
const double wingspan = FDMExec->GetAircraft()->GetWingSpan();
const FGMatrix33& Tl2b = FDMExec->GetPropagate()->GetTl2b();
const FGMatrix33& Tb2l = FDMExec->GetPropagate()->GetTb2l();
const FGColumnVector3& vPQR = FDMExec->GetPropagate()->GetPQR();
const FGColumnVector3& vUVW = FDMExec->GetPropagate()->GetUVW();
const FGColumnVector3& vUVWdot = FDMExec->GetPropagate()->GetUVWdot();
const FGColumnVector3& vVel = FDMExec->GetPropagate()->GetVel();
p = FDMExec->GetAtmosphere()->GetPressure();
rhosl = FDMExec->GetAtmosphere()->GetDensitySL();
psl = FDMExec->GetAtmosphere()->GetPressureSL();
sat = FDMExec->GetAtmosphere()->GetTemperature();
// Rotation
double cTht = FDMExec->GetPropagate()->GetCosEuler(eTht);
double sTht = FDMExec->GetPropagate()->GetSinEuler(eTht);
double cPhi = FDMExec->GetPropagate()->GetCosEuler(ePhi);
double sPhi = FDMExec->GetPropagate()->GetSinEuler(ePhi);
vEulerRates(eTht) = vPQR(eQ)*cPhi - vPQR(eR)*sPhi;
if (cTht != 0.0) {
vEulerRates(ePsi) = (vPQR(eQ)*sPhi + vPQR(eR)*cPhi)/cTht;
vEulerRates(ePhi) = vPQR(eP) + vEulerRates(ePsi)*sTht;
vEulerRates(eTht) = in.vPQR(eQ)*in.CosPhi - in.vPQR(eR)*in.SinPhi;
if (in.CosTht != 0.0) {
vEulerRates(ePsi) = (in.vPQR(eQ)*in.SinPhi + in.vPQR(eR)*in.CosPhi)/in.CosTht;
vEulerRates(ePhi) = in.vPQR(eP) + vEulerRates(ePsi)*in.SinTht;
}
// Combine the wind speed with aircraft speed to obtain wind relative speed
FGColumnVector3 wind = Tl2b*FDMExec->GetAtmosphere()->GetTotalWindNED();
vAeroPQR = vPQR - FDMExec->GetAtmosphere()->GetTurbPQR();
vAeroUVW = vUVW - wind;
vAeroPQR = in.vPQR - in.TurbPQR;
vAeroUVW = in.vUVW - in.Tl2b * in.TotalWindNED;
Vt = vAeroUVW.Magnitude();
double Vt2 = Vt*Vt;
alpha = beta = adot = bdot = 0;
double mUW = (vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
double AeroU2 = vAeroUVW(eU)*vAeroUVW(eU);
double AeroV2 = vAeroUVW(eV)*vAeroUVW(eV);
double AeroW2 = vAeroUVW(eW)*vAeroUVW(eW);
double mUW = AeroU2 + AeroW2;
double Vt2 = Vt*Vt;
if ( Vt > 1.0 ) {
if (vAeroUVW(eW) != 0.0)
alpha = vAeroUVW(eU)*vAeroUVW(eU) > 0.0 ? atan2(vAeroUVW(eW), vAeroUVW(eU)) : 0.0;
alpha = AeroU2 > 0.0 ? atan2(vAeroUVW(eW), vAeroUVW(eU)) : 0.0;
if (vAeroUVW(eV) != 0.0)
beta = mUW > 0.0 ? atan2(vAeroUVW(eV), sqrt(mUW)) : 0.0;
beta = mUW > 0.0 ? atan2(vAeroUVW(eV), sqrt(mUW)) : 0.0;
double signU=1;
if (vAeroUVW(eU) < 0.0) signU=-1;
if ( mUW >= 1.0 ) {
adot = (vAeroUVW(eU)*vUVWdot(eW) - vAeroUVW(eW)*vUVWdot(eU))/mUW;
bdot = (signU*mUW*vUVWdot(eV)
- vAeroUVW(eV)*(vAeroUVW(eU)*vUVWdot(eU) + vAeroUVW(eW)*vUVWdot(eW)))/(Vt2*sqrt(mUW));
adot = (vAeroUVW(eU)*in.vUVWdot(eW) - vAeroUVW(eW)*in.vUVWdot(eU))/mUW;
bdot = (signU*mUW*in.vUVWdot(eV)
- vAeroUVW(eV)*(vAeroUVW(eU)*in.vUVWdot(eU) + vAeroUVW(eW)*in.vUVWdot(eW)))/(Vt2*sqrt(mUW));
}
}
Re = Vt * FDMExec->GetAircraft()->Getcbar() / FDMExec->GetAtmosphere()->GetKinematicViscosity();
Re = Vt * in.Wingchord / in.KinematicViscosity;
qbar = 0.5*density*Vt2;
qbarUW = 0.5*density*(mUW);
qbarUV = 0.5*density*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eV)*vAeroUVW(eV));
Mach = Vt / soundspeed;
MachU = vMachUVW(eU) = vAeroUVW(eU) / soundspeed;
vMachUVW(eV) = vAeroUVW(eV) / soundspeed;
vMachUVW(eW) = vAeroUVW(eW) / soundspeed;
double densityD2 = 0.5*in.Density;
qbar = densityD2 * Vt2;
qbarUW = densityD2 * (mUW);
qbarUV = densityD2 * (AeroU2 + AeroV2);
Mach = Vt / in.SoundSpeed;
MachU = vMachUVW(eU) = vAeroUVW(eU) / in.SoundSpeed;
vMachUVW(eV) = vAeroUVW(eV) / in.SoundSpeed;
vMachUVW(eW) = vAeroUVW(eW) / in.SoundSpeed;
double MachU2 = MachU * MachU;
// Position
Vground = sqrt( vVel(eNorth)*vVel(eNorth) + vVel(eEast)*vVel(eEast) );
Vground = sqrt( in.vVel(eNorth)*in.vVel(eNorth) + in.vVel(eEast)*in.vVel(eEast) );
psigt = atan2(vVel(eEast), vVel(eNorth));
psigt = atan2(in.vVel(eEast), in.vVel(eNorth));
if (psigt < 0.0) psigt += 2*M_PI;
gamma = atan2(-vVel(eDown), Vground);
gamma = atan2(-in.vVel(eDown), Vground);
tat = sat*(1 + 0.2*Mach*Mach); // Total Temperature, isentropic flow
tat = in.Temperature*(1 + 0.2*Mach*Mach); // Total Temperature, isentropic flow
tatc = RankineToCelsius(tat);
if (MachU < 1) { // Calculate total pressure assuming isentropic flow
pt = p*pow((1 + 0.2*MachU*MachU),3.5);
pt = in.Pressure*pow((1 + 0.2*MachU2),3.5);
} else {
// Use Rayleigh pitot tube formula for normal shock in front of pitot tube
B = 5.76*MachU*MachU/(5.6*MachU*MachU - 0.8);
D = (2.8*MachU*MachU-0.4)*0.4167;
pt = p*pow(B,3.5)*D;
B = 5.76 * MachU2 / (5.6*MachU2 - 0.8);
D = (2.8 * MachU2 - 0.4) * 0.4167;
pt = in.Pressure*pow(B,3.5)*D;
}
A = pow(((pt-p)/psl+1),0.28571);
A = pow(((pt-in.Pressure)/in.PressureSL + 1),0.28571);
if (MachU > 0.0) {
vcas = sqrt(7*psl/rhosl*(A-1));
veas = sqrt(2*qbar/rhosl);
vcas = sqrt(7 * in.PressureSL / in.DensitySL * (A-1));
veas = sqrt(2 * qbar / in.DensitySL);
vtrue = 1116.43559 * MachU * sqrt(in.Temperature / 518.67);
} else {
vcas = veas = 0.0;
vcas = veas = vtrue = 0.0;
}
const double SLgravity = FDMExec->GetInertial()->SLgravity();
vPilotAccel.InitMatrix();
vNcg = in.vBodyAccel/in.SLGravity;
if ( Vt > 1.0 ) {
vAircraftAccel = FDMExec->GetAircraft()->GetBodyAccel();
// Nz is Acceleration in "g's", along normal axis (-Z body axis)
Nz = -vAircraftAccel(eZ)/SLgravity;
vToEyePt = FDMExec->GetMassBalance()->StructuralToBody(FDMExec->GetAircraft()->GetXYZep());
vPilotAccel = vAircraftAccel + FDMExec->GetPropagate()->GetPQRdot() * vToEyePt;
vPilotAccel += vPQR * (vPQR * vToEyePt);
// Nz is Acceleration in "g's", along normal axis (-Z body axis)
Nz = -vNcg(eZ);
vPilotAccel = in.vBodyAccel + in.vPQRdot * in.ToEyePt;
vPilotAccel += in.vPQR * (in.vPQR * in.ToEyePt);
} else {
// The line below handles low velocity (and on-ground) cases, basically
// representing the opposite of the force that the landing gear would
// exert on the ground (which is just the total weight). This eliminates
// any jitter that could be introduced by the landing gear. Theoretically,
// this branch could be eliminated, with a penalty of having a short
// transient at startup (lasting only a fraction of a second).
vPilotAccel = Tl2b * FGColumnVector3( 0.0, 0.0, -SLgravity );
Nz = -vPilotAccel(eZ)/SLgravity;
// The line below handles low velocity (and on-ground) cases, basically
// representing the opposite of the force that the landing gear would
// exert on the ground (which is just the total weight). This eliminates
// any jitter that could be introduced by the landing gear. Theoretically,
// this branch could be eliminated, with a penalty of having a short
// transient at startup (lasting only a fraction of a second).
vPilotAccel = in.Tl2b * FGColumnVector3( 0.0, 0.0, -in.SLGravity );
Nz = -vPilotAccel(eZ) / in.SLGravity;
}
vPilotAccelN = vPilotAccel/SLgravity;
vNwcg = mTb2w * vNcg;
vNwcg(eZ) = 1.0 - vNwcg(eZ);
vPilotAccelN = vPilotAccel / in.SLGravity;
// VRP computation
const FGLocation& vLocation = FDMExec->GetPropagate()->GetLocation();
const FGColumnVector3& vrpStructural = FDMExec->GetAircraft()->GetXYZvrp();
const FGColumnVector3 vrpBody = FDMExec->GetMassBalance()->StructuralToBody( vrpStructural );
const FGColumnVector3 vrpLocal = Tb2l * vrpBody;
vLocationVRP = vLocation.LocalToLocation( vrpLocal );
vLocationVRP = in.vLocation.LocalToLocation( in.Tb2l * in.VRPBody );
// Recompute some derived values now that we know the dependent parameters values ...
hoverbcg = DistanceAGL / wingspan;
hoverbcg = in.DistanceAGL / in.Wingspan;
FGColumnVector3 vMac = Tb2l*FDMExec->GetMassBalance()->StructuralToBody(FDMExec->GetAircraft()->GetXYZrp());
hoverbmac = (DistanceAGL + vMac(3)) / wingspan;
// when all model are executed,
// please calculate the distance from the initial point
FGColumnVector3 vMac = in.Tb2l * in.RPBody;
hoverbmac = (in.DistanceAGL + vMac(3)) / in.Wingspan;
// When all models are executed calculate the distance from the initial point.
CalculateRelativePosition();
RunPostFunctions();
@ -300,6 +262,68 @@ bool FGAuxiliary::Run(bool Holding)
return false;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// From Stevens and Lewis, "Aircraft Control and Simulation", 3rd Ed., the
// transformation from body to wind axes is defined (where "a" is alpha and "B"
// is beta):
//
// cos(a)*cos(B) sin(B) sin(a)*cos(B)
// -cos(a)*sin(B) cos(B) -sin(a)*sin(B)
// -sin(a) 0 cos(a)
//
// The transform from wind to body axes is then,
//
// cos(a)*cos(B) -cos(a)*sin(B) -sin(a)
// sin(B) cos(B) 0
// sin(a)*cos(B) -sin(a)*sin(B) cos(a)
FGMatrix33& FGAuxiliary::GetTw2b(void)
{
double ca, cb, sa, sb;
ca = cos(alpha);
sa = sin(alpha);
cb = cos(beta);
sb = sin(beta);
mTw2b(1,1) = ca*cb;
mTw2b(1,2) = -ca*sb;
mTw2b(1,3) = -sa;
mTw2b(2,1) = sb;
mTw2b(2,2) = cb;
mTw2b(2,3) = 0.0;
mTw2b(3,1) = sa*cb;
mTw2b(3,2) = -sa*sb;
mTw2b(3,3) = ca;
return mTw2b;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGMatrix33& FGAuxiliary::GetTb2w(void)
{
double ca, cb, sa, sb;
ca = cos(alpha);
sa = sin(alpha);
cb = cos(beta);
sb = sin(beta);
mTb2w(1,1) = ca*cb;
mTb2w(1,2) = sb;
mTb2w(1,3) = sa*cb;
mTb2w(2,1) = -ca*sb;
mTb2w(2,2) = cb;
mTb2w(2,3) = -sa*sb;
mTb2w(3,1) = -sa;
mTb2w(3,2) = 0.0;
mTb2w(3,3) = ca;
return mTb2w;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// A positive headwind is blowing with you, a negative headwind is blowing against you.
@ -308,12 +332,7 @@ bool FGAuxiliary::Run(bool Holding)
double FGAuxiliary::GetHeadWind(void) const
{
double psiw,vw;
psiw = FDMExec->GetAtmosphere()->GetWindPsi();
vw = FDMExec->GetAtmosphere()->GetTotalWindNED().Magnitude();
return vw*cos(psiw - FDMExec->GetPropagate()->GetEuler(ePsi));
return in.Vwind * cos(in.WindPsi - in.Psi);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -324,23 +343,38 @@ double FGAuxiliary::GetHeadWind(void) const
double FGAuxiliary::GetCrossWind(void) const
{
double psiw,vw;
psiw = FDMExec->GetAtmosphere()->GetWindPsi();
vw = FDMExec->GetAtmosphere()->GetTotalWindNED().Magnitude();
return vw*sin(psiw - FDMExec->GetPropagate()->GetEuler(ePsi));
return in.Vwind * sin(in.WindPsi - in.Psi);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGAuxiliary::GethVRP(void) const
{
return vLocationVRP.GetRadius() - FDMExec->GetPropagate()->GetSeaLevelRadius();
return vLocationVRP.GetRadius() - in.ReferenceRadius;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGAuxiliary::GetNlf(void) const
{
if (in.Mass != 0)
return (-in.vFw(3))/(in.Mass*slugtolb);
else
return 0.;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGAuxiliary::CalculateRelativePosition(void) //ToDo: This belongs elsewhere - perhaps in FGPropagate or Exec
{
const double earth_radius_mt = in.ReferenceRadius*fttom;
lat_relative_position=(in.Latitude - FDMExec->GetIC()->GetLatitudeDegIC() *degtorad)*earth_radius_mt;
lon_relative_position=(in.Longitude - FDMExec->GetIC()->GetLongitudeDegIC()*degtorad)*earth_radius_mt;
relative_position = sqrt(lat_relative_position*lat_relative_position + lon_relative_position*lon_relative_position);
};
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGAuxiliary::bind(void)
{
typedef double (FGAuxiliary::*PMF)(int) const;
@ -352,6 +386,8 @@ void FGAuxiliary::bind(void)
PropertyManager->Tie("velocities/vc-kts", this, &FGAuxiliary::GetVcalibratedKTS);
PropertyManager->Tie("velocities/ve-fps", this, &FGAuxiliary::GetVequivalentFPS);
PropertyManager->Tie("velocities/ve-kts", this, &FGAuxiliary::GetVequivalentKTS);
PropertyManager->Tie("velocities/vtrue-fps", this, &FGAuxiliary::GetVtrueFPS);
PropertyManager->Tie("velocities/vtrue-kts", this, &FGAuxiliary::GetVtrueKTS);
PropertyManager->Tie("velocities/machU", this, &FGAuxiliary::GetMachU);
PropertyManager->Tie("velocities/p-aero-rad_sec", this, eX, (PMF)&FGAuxiliary::GetAeroPQR);
PropertyManager->Tie("velocities/q-aero-rad_sec", this, eY, (PMF)&FGAuxiliary::GetAeroPQR);
@ -362,8 +398,8 @@ void FGAuxiliary::bind(void)
PropertyManager->Tie("velocities/u-aero-fps", this, eU, (PMF)&FGAuxiliary::GetAeroUVW);
PropertyManager->Tie("velocities/v-aero-fps", this, eV, (PMF)&FGAuxiliary::GetAeroUVW);
PropertyManager->Tie("velocities/w-aero-fps", this, eW, (PMF)&FGAuxiliary::GetAeroUVW);
PropertyManager->Tie("velocities/vt-fps", this, &FGAuxiliary::GetVt, &FGAuxiliary::SetVt, true);
PropertyManager->Tie("velocities/mach", this, &FGAuxiliary::GetMach, &FGAuxiliary::SetMach, true);
PropertyManager->Tie("velocities/vt-fps", this, &FGAuxiliary::GetVt);
PropertyManager->Tie("velocities/mach", this, &FGAuxiliary::GetMach);
PropertyManager->Tie("velocities/vg-fps", this, &FGAuxiliary::GetVground);
PropertyManager->Tie("accelerations/a-pilot-x-ft_sec2", this, eX, (PMF)&FGAuxiliary::GetPilotAccel);
PropertyManager->Tie("accelerations/a-pilot-y-ft_sec2", this, eY, (PMF)&FGAuxiliary::GetPilotAccel);
@ -372,25 +408,26 @@ void FGAuxiliary::bind(void)
PropertyManager->Tie("accelerations/n-pilot-y-norm", this, eY, (PMF)&FGAuxiliary::GetNpilot);
PropertyManager->Tie("accelerations/n-pilot-z-norm", this, eZ, (PMF)&FGAuxiliary::GetNpilot);
PropertyManager->Tie("accelerations/Nz", this, &FGAuxiliary::GetNz);
PropertyManager->Tie("forces/load-factor", this, &FGAuxiliary::GetNlf);
/* PropertyManager->Tie("atmosphere/headwind-fps", this, &FGAuxiliary::GetHeadWind, true);
PropertyManager->Tie("atmosphere/crosswind-fps", this, &FGAuxiliary::GetCrossWind, true); */
PropertyManager->Tie("aero/alpha-rad", this, (PF)&FGAuxiliary::Getalpha, &FGAuxiliary::Setalpha, true);
PropertyManager->Tie("aero/beta-rad", this, (PF)&FGAuxiliary::Getbeta, &FGAuxiliary::Setbeta, true);
PropertyManager->Tie("aero/alpha-rad", this, (PF)&FGAuxiliary::Getalpha);
PropertyManager->Tie("aero/beta-rad", this, (PF)&FGAuxiliary::Getbeta);
PropertyManager->Tie("aero/mag-beta-rad", this, (PF)&FGAuxiliary::GetMagBeta);
PropertyManager->Tie("aero/alpha-deg", this, inDegrees, (PMF)&FGAuxiliary::Getalpha);
PropertyManager->Tie("aero/beta-deg", this, inDegrees, (PMF)&FGAuxiliary::Getbeta);
PropertyManager->Tie("aero/mag-beta-deg", this, inDegrees, (PMF)&FGAuxiliary::GetMagBeta);
PropertyManager->Tie("aero/Re", this, &FGAuxiliary::GetReynoldsNumber);
PropertyManager->Tie("aero/qbar-psf", this, &FGAuxiliary::Getqbar, &FGAuxiliary::Setqbar, true);
PropertyManager->Tie("aero/qbarUW-psf", this, &FGAuxiliary::GetqbarUW, &FGAuxiliary::SetqbarUW, true);
PropertyManager->Tie("aero/qbarUV-psf", this, &FGAuxiliary::GetqbarUV, &FGAuxiliary::SetqbarUV, true);
PropertyManager->Tie("aero/alphadot-rad_sec", this, (PF)&FGAuxiliary::Getadot, &FGAuxiliary::Setadot, true);
PropertyManager->Tie("aero/betadot-rad_sec", this, (PF)&FGAuxiliary::Getbdot, &FGAuxiliary::Setbdot, true);
PropertyManager->Tie("aero/qbar-psf", this, &FGAuxiliary::Getqbar);
PropertyManager->Tie("aero/qbarUW-psf", this, &FGAuxiliary::GetqbarUW);
PropertyManager->Tie("aero/qbarUV-psf", this, &FGAuxiliary::GetqbarUV);
PropertyManager->Tie("aero/alphadot-rad_sec", this, (PF)&FGAuxiliary::Getadot);
PropertyManager->Tie("aero/betadot-rad_sec", this, (PF)&FGAuxiliary::Getbdot);
PropertyManager->Tie("aero/alphadot-deg_sec", this, inDegrees, (PMF)&FGAuxiliary::Getadot);
PropertyManager->Tie("aero/betadot-deg_sec", this, inDegrees, (PMF)&FGAuxiliary::Getbdot);
PropertyManager->Tie("aero/h_b-cg-ft", this, &FGAuxiliary::GetHOverBCG);
PropertyManager->Tie("aero/h_b-mac-ft", this, &FGAuxiliary::GetHOverBMAC);
PropertyManager->Tie("flight-path/gamma-rad", this, &FGAuxiliary::GetGamma, &FGAuxiliary::SetGamma);
PropertyManager->Tie("flight-path/gamma-rad", this, &FGAuxiliary::GetGamma);
PropertyManager->Tie("flight-path/psi-gt-rad", this, &FGAuxiliary::GetGroundTrack);
PropertyManager->Tie("position/distance-from-start-lon-mt", this, &FGAuxiliary::GetLongitudeRelativePosition);
@ -403,16 +440,6 @@ void FGAuxiliary::bind(void)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGAuxiliary::CalculateRelativePosition(void)
{
const double earth_radius_mt = FDMExec->GetInertial()->GetRefRadius()*fttom;
lat_relative_position=(FDMExec->GetPropagate()->GetLatitude() - FDMExec->GetIC()->GetLatitudeDegIC() *degtorad)*earth_radius_mt;
lon_relative_position=(FDMExec->GetPropagate()->GetLongitude() - FDMExec->GetIC()->GetLongitudeDegIC()*degtorad)*earth_radius_mt;
relative_position = sqrt(lat_relative_position*lat_relative_position + lon_relative_position*lon_relative_position);
};
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGAuxiliary::BadUnits(void) const
{
cerr << "Bad units" << endl; return 0.0;

View file

@ -41,13 +41,14 @@ INCLUDES
#include "FGModel.h"
#include "math/FGColumnVector3.h"
#include "math/FGMatrix33.h"
#include "math/FGLocation.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_AUXILIARY "$Id: FGAuxiliary.h,v 1.20 2011/05/20 03:18:36 jberndt Exp $"
#define ID_AUXILIARY "$Id: FGAuxiliary.h,v 1.23 2011/08/17 23:56:01 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -96,10 +97,9 @@ CLASS DOCUMENTATION
by the F = ma relation. If the vForces vector is divided by the aircraft
mass, the acceleration vector is calculated. The term wdot is equivalent
to the JSBSim vPQRdot vector, and the w parameter is equivalent to vPQR.
The radius R is calculated below in the vector vToEyePt.
@author Tony Peden, Jon Berndt
@version $Id: FGAuxiliary.h,v 1.20 2011/05/20 03:18:36 jberndt Exp $
@version $Id: FGAuxiliary.h,v 1.23 2011/08/17 23:56:01 jberndt Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -137,6 +137,10 @@ public:
double GetVequivalentFPS(void) const { return veas; }
/** Returns equivalent airspeed in knots. */
double GetVequivalentKTS(void) const { return veas*fpstokts; }
/** Returns the true airspeed in feet per second. */
double GetVtrueFPS() const { return vtrue; }
/** Returns the true airspeed in knots. */
double GetVtrueKTS() const { return vtrue * fpstokts; }
/** Returns the total pressure.
Total pressure is freestream total pressure for
@ -147,9 +151,9 @@ public:
/** Returns the total temperature.
The total temperature ("tat", isentropic flow) is calculated:
@code
tat = sat*(1 + 0.2*Mach*Mach)
tat = in.Temperature*(1 + 0.2*Mach*Mach)
@endcode
(where "sat" is standard temperature) */
(where "in.Temperature" is standard temperature calculated by the atmosphere model) */
double GetTotalTemperature(void) const { return tat; }
double GetTAT_C(void) const { return tatc; }
@ -161,6 +165,9 @@ public:
const FGColumnVector3& GetPilotAccel (void) const { return vPilotAccel; }
const FGColumnVector3& GetNpilot (void) const { return vPilotAccelN; }
const FGColumnVector3& GetNcg (void) const { return vNcg; }
double GetNcg (int idx) const { return vNcg(idx); }
double GetNlf (void) const;
const FGColumnVector3& GetAeroPQR (void) const { return vAeroPQR; }
const FGColumnVector3& GetEulerRates (void) const { return vEulerRates; }
const FGColumnVector3& GetAeroUVW (void) const { return vAeroUVW; }
@ -185,6 +192,16 @@ public:
double GetMagBeta (int unit) const { if (unit == inDegrees) return fabs(beta)*radtodeg;
else return BadUnits(); }
/** Calculates and returns the wind-to-body axis transformation matrix.
@return a reference to the wind-to-body transformation matrix.
*/
FGMatrix33& GetTw2b(void);
/** Calculates and returns the body-to-wind axis transformation matrix.
@return a reference to the wind-to-body transformation matrix.
*/
FGMatrix33& GetTb2w(void);
double Getqbar (void) const { return qbar; }
double GetqbarUW (void) const { return qbarUW; }
double GetqbarUV (void) const { return qbarUV; }
@ -208,6 +225,8 @@ public:
/** The vertical acceleration in g's of the aircraft center of gravity. */
double GetNz (void) const { return Nz; }
FGColumnVector3& GetNwcg(void) { return vNwcg; }
double GetHOverBCG(void) const { return hoverbcg; }
double GetHOverBMAC(void) const { return hoverbmac; }
@ -217,23 +236,6 @@ public:
double GetHeadWind(void) const;
double GetCrossWind(void) const;
// SET functions
void SetAeroUVW(FGColumnVector3 tt) { vAeroUVW = tt; }
void Setalpha (double tt) { alpha = tt; }
void Setbeta (double tt) { beta = tt; }
void Setqbar (double tt) { qbar = tt; }
void SetqbarUW (double tt) { qbarUW = tt; }
void SetqbarUV (double tt) { qbarUV = tt; }
void SetVt (double tt) { Vt = tt; }
void SetMach (double tt) { Mach=tt; }
void Setadot (double tt) { adot = tt; }
void Setbdot (double tt) { bdot = tt; }
void SetAB (double t1, double t2) { alpha=t1; beta=t2; }
void SetGamma (double tt) { gamma = tt; }
// Time routines, SET and GET functions, used by FGMSIS atmosphere
void SetDayOfYear (int doy) { day_of_year = doy; }
@ -248,19 +250,65 @@ public:
void SetAeroPQR(FGColumnVector3 tt) { vAeroPQR = tt; }
struct Inputs {
double Pressure;
double Density;
double DensitySL;
double PressureSL;
double Temperature;
double SoundSpeed;
double KinematicViscosity;
double DistanceAGL;
double Wingspan;
double Wingchord;
double SLGravity;
double Mass;
FGMatrix33 Tl2b;
FGMatrix33 Tb2l;
FGMatrix33 Tb2w;
FGColumnVector3 vPQR;
FGColumnVector3 vPQRdot;
FGColumnVector3 vUVW;
FGColumnVector3 vUVWdot;
FGColumnVector3 vVel;
FGColumnVector3 vBodyAccel;
FGColumnVector3 ToEyePt;
FGColumnVector3 RPBody;
FGColumnVector3 VRPBody;
FGColumnVector3 vFw;
FGLocation vLocation;
double Latitude;
double Longitude;
double InitialLatitude;
double InitialLongitude;
double ReferenceRadius;
double CosTht;
double SinTht;
double CosPhi;
double SinPhi;
double Psi;
FGColumnVector3 TotalWindNED;
FGColumnVector3 TurbPQR;
double WindPsi;
double Vwind;
} in;
private:
double vcas, veas;
double rhosl, rho, p, psl, pt, tat, sat, tatc; // Don't add a getter for pt!
double vcas, veas, vtrue;
double pt, tat, tatc; // Don't add a getter for pt!
FGMatrix33 mTw2b;
FGMatrix33 mTb2w;
FGColumnVector3 vPilotAccel;
FGColumnVector3 vPilotAccelN;
FGColumnVector3 vToEyePt;
FGColumnVector3 vNcg;
FGColumnVector3 vNwcg;
FGColumnVector3 vAeroPQR;
FGColumnVector3 vAeroUVW;
FGColumnVector3 vEuler;
FGColumnVector3 vEulerRates;
FGColumnVector3 vMachUVW;
FGColumnVector3 vAircraftAccel;
FGLocation vLocationVRP;
double Vt, Vground, Mach, MachU;

View file

@ -45,7 +45,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGBuoyantForces.cpp,v 1.19 2011/07/01 21:22:25 andgi Exp $";
static const char *IdSrc = "$Id: FGBuoyantForces.cpp,v 1.20 2011/08/06 13:47:59 jberndt Exp $";
static const char *IdHdr = ID_BUOYANTFORCES;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -131,7 +131,7 @@ bool FGBuoyantForces::Load(Element *element)
gas_cell_element = document->FindElement("gas_cell");
while (gas_cell_element) {
NoneDefined = false;
Cells.push_back(new FGGasCell(FDMExec, gas_cell_element, Cells.size()));
Cells.push_back(new FGGasCell(FDMExec, gas_cell_element, Cells.size(), in));
gas_cell_element = document->FindNextElement("gas_cell");
}

View file

@ -32,8 +32,8 @@ HISTORY
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifndef FGBuoyanTFORCES_H
#define FGBuoyanTFORCES_H
#ifndef FGBUOYANTFORCES_H
#define FGBUOYANTFORCES_H
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
@ -51,7 +51,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_BUOYANTFORCES "$Id: FGBuoyantForces.h,v 1.13 2011/07/01 21:22:25 andgi Exp $"
#define ID_BUOYANTFORCES "$Id: FGBuoyantForces.h,v 1.15 2011/08/14 20:15:56 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -96,7 +96,7 @@ CLASS DOCUMENTATION
See FGGasCell for the full configuration file format for gas cells.
@author Anders Gidenstam, Jon S. Berndt
@version $Id: FGBuoyantForces.h,v 1.13 2011/07/01 21:22:25 andgi Exp $
@version $Id: FGBuoyantForces.h,v 1.15 2011/08/14 20:15:56 jberndt Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -172,6 +172,8 @@ public:
parameters */
string GetBuoyancyValues(string delimeter);
FGGasCell::Inputs in;
private:
vector <FGGasCell*> Cells;
// Buoyant forces and moments. Excluding the gas weight.

27
src/FDM/JSBSim/models/FGExternalReactions.cpp Executable file → Normal file
View file

@ -53,7 +53,7 @@ DEFINITIONS
GLOBAL DATA
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
static const char *IdSrc = "$Id: FGExternalReactions.cpp,v 1.10 2011/05/20 03:18:36 jberndt Exp $";
static const char *IdSrc = "$Id: FGExternalReactions.cpp,v 1.12 2011/07/20 12:16:34 jberndt Exp $";
static const char *IdHdr = ID_EXTERNALREACTIONS;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -63,6 +63,7 @@ CLASS IMPLEMENTATION
FGExternalReactions::FGExternalReactions(FGFDMExec* fdmex) : FGModel(fdmex)
{
NoneDefined = true;
Debug(0);
}
@ -70,6 +71,14 @@ FGExternalReactions::FGExternalReactions(FGFDMExec* fdmex) : FGModel(fdmex)
bool FGExternalReactions::Load(Element* el)
{
// check if a file attribute was specified
string fname = el->GetAttributeValue("file");
if (!fname.empty()) {
string file = FDMExec->GetFullAircraftPath() + "/" + fname;
el = LoadXMLDocument(file);
if (el == 0L) return false;
}
FGModel::Load(el); // Call the base class Load() function to load interface properties.
Debug(2);
@ -87,6 +96,8 @@ bool FGExternalReactions::Load(Element* el)
PostLoad(el, PropertyManager);
if (!NoneDefined) bind();
return true;
}
@ -130,6 +141,20 @@ bool FGExternalReactions::Run(bool Holding)
return false;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGExternalReactions::bind(void)
{
typedef double (FGExternalReactions::*PMF)(int) const;
PropertyManager->Tie("moments/l-external-lbsft", this, eL, (PMF)&FGExternalReactions::GetMoments);
PropertyManager->Tie("moments/m-external-lbsft", this, eM, (PMF)&FGExternalReactions::GetMoments);
PropertyManager->Tie("moments/n-external-lbsft", this, eN, (PMF)&FGExternalReactions::GetMoments);
PropertyManager->Tie("forces/fbx-external-lbs", this, eX, (PMF)&FGExternalReactions::GetForces);
PropertyManager->Tie("forces/fby-external-lbs", this, eY, (PMF)&FGExternalReactions::GetForces);
PropertyManager->Tie("forces/fbz-external-lbs", this, eZ, (PMF)&FGExternalReactions::GetForces);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print

9
src/FDM/JSBSim/models/FGExternalReactions.h Executable file → Normal file
View file

@ -41,12 +41,14 @@ INCLUDES
#include <vector>
#include "FGModel.h"
#include "FGExternalForce.h"
#include "input_output/FGXMLFileRead.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_EXTERNALREACTIONS "$Id: FGExternalReactions.h,v 1.11 2011/05/20 03:18:36 jberndt Exp $"
#define ID_EXTERNALREACTIONS "$Id: FGExternalReactions.h,v 1.13 2011/07/20 12:16:34 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -115,7 +117,7 @@ CLASS DOCUMENTATION
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGExternalReactions : public FGModel
class FGExternalReactions : public FGModel, public FGXMLFileRead
{
public:
/** Constructor.
@ -152,11 +154,13 @@ public:
@return the total force in pounds.
*/
FGColumnVector3 GetForces(void) const {return vTotalForces;}
double GetForces(int idx) const {return vTotalForces(idx);}
/** Retrieves the total moment resulting from the forces defined in the external reactions.
@return the total moment in foot-pounds.
*/
FGColumnVector3 GetMoments(void) const {return vTotalMoments;}
double GetMoments(int idx) const {return vTotalMoments(idx);}
private:
@ -167,6 +171,7 @@ private:
bool NoneDefined;
void bind(void);
void Debug(int from);
};
}

View file

@ -37,13 +37,14 @@ HISTORY
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <fstream>
#include <sstream>
#include <iomanip>
#include "FGFCS.h"
#include "FGFDMExec.h"
#include "FGGroundReactions.h"
#include "input_output/FGPropertyManager.h"
#include <fstream>
#include <sstream>
#include <iomanip>
#include "models/flight_control/FGFilter.h"
#include "models/flight_control/FGDeadBand.h"
@ -63,7 +64,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGFCS.cpp,v 1.74 2011/05/20 03:18:36 jberndt Exp $";
static const char *IdSrc = "$Id: FGFCS.cpp,v 1.77 2011/09/25 14:05:40 bcoconni Exp $";
static const char *IdHdr = ID_FCS;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -78,7 +79,7 @@ FGFCS::FGFCS(FGFDMExec* fdmex) : FGModel(fdmex)
DaCmd = DeCmd = DrCmd = DsCmd = DfCmd = DsbCmd = DspCmd = 0;
PTrimCmd = YTrimCmd = RTrimCmd = 0.0;
GearCmd = GearPos = 1; // default to gear down
LeftBrake = RightBrake = CenterBrake = 0.0;
BrakePos.resize(FGLGear::bgNumBrakeGroups);
TailhookPos = WingFoldPos = 0.0;
bind();
@ -664,6 +665,8 @@ bool FGFCS::Load(Element* el, SystemType systype)
channel_element = document->FindNextElement("channel");
}
PostLoad(document, PropertyManager);
ResetParser();
return true;
@ -673,17 +676,7 @@ bool FGFCS::Load(Element* el, SystemType systype)
double FGFCS::GetBrake(FGLGear::BrakeGroup bg)
{
switch (bg) {
case FGLGear::bgLeft:
return LeftBrake;
case FGLGear::bgRight:
return RightBrake;
case FGLGear::bgCenter:
return CenterBrake;
default:
cerr << "GetBrake asked to return a bogus brake value" << endl;
}
return 0.0;
return BrakePos[bg];
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -838,9 +831,10 @@ void FGFCS::AddThrottle(void)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGFCS::AddGear(void)
void FGFCS::AddGear(unsigned int NumGear)
{
SteerPosDeg.push_back(0.0);
SteerPosDeg.clear();
for (unsigned int i=0; i<NumGear; i++) SteerPosDeg.push_back(0.0);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -51,7 +51,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_FCS "$Id: FGFCS.h,v 1.36 2011/05/20 03:18:36 jberndt Exp $"
#define ID_FCS "$Id: FGFCS.h,v 1.39 2011/08/14 20:15:56 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -168,7 +168,7 @@ CLASS DOCUMENTATION
@property gear/tailhook-pos-norm
@author Jon S. Berndt
@version $Revision: 1.36 $
@version $Revision: 1.39 $
@see FGActuator
@see FGDeadBand
@see FGFCSFunction
@ -243,11 +243,15 @@ public:
@return throttle command in range from 0 - 1.0 for the given engine */
double GetThrottleCmd(int engine) const;
vector <double> GetThrottleCmd() const {return ThrottleCmd;}
/** Gets the mixture command.
@param engine engine ID number
@return mixture command in range from 0 - 1.0 for the given engine */
double GetMixtureCmd(int engine) const { return MixtureCmd[engine]; }
vector <double> GetMixtureCmd() const {return MixtureCmd;}
/** Gets the prop pitch command.
@param engine engine ID number
@return pitch command in range from 0.0 - 1.0 for the given engine */
@ -318,15 +322,21 @@ public:
@return throttle position for the given engine in range from 0 - 1.0 */
double GetThrottlePos(int engine) const;
vector <double> GetThrottlePos() const {return ThrottlePos;}
/** Gets the mixture position.
@param engine engine ID number
@return mixture position for the given engine in range from 0 - 1.0 */
double GetMixturePos(int engine) const { return MixturePos[engine]; }
vector <double> GetMixturePos() const {return MixturePos;}
/** Gets the steering position.
@return steering position in degrees */
double GetSteerPosDeg(int gear) const { return SteerPosDeg[gear]; }
vector <double> GetSteerPosDeg() const {return SteerPosDeg;}
/** Gets the gear position (0 up, 1 down), defaults to down
@return gear position (0 up, 1 down) */
double GetGearPos(void) const { return GearPos; }
@ -344,10 +354,14 @@ public:
@return prop pitch position for the given engine in range from 0 - 1.0 */
double GetPropAdvance(int engine) const { return PropAdvance[engine]; }
vector <double> GetPropAdvance() const { return PropAdvance; }
/** Gets the prop feather position.
@param engine engine ID number
@return prop fether for the given engine (on / off)*/
bool GetPropFeather(int engine) const { return PropFeather[engine]; }
vector <bool> GetPropFeather() const { return PropFeather; }
//@}
/** Retrieves all component names for inclusion in output stream
@ -499,32 +513,34 @@ public:
//@{
/** Sets the left brake group
@param cmd brake setting in percent (0.0 - 1.0) */
void SetLBrake(double cmd) {LeftBrake = cmd;}
void SetLBrake(double cmd) {BrakePos[FGLGear::bgLeft] = cmd;}
/** Sets the right brake group
@param cmd brake setting in percent (0.0 - 1.0) */
void SetRBrake(double cmd) {RightBrake = cmd;}
void SetRBrake(double cmd) {BrakePos[FGLGear::bgRight] = cmd;}
/** Sets the center brake group
@param cmd brake setting in percent (0.0 - 1.0) */
void SetCBrake(double cmd) {CenterBrake = cmd;}
void SetCBrake(double cmd) {BrakePos[FGLGear::bgCenter] = cmd;}
/** Gets the brake for a specified group.
@param bg which brakegroup to retrieve the command for
@return the brake setting for the supplied brake group argument */
double GetBrake(FGLGear::BrakeGroup bg);
vector <double> GetBrakePos() const {return BrakePos;}
/** Gets the left brake.
@return the left brake setting. */
double GetLBrake(void) const {return LeftBrake;}
double GetLBrake(void) const {return BrakePos[FGLGear::bgLeft];}
/** Gets the right brake.
@return the right brake setting. */
double GetRBrake(void) const {return RightBrake;}
double GetRBrake(void) const {return BrakePos[FGLGear::bgRight];}
/** Gets the center brake.
@return the center brake setting. */
double GetCBrake(void) const {return CenterBrake;}
double GetCBrake(void) const {return BrakePos[FGLGear::bgCenter];}
//@}
enum SystemType { stFCS, stSystem, stAutoPilot };
@ -540,13 +556,17 @@ public:
std::string FindSystemFullPathname(const std::string& system_filename);
void AddThrottle(void);
void AddGear(void);
void AddGear(unsigned int NumGear);
double GetDt(void);
FGPropertyManager* GetPropertyManager(void) { return PropertyManager; }
bool GetTrimStatus(void) const { return FDMExec->GetTrimStatus(); }
struct Inputs {
unsigned int NumGear;
} in;
private:
double DaCmd, DeCmd, DrCmd, DsCmd, DfCmd, DsbCmd, DspCmd;
double DePos[NForms], DaLPos[NForms], DaRPos[NForms], DrPos[NForms];
@ -562,6 +582,7 @@ private:
std::vector <bool> PropFeather;
std::vector <double> SteerPosDeg;
double LeftBrake, RightBrake, CenterBrake; // Brake settings
vector <double> BrakePos; // left, center, right - defined by FGLGear:: enum
double GearCmd,GearPos;
double TailhookPos, WingFoldPos;

View file

@ -36,9 +36,6 @@ INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFDMExec.h"
#include "models/FGAuxiliary.h"
#include "models/FGAtmosphere.h"
#include "models/FGInertial.h"
#include "models/FGMassBalance.h"
#include "FGGasCell.h"
#include "input_output/FGXMLElement.h"
@ -53,7 +50,7 @@ using std::max;
namespace JSBSim {
static const char *IdSrc = "$Id: FGGasCell.cpp,v 1.14 2011/07/01 21:22:25 andgi Exp $";
static const char *IdSrc = "$Id: FGGasCell.cpp,v 1.15 2011/08/06 13:47:59 jberndt Exp $";
static const char *IdHdr = ID_GASCELL;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -65,15 +62,13 @@ const double FGGasCell::M_air = 0.0019186; // [slug/mol]
const double FGGasCell::M_hydrogen = 0.00013841; // [slug/mol]
const double FGGasCell::M_helium = 0.00027409; // [slug/mol]
FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, int num) : FGForce(exec)
FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, int num, const struct Inputs& input)
: FGForce(exec), in(input)
{
string token;
Element* element;
Auxiliary = exec->GetAuxiliary();
Atmosphere = exec->GetAtmosphere();
PropertyManager = exec->GetPropertyManager();
Inertial = exec->GetInertial();
MassBalance = exec->GetMassBalance();
gasCellJ = FGMatrix33();
@ -175,10 +170,10 @@ FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, int num) : FGForce(exec)
SetLocation(vXYZ);
if (Temperature == 0.0) {
Temperature = Atmosphere->GetTemperature();
Temperature = in.Temperature;
}
if (Pressure == 0.0) {
Pressure = Atmosphere->GetPressure();
Pressure = in.Pressure;
}
if (Volume != 0.0) {
// Calculate initial gas content.
@ -239,7 +234,7 @@ FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, int num) : FGForce(exec)
Ballonet.push_back(new FGBallonet(exec,
ballonet_element,
Ballonet.size(),
this));
this, in));
ballonet_element = el->FindNextElement("ballonet");
}
}
@ -265,10 +260,10 @@ FGGasCell::~FGGasCell()
void FGGasCell::Calculate(double dt)
{
const double AirTemperature = Atmosphere->GetTemperature(); // [Rankine]
const double AirPressure = Atmosphere->GetPressure(); // [lbs/ft²]
const double AirDensity = Atmosphere->GetDensity(); // [slug/ft³]
const double g = Inertial->gravity(); // [lbs/slug]
const double AirTemperature = in.Temperature; // [Rankine]
const double AirPressure = in.Pressure; // [lbs/ft²]
const double AirDensity = in.Density; // [slug/ft³]
const double g = in.gravity; // [lbs/slug]
const double OldTemperature = Temperature;
const double OldPressure = Pressure;
@ -509,15 +504,13 @@ const double FGBallonet::R = 3.4071; // [lbs ft/(mol Rankine)]
const double FGBallonet::M_air = 0.0019186; // [slug/mol]
const double FGBallonet::Cv_air = 5.0/2.0; // [??]
FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, int num, FGGasCell* parent)
FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, int num, FGGasCell* parent, const struct FGGasCell::Inputs& input)
: in(input)
{
string token;
Element* element;
Auxiliary = exec->GetAuxiliary();
Atmosphere = exec->GetAtmosphere();
PropertyManager = exec->GetPropertyManager();
Inertial = exec->GetInertial();
MassBalance = exec->GetMassBalance();
ballonetJ = FGMatrix33();
@ -696,8 +689,8 @@ FGBallonet::~FGBallonet()
void FGBallonet::Calculate(double dt)
{
const double ParentPressure = Parent->GetPressure(); // [lbs/ft²]
const double AirPressure = Atmosphere->GetPressure(); // [lbs/ft²]
const double ParentPressure = Parent->GetPressure(); // [lbs/ft²]
const double AirPressure = Pressure; // [lbs/ft²]
const double OldTemperature = Temperature;
const double OldPressure = Pressure;

View file

@ -32,8 +32,8 @@ This class simulates a generic gas cell for static buoyancy.
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifndef FGGasCell_H
#define FGGasCell_H
#ifndef FGGASCELL_H
#define FGGASCELL_H
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
@ -50,7 +50,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_GASCELL "$Id: FGGasCell.h,v 1.11 2011/07/01 21:22:25 andgi Exp $"
#define ID_GASCELL "$Id: FGGasCell.h,v 1.12 2011/08/06 13:47:59 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -172,11 +172,18 @@ CLASS DECLARATION
class FGGasCell : public FGForce
{
public:
struct Inputs {
double Pressure;
double Temperature;
double Density;
double gravity;
};
/** Constructor
@param exec Executive a pointer to the parent executive object
@param el Pointer to configuration file XML node
@param num Gas cell index number. */
FGGasCell(FGFDMExec* exec, Element* el, int num);
FGGasCell(FGFDMExec* exec, Element* el, int num, const struct Inputs& input);
~FGGasCell();
/** Runs the gas cell model; called by BuoyantForces
@ -221,6 +228,8 @@ public:
@return gas pressure in lbs / ft<sup>2</sup>. */
double GetPressure(void) const {return Pressure;}
const struct Inputs& in;
private:
enum GasType {ttUNKNOWN, ttHYDROGEN, ttHELIUM, ttAIR};
@ -252,10 +261,7 @@ private:
FGMatrix33 gasCellJ; // [slug foot^2]
FGColumnVector3 gasCellM; // [lbs in]
FGAuxiliary* Auxiliary;
FGAtmosphere* Atmosphere;
FGPropertyManager* PropertyManager;
FGInertial* Inertial;
FGMassBalance* MassBalance;
void Debug(int from);
@ -302,7 +308,7 @@ private:
class FGBallonet : public FGJSBBase
{
public:
FGBallonet(FGFDMExec* exec, Element* el, int num, FGGasCell* parent);
FGBallonet(FGFDMExec* exec, Element* el, int num, FGGasCell* parent, const struct FGGasCell::Inputs& input);
~FGBallonet();
/** Runs the ballonet model; called by FGGasCell
@ -333,6 +339,8 @@ public:
@return heat flow in lbs ft / sec. */
double GetHeatFlow(void) const {return dU;} // [lbs ft / sec]
const struct FGGasCell::Inputs& in;
private:
int CellNum;
// Structural constants
@ -356,10 +364,7 @@ private:
double ValveOpen; // 0 <= ValveOpen <= 1 (or higher).
FGMatrix33 ballonetJ; // [slug foot^2]
FGAuxiliary* Auxiliary;
FGAtmosphere* Atmosphere;
FGPropertyManager* PropertyManager;
FGInertial* Inertial;
FGMassBalance* MassBalance;
void Debug(int from);

View file

@ -39,56 +39,16 @@ INCLUDES
#include <iomanip>
#include "FGGroundReactions.h"
#include "FGFCS.h"
#include "FGLGear.h"
#include "input_output/FGPropertyManager.h"
using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGGroundReactions.cpp,v 1.32 2011/05/20 03:18:36 jberndt Exp $";
static const char *IdSrc = "$Id: FGGroundReactions.cpp,v 1.36 2011/08/21 15:13:22 bcoconni Exp $";
static const char *IdHdr = ID_GROUNDREACTIONS;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION for MultiplierIterator (See below for FGGroundReactions)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
MultiplierIterator::MultiplierIterator(FGGroundReactions* GndReactions)
: GroundReactions(GndReactions),
multiplier(NULL),
gearNum(0),
entry(0)
{
for (int i=0; i < GroundReactions->GetNumGearUnits(); i++) {
FGLGear* gear = GroundReactions->GetGearUnit(i);
if (!gear->GetWOW()) continue;
gearNum = i;
multiplier = gear->GetMultiplierEntry(0);
break;
}
}
MultiplierIterator& MultiplierIterator::operator++()
{
for (int i=gearNum; i < GroundReactions->GetNumGearUnits(); i++) {
FGLGear* gear = GroundReactions->GetGearUnit(i);
if (!gear->GetWOW()) continue;
multiplier = gear->GetMultiplierEntry(++entry);
if (multiplier) {
gearNum = i;
break;
}
else
entry = -1;
}
return *this;
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
@ -131,6 +91,8 @@ bool FGGroundReactions::Run(bool Holding)
vForces.InitMatrix();
vMoments.InitMatrix();
multipliers.clear();
// Sum forces and moments for all gear, here.
// Some optimizations may be made here - or rather in the gear code itself.
// The gear ::Run() method is called several times - once for each gear.
@ -160,20 +122,6 @@ bool FGGroundReactions::GetWOW(void) const
return result;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// This function must be called after friction forces are resolved in order to
// include them in the ground reactions total force and moment.
void FGGroundReactions::UpdateForcesAndMoments(void)
{
vForces.InitMatrix();
vMoments.InitMatrix();
for (unsigned int i=0; i<lGear.size(); i++) {
vForces += lGear[i]->UpdateForces();
vMoments += lGear[i]->GetMoments();
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGGroundReactions::Load(Element* el)
@ -182,15 +130,18 @@ bool FGGroundReactions::Load(Element* el)
Debug(2);
unsigned int numContacts = el->GetNumElements("contact");
lGear.resize(numContacts);
Element* contact_element = el->FindElement("contact");
while (contact_element) {
lGear.push_back(new FGLGear(contact_element, FDMExec, num++));
FDMExec->GetFCS()->AddGear(); // make the FCS aware of the landing gear
for (unsigned int idx=0; idx<numContacts; idx++) {
lGear[idx] = new FGLGear(contact_element, FDMExec, num++, in);
contact_element = el->FindNextElement("contact");
}
FGModel::Load(el); // Perform base class Load
in.vWhlBodyVec.resize(lGear.size());
for (unsigned int i=0; i<lGear.size();i++) lGear[i]->bind();
PostLoad(el, PropertyManager);
@ -275,12 +226,6 @@ void FGGroundReactions::bind(void)
typedef double (FGGroundReactions::*PMF)(int) const;
PropertyManager->Tie("gear/num-units", this, &FGGroundReactions::GetNumGearUnits);
PropertyManager->Tie("gear/wow", this, &FGGroundReactions::GetWOW);
PropertyManager->Tie("moments/l-gear-lbsft", this, eL, (PMF)&FGGroundReactions::GetMoments);
PropertyManager->Tie("moments/m-gear-lbsft", this, eM, (PMF)&FGGroundReactions::GetMoments);
PropertyManager->Tie("moments/n-gear-lbsft", this, eN, (PMF)&FGGroundReactions::GetMoments);
PropertyManager->Tie("forces/fbx-gear-lbs", this, eX, (PMF)&FGGroundReactions::GetForces);
PropertyManager->Tie("forces/fby-gear-lbs", this, eY, (PMF)&FGGroundReactions::GetForces);
PropertyManager->Tie("forces/fbz-gear-lbs", this, eZ, (PMF)&FGGroundReactions::GetForces);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -45,7 +45,7 @@ INCLUDES
#include "math/FGColumnVector3.h"
#include "input_output/FGXMLElement.h"
#define ID_GROUNDREACTIONS "$Id: FGGroundReactions.h,v 1.20 2011/05/20 03:18:36 jberndt Exp $"
#define ID_GROUNDREACTIONS "$Id: FGGroundReactions.h,v 1.24 2011/08/21 15:13:22 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -78,19 +78,6 @@ CLASS DOCUMENTATION
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class MultiplierIterator
{
public:
MultiplierIterator(FGGroundReactions* GndReactions);
MultiplierIterator& operator++();
FGPropagate::LagrangeMultiplier* operator*() { return multiplier; }
private:
FGGroundReactions* GroundReactions;
FGPropagate::LagrangeMultiplier* multiplier;
int gearNum;
int entry;
};
class FGGroundReactions : public FGModel
{
public:
@ -114,7 +101,6 @@ public:
string GetGroundReactionStrings(string delimeter) const;
string GetGroundReactionValues(string delimeter) const;
bool GetWOW(void) const;
void UpdateForcesAndMoments(void);
int GetNumGearUnits(void) const { return (int)lGear.size(); }
@ -123,10 +109,16 @@ public:
@return a pointer to the FGLGear instance of the gear unit requested */
FGLGear* GetGearUnit(int gear) const { return lGear[gear]; }
void RegisterLagrangeMultiplier(LagrangeMultiplier* lmult) { multipliers.push_back(lmult); }
vector <LagrangeMultiplier*>* GetMultipliersList(void) { return &multipliers; }
FGLGear::Inputs in;
private:
vector <FGLGear*> lGear;
FGColumnVector3 vForces;
FGColumnVector3 vMoments;
vector <LagrangeMultiplier*> multipliers;
void bind(void);
void Debug(int from);

View file

@ -37,15 +37,13 @@ INCLUDES
#include "FGInertial.h"
#include "FGFDMExec.h"
#include "FGPropagate.h"
#include "FGMassBalance.h"
#include <iostream>
using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGInertial.cpp,v 1.21 2011/05/20 03:18:36 jberndt Exp $";
static const char *IdSrc = "$Id: FGInertial.cpp,v 1.24 2011/08/04 12:46:32 jberndt Exp $";
static const char *IdHdr = ID_INERTIAL;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -65,7 +63,6 @@ FGInertial::FGInertial(FGFDMExec* fgex) : FGModel(fgex)
J2 = 1.0826266836E-03; // WGS84 value for J2
a = 20925646.3255; // WGS84 semimajor axis length in feet
b = 20855486.5951; // WGS84 semiminor axis length in feet
earthPosAngle = 0.0;
// Lunar defaults
/*
@ -76,9 +73,9 @@ FGInertial::FGInertial(FGFDMExec* fgex) : FGModel(fgex)
J2 = 2.033542482111609E-4; // value for J2
a = 5702559.05; // semimajor axis length in feet
b = 5695439.63; // semiminor axis length in feet
earthPosAngle = 0.0;
*/
vOmegaPlanet = FGColumnVector3( 0.0, 0.0, RotationRate );
gAccelReference = GM/(RadiusReference*RadiusReference);
gAccel = GM/(RadiusReference*RadiusReference);
@ -98,8 +95,6 @@ FGInertial::~FGInertial(void)
bool FGInertial::InitModel(void)
{
earthPosAngle = 0.0;
return true;
}
@ -114,9 +109,7 @@ bool FGInertial::Run(bool Holding)
RunPreFunctions();
// Gravitation accel
double r = FDMExec->GetPropagate()->GetRadius();
gAccel = GetGAccel(r);
earthPosAngle += FDMExec->GetDeltaT()*RotationRate;
gAccel = GetGAccel(in.Radius);
RunPostFunctions();
@ -143,8 +136,7 @@ FGColumnVector3 FGInertial::GetGravityJ2(FGColumnVector3 position) const
// Gravitation accel
double r = position.Magnitude();
double lat = FDMExec->GetPropagate()->GetLatitude();
double sinLat = sin(lat);
double sinLat = sin(in.Latitude);
double adivr = a/r;
double preCommon = 1.5*J2*adivr*adivr;
@ -163,7 +155,7 @@ FGColumnVector3 FGInertial::GetGravityJ2(FGColumnVector3 position) const
void FGInertial::bind(void)
{
PropertyManager->Tie("position/epa-rad", this, &FGInertial::GetEarthPositionAngle);
PropertyManager->Tie("inertial/sea-level-radius_ft", this, &FGInertial::GetRefRadius);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -47,7 +47,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_INERTIAL "$Id: FGInertial.h,v 1.16 2011/05/20 03:18:36 jberndt Exp $"
#define ID_INERTIAL "$Id: FGInertial.h,v 1.19 2011/08/04 12:46:32 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -86,17 +86,20 @@ public:
double SLgravity(void) const {return gAccelReference;}
double gravity(void) const {return gAccel;}
double omega(void) const {return RotationRate;}
double GetEarthPositionAngle(void) const { return earthPosAngle; }
double GetEarthPositionAngleDeg(void) const { return earthPosAngle*radtodeg;}
FGColumnVector3 GetOmegaPlanet() const {return vOmegaPlanet;}
double GetGAccel(double r) const;
FGColumnVector3 GetGravityJ2(FGColumnVector3 position) const;
double GetRefRadius(void) const {return RadiusReference;}
double GetSemimajor(void) const {return a;}
double GetSemiminor(void) const {return b;}
void SetEarthPositionAngle(double epa) {earthPosAngle = epa;}
struct Inputs {
double Radius;
double Latitude;
} in;
private:
FGColumnVector3 vOmegaPlanet;
double gAccel;
double gAccelReference;
double RadiusReference;

0
src/FDM/JSBSim/models/FGInput.cpp Executable file → Normal file
View file

0
src/FDM/JSBSim/models/FGInput.h Executable file → Normal file
View file

View file

@ -40,16 +40,14 @@ HISTORY
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGLGear.h"
#include "FGGroundReactions.h"
#include "FGFCS.h"
#include "FGAuxiliary.h"
#include "FGAtmosphere.h"
#include "FGMassBalance.h"
#include "math/FGTable.h"
#include <cstdlib>
#include <cstring>
#include "FGLGear.h"
#include "input_output/FGPropertyManager.h"
#include "models/FGGroundReactions.h"
#include "math/FGTable.h"
using namespace std;
namespace JSBSim {
@ -62,7 +60,7 @@ DEFINITIONS
GLOBAL DATA
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
static const char *IdSrc = "$Id: FGLGear.cpp,v 1.80 2011/01/24 13:01:56 jberndt Exp $";
static const char *IdSrc = "$Id: FGLGear.cpp,v 1.89 2011/09/11 11:36:04 bcoconni Exp $";
static const char *IdHdr = ID_LGEAR;
// Body To Structural (body frame is rotated 180 deg about Y and lengths are given in
@ -73,8 +71,9 @@ const FGMatrix33 FGLGear::Tb2s(-1./inchtoft, 0., 0., 0., 1./inchtoft, 0., 0., 0.
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) :
FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number, const struct Inputs& inputs) :
FGForce(fdmex),
in(inputs),
GearNumber(number),
SteerAngle(0.0),
Castered(false),
@ -102,6 +101,15 @@ FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) :
eContactType = ctSTRUCTURE;
}
// Default values for structural contact points
if (eContactType == ctSTRUCTURE) {
kSpring = in.EmptyWeight;
bDamp = kSpring;
bDampRebound = kSpring * 10;
staticFCoeff = 1.0;
dynamicFCoeff = 1.0;
}
if (el->FindElement("spring_coeff"))
kSpring = el->FindElementValueAsNumberConvertTo("spring_coeff", "LBS/FT");
if (el->FindElement("damping_coeff")) {
@ -138,12 +146,15 @@ FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) :
if (el->FindElement("retractable"))
isRetractable = ((unsigned int)el->FindElementValueAsNumber("retractable"))>0.0?true:false;
GroundReactions = fdmex->GetGroundReactions();
PropertyManager = fdmex->GetPropertyManager();
ForceY_Table = 0;
force_table = el->FindElement("table");
while (force_table) {
force_type = force_table->GetAttributeValue("type");
if (force_type == "CORNERING_COEFF") {
ForceY_Table = new FGTable(fdmex->GetPropertyManager(), force_table);
ForceY_Table = new FGTable(PropertyManager, force_table);
} else {
cerr << "Undefined force table for " << name << " contact point" << endl;
}
@ -212,12 +223,6 @@ FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) :
<< sSteerType << " is undefined." << endl;
}
Auxiliary = fdmex->GetAuxiliary();
Propagate = fdmex->GetPropagate();
FCS = fdmex->GetFCS();
MassBalance = fdmex->GetMassBalance();
GroundReactions = fdmex->GetGroundReactions();
GearUp = false;
GearDown = true;
GearPos = 1.0;
@ -236,8 +241,6 @@ FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) :
MaximumStrutForce = MaximumStrutTravel = 0.0;
SinkRate = GroundSpeed = 0.0;
vWhlBodyVec = MassBalance->StructuralToBody(vXYZn);
vLocalGear = Propagate->GetTb2l() * vWhlBodyVec;
vWhlVelVec.InitMatrix();
compressLength = 0.0;
@ -274,29 +277,27 @@ FGLGear::~FGLGear()
FGColumnVector3& FGLGear::GetBodyForces(void)
{
double t = fdmex->GetSimTime();
dT = fdmex->GetDeltaT()*GroundReactions->GetRate();
vFn.InitMatrix();
if (isRetractable) ComputeRetractionState();
if (GearDown) {
FGColumnVector3 angularVel;
FGColumnVector3 terrainVel, dummy;
vWhlBodyVec = MassBalance->StructuralToBody(vXYZn); // Get wheel in body frame
vLocalGear = Propagate->GetTb2l() * vWhlBodyVec; // Get local frame wheel location
vLocalGear = in.Tb2l * in.vWhlBodyVec[GearNumber]; // Get local frame wheel location
gearLoc = Propagate->GetLocation().LocalToLocation(vLocalGear);
gearLoc = in.Location.LocalToLocation(vLocalGear);
// Compute the height of the theoretical location of the wheel (if strut is
// not compressed) with respect to the ground level
double height = fdmex->GetGroundCallback()->GetAGLevel(t, gearLoc, contact, normal, cvel, angularVel);
vGroundNormal = Propagate->GetTec2b() * normal;
double height = fdmex->GetGroundCallback()->GetAGLevel(t, gearLoc, contact, normal, terrainVel, dummy);
vGroundNormal = in.Tec2b * normal;
// The height returned above is the AGL and is expressed in the Z direction
// of the ECEF coordinate frame. We now need to transform this height in
// actual compression of the strut (BOGEY) of in the normal direction to the
// ground (STRUCTURE)
double normalZ = (Propagate->GetTec2l()*normal)(eZ);
double normalZ = (in.Tec2l*normal)(eZ);
double LGearProj = -(mTGear.Transposed() * vGroundNormal)(eZ);
switch (eContactType) {
@ -309,7 +310,6 @@ FGColumnVector3& FGLGear::GetBodyForces(void)
}
if (compressLength > 0.00) {
WOW = true;
// The following equations use the vector to the tire contact patch
@ -325,10 +325,10 @@ FGColumnVector3& FGLGear::GetBodyForces(void)
break;
}
FGColumnVector3 vWhlContactVec = vWhlBodyVec + vWhlDisplVec;
FGColumnVector3 vWhlContactVec = in.vWhlBodyVec[GearNumber] + vWhlDisplVec;
vActingXYZn = vXYZn + Tb2s * vWhlDisplVec;
FGColumnVector3 vBodyWhlVel = Propagate->GetPQR() * vWhlContactVec;
vBodyWhlVel += Propagate->GetUVW() - Propagate->GetTec2b() * cvel;
FGColumnVector3 vBodyWhlVel = in.PQR * vWhlContactVec;
vBodyWhlVel += in.UVW - in.Tec2b * terrainVel;
vWhlVelVec = mTGear.Transposed() * vBodyWhlVel;
@ -338,9 +338,13 @@ FGColumnVector3& FGLGear::GetBodyForces(void)
vLocalWhlVel = Transform().Transposed() * vBodyWhlVel;
compressSpeed = -vLocalWhlVel(eX);
if (eContactType == ctBOGEY)
compressSpeed /= LGearProj;
if (fdmex->GetTrimStatus())
compressSpeed = 0.0; // Steady state is sought during trimming
else {
compressSpeed = -vLocalWhlVel(eX);
if (eContactType == ctBOGEY)
compressSpeed /= LGearProj;
}
ComputeVerticalStrutForce();
@ -364,7 +368,7 @@ FGColumnVector3& FGLGear::GetBodyForces(void)
StrutForce = 0.0;
// Let wheel spin down slowly
vWhlVelVec(eX) -= 13.0*dT;
vWhlVelVec(eX) -= 13.0 * in.TotalDeltaT;
if (vWhlVelVec(eX) < 0.0) vWhlVelVec(eX) = 0.0;
// Return to neutral position between 1.0 and 0.8 gear pos.
@ -463,14 +467,14 @@ void FGLGear::ComputeSteeringAngle(void)
{
switch (eSteerType) {
case stSteer:
SteerAngle = degtorad * FCS->GetSteerPosDeg(GearNumber);
SteerAngle = degtorad * in.SteerPosDeg[GearNumber];
break;
case stFixed:
SteerAngle = 0.0;
break;
case stCaster:
if (!Castered)
SteerAngle = degtorad * FCS->GetSteerPosDeg(GearNumber);
SteerAngle = degtorad * in.SteerPosDeg[GearNumber];
else {
// Check that the speed is non-null otherwise use the current angle
if (vWhlVelVec.Magnitude(eX,eY) > 0.1)
@ -488,7 +492,7 @@ void FGLGear::ComputeSteeringAngle(void)
void FGLGear::ResetReporting(void)
{
if (Propagate->GetDistanceAGL() > 200.0) {
if (in.DistanceAGL > 200.0) {
FirstContact = false;
StartedGroundRun = false;
LandingReported = false;
@ -508,16 +512,16 @@ void FGLGear::InitializeReporting(void)
if (!FirstContact) {
FirstContact = true;
SinkRate = compressSpeed;
GroundSpeed = Propagate->GetVel().Magnitude();
GroundSpeed = in.Vground;
TakeoffReported = false;
}
// If the takeoff run is starting, initialize.
if ((Propagate->GetVel().Magnitude() > 0.1) &&
(FCS->GetBrake(bgLeft) == 0) &&
(FCS->GetBrake(bgRight) == 0) &&
(FCS->GetThrottlePos(0) > 0.90) && !StartedGroundRun)
if ((in.Vground > 0.1) &&
(in.BrakePos[bgLeft] == 0) &&
(in.BrakePos[bgRight] == 0) &&
(in.TakeoffThrottle && !StartedGroundRun))
{
TakeoffDistanceTraveled = 0;
TakeoffDistanceTraveled50ft = 0;
@ -531,25 +535,25 @@ void FGLGear::InitializeReporting(void)
void FGLGear::ReportTakeoffOrLanding(void)
{
if (FirstContact)
LandingDistanceTraveled += Auxiliary->GetVground()*dT;
LandingDistanceTraveled += in.Vground * in.TotalDeltaT;
if (StartedGroundRun) {
TakeoffDistanceTraveled50ft += Auxiliary->GetVground()*dT;
if (WOW) TakeoffDistanceTraveled += Auxiliary->GetVground()*dT;
TakeoffDistanceTraveled50ft += in.Vground * in.TotalDeltaT;
if (WOW) TakeoffDistanceTraveled += in.Vground * in.TotalDeltaT;
}
if ( ReportEnable
&& Auxiliary->GetVground() <= 0.05
&& in.Vground <= 0.05
&& !LandingReported
&& GroundReactions->GetWOW())
&& in.WOW)
{
if (debug_lvl > 0) Report(erLand);
}
if ( ReportEnable
&& !TakeoffReported
&& (Propagate->GetDistanceAGL() - vLocalGear(eZ)) > 50.0
&& !GroundReactions->GetWOW())
&& (in.DistanceAGL - vLocalGear(eZ)) > 50.0
&& !in.WOW)
{
if (debug_lvl > 0) Report(erTakeoff);
}
@ -584,24 +588,24 @@ void FGLGear::ComputeBrakeForceCoefficient(void)
{
switch (eBrakeGrp) {
case bgLeft:
BrakeFCoeff = ( rollingFCoeff*(1.0 - FCS->GetBrake(bgLeft)) +
staticFCoeff*FCS->GetBrake(bgLeft) );
BrakeFCoeff = ( rollingFCoeff * (1.0 - in.BrakePos[bgLeft]) +
staticFCoeff * in.BrakePos[bgLeft] );
break;
case bgRight:
BrakeFCoeff = ( rollingFCoeff*(1.0 - FCS->GetBrake(bgRight)) +
staticFCoeff*FCS->GetBrake(bgRight) );
BrakeFCoeff = ( rollingFCoeff * (1.0 - in.BrakePos[bgRight]) +
staticFCoeff * in.BrakePos[bgRight] );
break;
case bgCenter:
BrakeFCoeff = ( rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
staticFCoeff*FCS->GetBrake(bgCenter) );
BrakeFCoeff = ( rollingFCoeff * (1.0 - in.BrakePos[bgCenter]) +
staticFCoeff * in.BrakePos[bgCenter] );
break;
case bgNose:
BrakeFCoeff = ( rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
staticFCoeff*FCS->GetBrake(bgCenter) );
BrakeFCoeff = ( rollingFCoeff * (1.0 - in.BrakePos[bgCenter]) +
staticFCoeff * in.BrakePos[bgCenter] );
break;
case bgTail:
BrakeFCoeff = ( rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
staticFCoeff*FCS->GetBrake(bgCenter) );
BrakeFCoeff = ( rollingFCoeff * (1.0 - in.BrakePos[bgCenter]) +
staticFCoeff * in.BrakePos[bgCenter] );
break;
case bgNone:
BrakeFCoeff = rollingFCoeff;
@ -683,9 +687,9 @@ void FGLGear::ComputeVerticalStrutForce(void)
double FGLGear::GetGearUnitPos(void)
{
// hack to provide backward compatibility to gear/gear-pos-norm property
if( useFCSGearPos || FCS->GetGearPos() != 1.0 ) {
if( useFCSGearPos || in.FCSGearPos != 1.0 ) {
useFCSGearPos = true;
return FCS->GetGearPos();
return in.FCSGearPos;
}
return GearPos;
}
@ -711,7 +715,14 @@ void FGLGear::ComputeJacobian(const FGColumnVector3& vWhlContactVec)
LMultiplier[ftDynamic].MomentJacobian = vWhlContactVec * LMultiplier[ftDynamic].ForceJacobian;
LMultiplier[ftDynamic].Max = 0.;
LMultiplier[ftDynamic].Min = -fabs(dynamicFCoeff * vFn(eX));
// The Lagrange multiplier value obtained from the previous iteration is kept
// This is supposed to accelerate the convergence of the projected Gauss-Seidel
// algorithm. The code just below is to make sure that the initial value
// is consistent with the current friction coefficient and normal reaction.
LMultiplier[ftDynamic].value = Constrain(LMultiplier[ftDynamic].Min, LMultiplier[ftDynamic].value, LMultiplier[ftDynamic].Max);
GroundReactions->RegisterLagrangeMultiplier(&LMultiplier[ftDynamic]);
}
else {
// Static friction is used for ctSTRUCTURE when the contact point is not moving.
@ -738,39 +749,24 @@ void FGLGear::ComputeJacobian(const FGColumnVector3& vWhlContactVec)
LMultiplier[ftRoll].Min = -LMultiplier[ftRoll].Max;
LMultiplier[ftSide].Min = -LMultiplier[ftSide].Max;
// The Lagrange multiplier value obtained from the previous iteration is kept
// This is supposed to accelerate the convergence of the projected Gauss-Seidel
// algorithm. The code just below is to make sure that the initial value
// is consistent with the current friction coefficient and normal reaction.
LMultiplier[ftRoll].value = Constrain(LMultiplier[ftRoll].Min, LMultiplier[ftRoll].value, LMultiplier[ftRoll].Max);
LMultiplier[ftSide].value = Constrain(LMultiplier[ftSide].Min, LMultiplier[ftSide].value, LMultiplier[ftSide].Max);
GroundReactions->RegisterLagrangeMultiplier(&LMultiplier[ftRoll]);
GroundReactions->RegisterLagrangeMultiplier(&LMultiplier[ftSide]);
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// This function is used by the MultiplierIterator class to enumerate the
// Lagrange multipliers of a landing gear. This allows to encapsulate the storage
// of the multipliers in FGLGear without exposing it. From an outside point of
// view, each FGLGear instance has a number of Lagrange multipliers which can be
// accessed through this routine without knowing the exact constraint which they
// model.
FGPropagate::LagrangeMultiplier* FGLGear::GetMultiplierEntry(int entry)
{
switch(entry) {
case 0:
if (StaticFriction)
return &LMultiplier[ftRoll];
else
return &LMultiplier[ftDynamic];
case 1:
if (StaticFriction)
return &LMultiplier[ftSide];
default:
return NULL;
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// This routine is called after the Lagrange multiplier has been computed. The
// friction forces of the landing gear are then updated accordingly.
FGColumnVector3& FGLGear::UpdateForces(void)
// This routine is called after the Lagrange multiplier has been computed in
// the FGAccelerations class. The friction forces of the landing gear are then
// updated accordingly.
void FGLGear::UpdateForces(void)
{
if (StaticFriction) {
vFn(eY) = LMultiplier[ftRoll].value;
@ -778,9 +774,6 @@ FGColumnVector3& FGLGear::UpdateForces(void)
}
else
vFn += LMultiplier[ftDynamic].value * (Transform ().Transposed() * LMultiplier[ftDynamic].ForceJacobian);
// Return the updated force in the body frame
return FGForce::GetBodyForces();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -789,41 +782,52 @@ void FGLGear::bind(void)
{
string property_name;
string base_property_name;
base_property_name = CreateIndexedPropertyName("gear/unit", GearNumber);
switch(eContactType) {
case ctBOGEY:
base_property_name = CreateIndexedPropertyName("gear/unit", GearNumber);
break;
case ctSTRUCTURE:
base_property_name = CreateIndexedPropertyName("contact/unit", GearNumber);
break;
default:
return;
}
property_name = base_property_name + "/WOW";
PropertyManager->Tie( property_name.c_str(), &WOW );
property_name = base_property_name + "/z-position";
PropertyManager->Tie( property_name.c_str(), (FGForce*)this,
&FGForce::GetLocationZ, &FGForce::SetLocationZ);
property_name = base_property_name + "/compression-ft";
PropertyManager->Tie( property_name.c_str(), &compressLength );
property_name = base_property_name + "/static_friction_coeff";
PropertyManager->Tie( property_name.c_str(), &staticFCoeff );
property_name = base_property_name + "/dynamic_friction_coeff";
PropertyManager->Tie( property_name.c_str(), &dynamicFCoeff );
if (eContactType == ctBOGEY) {
property_name = base_property_name + "/slip-angle-deg";
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &WheelSlip );
property_name = base_property_name + "/WOW";
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &WOW );
PropertyManager->Tie( property_name.c_str(), &WheelSlip );
property_name = base_property_name + "/wheel-speed-fps";
fdmex->GetPropertyManager()->Tie( property_name.c_str(), (FGLGear*)this,
PropertyManager->Tie( property_name.c_str(), (FGLGear*)this,
&FGLGear::GetWheelRollVel);
property_name = base_property_name + "/z-position";
fdmex->GetPropertyManager()->Tie( property_name.c_str(), (FGForce*)this,
&FGForce::GetLocationZ, &FGForce::SetLocationZ);
property_name = base_property_name + "/compression-ft";
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &compressLength );
property_name = base_property_name + "/side_friction_coeff";
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &FCoeff );
property_name = base_property_name + "/static_friction_coeff";
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &staticFCoeff );
PropertyManager->Tie( property_name.c_str(), &FCoeff );
property_name = base_property_name + "/rolling_friction_coeff";
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &rollingFCoeff );
property_name = base_property_name + "/dynamic_friction_coeff";
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &dynamicFCoeff );
PropertyManager->Tie( property_name.c_str(), &rollingFCoeff );
if (eSteerType == stCaster) {
property_name = base_property_name + "/steering-angle-deg";
fdmex->GetPropertyManager()->Tie( property_name.c_str(), this, &FGLGear::GetSteerAngleDeg );
PropertyManager->Tie( property_name.c_str(), this, &FGLGear::GetSteerAngleDeg );
property_name = base_property_name + "/castered";
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &Castered);
PropertyManager->Tie( property_name.c_str(), &Castered);
}
}
if( isRetractable ) {
property_name = base_property_name + "/pos-norm";
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &GearPos );
PropertyManager->Tie( property_name.c_str(), &GearPos );
}
}
@ -856,11 +860,11 @@ void FGLGear::Report(ReportType repType)
<< " ft, " << TakeoffDistanceTraveled*0.3048 << " meters" << endl;
cout << " Distance traveled (over 50'): " << TakeoffDistanceTraveled50ft
<< " ft, " << TakeoffDistanceTraveled50ft*0.3048 << " meters" << endl;
cout << " [Altitude (ASL): " << Propagate->GetAltitudeASL() << " ft. / "
<< Propagate->GetAltitudeASLmeters() << " m | Temperature: "
<< fdmex->GetAtmosphere()->GetTemperature() - 459.67 << " F / "
<< RankineToCelsius(fdmex->GetAtmosphere()->GetTemperature()) << " C]" << endl;
cout << " [Velocity (KCAS): " << Auxiliary->GetVcalibratedKTS() << "]" << endl;
cout << " [Altitude (ASL): " << in.DistanceASL << " ft. / "
<< in.DistanceASL*FGJSBBase::fttom << " m | Temperature: "
<< in.Temperature - 459.67 << " F / "
<< RankineToCelsius(in.Temperature) << " C]" << endl;
cout << " [Velocity (KCAS): " << in.VcalibratedKts << "]" << endl;
TakeoffReported = true;
break;
case erNone:

View file

@ -38,16 +38,18 @@ SENTRY
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "models/propulsion/FGForce.h"
#include "models/FGPropagate.h"
#include "math/FGColumnVector3.h"
#include <string>
#include "models/propulsion/FGForce.h"
#include "math/FGColumnVector3.h"
#include "math/FGMatrix33.h"
#include "math/LagrangeMultiplier.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_LGEAR "$Id: FGLGear.h,v 1.41 2010/09/22 11:33:40 jberndt Exp $"
#define ID_LGEAR "$Id: FGLGear.h,v 1.47 2011/08/30 21:05:56 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -55,13 +57,9 @@ FORWARD DECLARATIONS
namespace JSBSim {
class FGAircraft;
class FGPropagate;
class FGFCS;
class FGMassBalance;
class FGAuxiliary;
class FGTable;
class Element;
class FGPropertyManager;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
@ -180,7 +178,7 @@ CLASS DOCUMENTATION
</contact>
@endcode
@author Jon S. Berndt
@version $Id: FGLGear.h,v 1.41 2010/09/22 11:33:40 jberndt Exp $
@version $Id: FGLGear.h,v 1.47 2011/08/30 21:05:56 bcoconni Exp $
@see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
NASA-Ames", NASA CR-2497, January 1975
@see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
@ -196,8 +194,30 @@ CLASS DECLARATION
class FGLGear : public FGForce
{
public:
struct Inputs {
double Vground;
double VcalibratedKts;
double Temperature;
double DistanceAGL;
double DistanceASL;
double TotalDeltaT;
bool TakeoffThrottle;
bool WOW;
FGMatrix33 Tb2l;
FGMatrix33 Tec2l;
FGMatrix33 Tec2b;
FGColumnVector3 PQR;
FGColumnVector3 UVW;
FGLocation Location;
std::vector <double> SteerPosDeg;
std::vector <double> BrakePos;
std::vector <FGColumnVector3> vWhlBodyVec;
double FCSGearPos;
double EmptyWeight;
};
/// Brake grouping enumerators
enum BrakeGroup {bgNone=0, bgLeft, bgRight, bgCenter, bgNose, bgTail };
enum BrakeGroup {bgNone=0, bgLeft, bgRight, bgCenter, bgNose, bgTail, bgNumBrakeGroups };
/// Steering group membership enumerators
enum SteerType {stSteer, stFixed, stCaster};
/// Contact point type
@ -213,7 +233,7 @@ public:
@param Executive a pointer to the parent executive object
@param number integer identifier for this instance of FGLGear
*/
FGLGear(Element* el, FGFDMExec* Executive, int number);
FGLGear(Element* el, FGFDMExec* Executive, int number, const struct Inputs& input);
/// Destructor
~FGLGear();
@ -221,8 +241,8 @@ public:
FGColumnVector3& GetBodyForces(void);
/// Gets the location of the gear in Body axes
FGColumnVector3& GetBodyLocation(void) { return vWhlBodyVec; }
double GetBodyLocation(int idx) const { return vWhlBodyVec(idx); }
FGColumnVector3 GetBodyLocation(void) const { return in.vWhlBodyVec[GearNumber]; }
double GetBodyLocation(int idx) const { return in.vWhlBodyVec[GearNumber](idx); }
FGColumnVector3& GetLocalGear(void) { return vLocalGear; }
double GetLocalGear(int idx) const { return vLocalGear(idx); }
@ -268,9 +288,11 @@ public:
bool GetGearUnitUp(void) const { return GearUp; }
bool GetGearUnitDown(void) const { return GearDown; }
double GetWheelRollForce(void) {
UpdateForces();
FGColumnVector3 vForce = mTGear.Transposed() * FGForce::GetBodyForces();
return vForce(eX)*cos(SteerAngle) + vForce(eY)*sin(SteerAngle); }
double GetWheelSideForce(void) {
UpdateForces();
FGColumnVector3 vForce = mTGear.Transposed() * FGForce::GetBodyForces();
return vForce(eY)*cos(SteerAngle) - vForce(eX)*sin(SteerAngle); }
double GetWheelRollVel(void) const { return vWhlVelVec(eX)*cos(SteerAngle)
@ -282,9 +304,8 @@ public:
bool IsBogey(void) const { return (eContactType == ctBOGEY);}
double GetGearUnitPos(void);
double GetSteerAngleDeg(void) const { return radtodeg*SteerAngle; }
FGPropagate::LagrangeMultiplier* GetMultiplierEntry(int entry);
void SetLagrangeMultiplier(double lambda, int entry);
FGColumnVector3& UpdateForces(void);
const struct Inputs& in;
void bind(void);
@ -293,13 +314,11 @@ private:
static const FGMatrix33 Tb2s;
FGMatrix33 mTGear;
FGColumnVector3 vGearOrient;
FGColumnVector3 vWhlBodyVec;
FGColumnVector3 vLocalGear;
FGColumnVector3 vWhlVelVec, vLocalWhlVel; // Velocity of this wheel
FGColumnVector3 normal, cvel, vGroundNormal;
FGColumnVector3 normal, vGroundNormal;
FGLocation contact, gearLoc;
FGTable *ForceY_Table;
double dT;
double SteerAngle;
double kSpring;
double bDamp;
@ -348,13 +367,10 @@ private:
DampType eDampTypeRebound;
double maxSteerAngle;
FGPropagate::LagrangeMultiplier LMultiplier[3];
LagrangeMultiplier LMultiplier[3];
FGAuxiliary* Auxiliary;
FGPropagate* Propagate;
FGFCS* FCS;
FGMassBalance* MassBalance;
FGGroundReactions* GroundReactions;
FGPropertyManager* PropertyManager;
void ComputeRetractionState(void);
void ComputeBrakeForceCoefficient(void);
@ -364,6 +380,7 @@ private:
void ComputeVerticalStrutForce(void);
void ComputeGroundCoordSys(void);
void ComputeJacobian(const FGColumnVector3& vWhlContactVec);
void UpdateForces(void);
void CrashDetect(void);
void InitializeReporting(void);
void ResetReporting(void);

View file

@ -38,20 +38,18 @@ HISTORY
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGMassBalance.h"
#include "FGPropulsion.h"
#include "propulsion/FGTank.h"
#include "FGBuoyantForces.h"
#include "input_output/FGPropertyManager.h"
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include "FGMassBalance.h"
#include "FGFDMExec.h"
#include "input_output/FGPropertyManager.h"
using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGMassBalance.cpp,v 1.35 2011/05/20 03:18:36 jberndt Exp $";
static const char *IdSrc = "$Id: FGMassBalance.cpp,v 1.37 2011/07/12 01:52:49 jberndt Exp $";
static const char *IdHdr = ID_MASSBALANCE;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -149,8 +147,8 @@ bool FGMassBalance::Load(Element* el)
if (FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight += FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight();
}
Weight = EmptyWeight + FDMExec->GetPropulsion()->GetTanksWeight() + GetTotalPointMassWeight()
+ FDMExec->GetBuoyantForces()->GetGasMass()*slugtolb + ChildFDMWeight;
Weight = EmptyWeight + in.TanksWeight + GetTotalPointMassWeight()
+ in.GasMass*slugtolb + ChildFDMWeight;
Mass = lbtoslug*Weight;
@ -177,16 +175,17 @@ bool FGMassBalance::Run(bool Holding)
if (FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight += FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight();
}
Weight = EmptyWeight + FDMExec->GetPropulsion()->GetTanksWeight() + GetTotalPointMassWeight()
+ FDMExec->GetBuoyantForces()->GetGasMass()*slugtolb + ChildFDMWeight;
Weight = EmptyWeight + in.TanksWeight + GetTotalPointMassWeight()
+ in.GasMass*slugtolb + ChildFDMWeight;
Mass = lbtoslug*Weight;
// Calculate new CG
vXYZcg = (FDMExec->GetPropulsion()->GetTanksMoment() + EmptyWeight*vbaseXYZcg
vXYZcg = (EmptyWeight*vbaseXYZcg
+ GetPointMassMoment()
+ FDMExec->GetBuoyantForces()->GetGasMassMoment()) / Weight;
+ in.TanksMoment
+ in.GasMoment) / Weight;
// Track frame-by-frame delta CG, and move the EOM-tracked location
// by this amount.
@ -204,8 +203,8 @@ bool FGMassBalance::Run(bool Holding)
mJ += GetPointmassInertia( lbtoslug * EmptyWeight, vbaseXYZcg );
// Then add the contributions from the additional pointmasses.
mJ += CalculatePMInertias();
mJ += FDMExec->GetPropulsion()->CalculateTankInertias();
mJ += FDMExec->GetBuoyantForces()->GetGasMassInertia();
mJ += in.TankInertia;
mJ += in.GasInertia;
Ixx = mJ(1,1);
Iyy = mJ(2,2);
@ -430,24 +429,7 @@ void FGMassBalance::GetMassPropertiesReport(void) const
<< setw(12) << pm->GetPointMassMoI(3,3) << endl;
}
for (unsigned int i=0;i<FDMExec->GetPropulsion()->GetNumTanks() ;i++) {
FGTank* tank = FDMExec->GetPropulsion()->GetTank(i);
string tankname="";
if (tank->GetType() == FGTank::ttFUEL && tank->GetGrainType() != FGTank::gtUNKNOWN) {
tankname = "Solid Fuel";
} else if (tank->GetType() == FGTank::ttFUEL) {
tankname = "Fuel";
} else if (tank->GetType() == FGTank::ttOXIDIZER) {
tankname = "Oxidizer";
} else {
tankname = "(Unknown tank type)";
}
cout << highint << left << setw(4) << i << setw(30) << tankname << normint
<< right << setw(10) << tank->GetContents() << setw(8) << tank->GetXYZ(eX)
<< setw(8) << tank->GetXYZ(eY) << setw(8) << tank->GetXYZ(eZ)
<< setw(12) << "*" << setw(12) << "*"
<< setw(12) << "*" << endl;
}
cout << FDMExec->GetPropulsionTankReport();
cout << underon << setw(104) << " " << underoff << endl;
cout << highint << left << setw(30) << " Total: " << right << setw(14) << Weight

View file

@ -49,7 +49,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_MASSBALANCE "$Id: FGMassBalance.h,v 1.23 2011/05/20 03:18:36 jberndt Exp $"
#define ID_MASSBALANCE "$Id: FGMassBalance.h,v 1.25 2011/07/28 12:48:19 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONSS
@ -138,13 +138,13 @@ public:
slugs at the given vector r in the structural frame. The units
should be for the mass in slug and the vector in the structural
frame as usual in inches.
@param slugs the mass of this single pointmass given in slugs
@param mass_sl the mass of this single pointmass given in slugs
@param r the location of this single pointmass in the structural frame
*/
FGMatrix33 GetPointmassInertia(double slugs, const FGColumnVector3& r) const
FGMatrix33 GetPointmassInertia(double mass_sl, const FGColumnVector3& r) const
{
FGColumnVector3 v = StructuralToBody( r );
FGColumnVector3 sv = slugs*v;
FGColumnVector3 sv = mass_sl*v;
double xx = sv(1)*v(1);
double yy = sv(2)*v(2);
double zz = sv(3)*v(3);
@ -179,6 +179,15 @@ public:
void SetAircraftBaseInertias(FGMatrix33 BaseJ) {baseJ = BaseJ;}
void GetMassPropertiesReport(void) const;
struct Inputs {
double GasMass;
double TanksWeight;
FGColumnVector3 GasMoment;
FGMatrix33 GasInertia;
FGColumnVector3 TanksMoment;
FGMatrix33 TankInertia;
} in;
private:
double Weight;
double EmptyWeight;

View file

@ -48,7 +48,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_MODEL "$Id: FGModel.h,v 1.19 2011/05/20 03:18:36 jberndt Exp $"
#define ID_MODEL "$Id: FGModel.h,v 1.20 2011/06/21 04:41:54 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -79,7 +79,7 @@ public:
/// Constructor
FGModel(FGFDMExec*);
/// Destructor
~FGModel();
virtual ~FGModel();
std::string Name;

View file

@ -39,9 +39,16 @@ HISTORY
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <sstream>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include "FGOutput.h"
#include "FGFDMExec.h"
#include "FGAtmosphere.h"
#include "FGAccelerations.h"
#include "atmosphere/FGWinds.h"
#include "FGFCS.h"
#include "FGAerodynamics.h"
#include "FGGroundReactions.h"
@ -56,10 +63,6 @@ INCLUDES
#include "models/propulsion/FGEngine.h"
#include "models/propulsion/FGTank.h"
#include "models/propulsion/FGPiston.h"
#include <sstream>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#if defined(WIN32) && !defined(__CYGWIN__)
# include <windows.h>
@ -74,7 +77,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGOutput.cpp,v 1.55 2011/05/20 03:18:36 jberndt Exp $";
static const char *IdSrc = "$Id: FGOutput.cpp,v 1.62 2011/09/25 15:38:30 bcoconni Exp $";
static const char *IdHdr = ID_OUTPUT;
// (stolen from FGFS native_fdm.cxx)
@ -246,11 +249,12 @@ void FGOutput::DelimitedOutput(const string& fname)
const FGAuxiliary* Auxiliary = FDMExec->GetAuxiliary();
const FGAircraft* Aircraft = FDMExec->GetAircraft();
const FGAtmosphere* Atmosphere = FDMExec->GetAtmosphere();
const FGWinds* Winds = FDMExec->GetWinds();
const FGPropulsion* Propulsion = FDMExec->GetPropulsion();
const FGMassBalance* MassBalance = FDMExec->GetMassBalance();
const FGPropagate* Propagate = FDMExec->GetPropagate();
const FGAccelerations* Accelerations = FDMExec->GetAccelerations();
const FGFCS* FCS = FDMExec->GetFCS();
const FGInertial* Inertial = FDMExec->GetInertial();
const FGGroundReactions* GroundReactions = FDMExec->GetGroundReactions();
const FGExternalReactions* ExternalReactions = FDMExec->GetExternalReactions();
const FGBuoyantForces* BuoyantForces = FDMExec->GetBuoyantForces();
@ -409,7 +413,7 @@ void FGOutput::DelimitedOutput(const string& fname)
if (SubSystems & ssRates) {
outstream << delimeter;
outstream << (radtodeg*Propagate->GetPQR()).Dump(delimeter) << delimeter;
outstream << (radtodeg*Propagate->GetPQRdot()).Dump(delimeter) << delimeter;
outstream << (radtodeg*Accelerations->GetPQRdot()).Dump(delimeter) << delimeter;
outstream << (radtodeg*Propagate->GetPQRi()).Dump(delimeter);
}
if (SubSystems & ssVelocities) {
@ -453,9 +457,9 @@ void FGOutput::DelimitedOutput(const string& fname)
outstream << Atmosphere->GetTemperature() << delimeter;
outstream << Atmosphere->GetPressureSL() << delimeter;
outstream << Atmosphere->GetPressure() << delimeter;
outstream << Atmosphere->GetTurbMagnitude() << delimeter;
outstream << Atmosphere->GetTurbDirection().Dump(delimeter) << delimeter;
outstream << Atmosphere->GetTotalWindNED().Dump(delimeter);
outstream << Winds->GetTurbMagnitude() << delimeter;
outstream << Winds->GetTurbDirection().Dump(delimeter) << delimeter;
outstream << Winds->GetTotalWindNED().Dump(delimeter);
}
if (SubSystems & ssMassProps) {
outstream << delimeter;
@ -477,7 +481,7 @@ void FGOutput::DelimitedOutput(const string& fname)
outstream << ((FGColumnVector3)Propagate->GetInertialPosition()).Dump(delimeter) << delimeter;
outstream << ((FGColumnVector3)Propagate->GetLocation()).Dump(delimeter) << delimeter;
outstream.precision(14);
outstream << Inertial->GetEarthPositionAngleDeg() << delimeter;
outstream << Propagate->GetEarthPositionAngleDeg() << delimeter;
outstream << Propagate->GetDistanceAGL() << delimeter;
outstream << Propagate->GetTerrainElevation();
outstream.precision(10);
@ -513,10 +517,8 @@ void FGOutput::DelimitedOutput(const string& fname)
void FGOutput::SocketDataFill(FGNetFDM* net)
{
const FGAerodynamics* Aerodynamics = FDMExec->GetAerodynamics();
const FGAuxiliary* Auxiliary = FDMExec->GetAuxiliary();
const FGPropulsion* Propulsion = FDMExec->GetPropulsion();
const FGMassBalance* MassBalance = FDMExec->GetMassBalance();
const FGPropagate* Propagate = FDMExec->GetPropagate();
const FGFCS* FCS = FDMExec->GetFCS();
const FGGroundReactions* GroundReactions = FDMExec->GetGroundReactions();
@ -733,8 +735,10 @@ void FGOutput::SocketOutput(void)
const FGPropulsion* Propulsion = FDMExec->GetPropulsion();
const FGMassBalance* MassBalance = FDMExec->GetMassBalance();
const FGPropagate* Propagate = FDMExec->GetPropagate();
const FGAccelerations* Accelerations = FDMExec->GetAccelerations();
const FGFCS* FCS = FDMExec->GetFCS();
const FGAtmosphere* Atmosphere = FDMExec->GetAtmosphere();
const FGWinds* Winds = FDMExec->GetWinds();
const FGAircraft* Aircraft = FDMExec->GetAircraft();
const FGGroundReactions* GroundReactions = FDMExec->GetGroundReactions();
@ -875,9 +879,9 @@ void FGOutput::SocketOutput(void)
socket->Append(radtodeg*Propagate->GetPQR(eP));
socket->Append(radtodeg*Propagate->GetPQR(eQ));
socket->Append(radtodeg*Propagate->GetPQR(eR));
socket->Append(radtodeg*Propagate->GetPQRdot(eP));
socket->Append(radtodeg*Propagate->GetPQRdot(eQ));
socket->Append(radtodeg*Propagate->GetPQRdot(eR));
socket->Append(radtodeg*Accelerations->GetPQRdot(eP));
socket->Append(radtodeg*Accelerations->GetPQRdot(eQ));
socket->Append(radtodeg*Accelerations->GetPQRdot(eR));
}
if (SubSystems & ssVelocities) {
socket->Append(Auxiliary->Getqbar());
@ -910,9 +914,9 @@ void FGOutput::SocketOutput(void)
socket->Append(Atmosphere->GetDensity());
socket->Append(Atmosphere->GetPressureSL());
socket->Append(Atmosphere->GetPressure());
socket->Append(Atmosphere->GetTurbMagnitude());
socket->Append(Atmosphere->GetTurbDirection().Dump(","));
socket->Append(Atmosphere->GetTotalWindNED().Dump(","));
socket->Append(Winds->GetTurbMagnitude());
socket->Append(Winds->GetTurbDirection().Dump(","));
socket->Append(Winds->GetTotalWindNED().Dump(","));
}
if (SubSystems & ssMassProps) {
socket->Append(MassBalance->GetJ()(1,1));
@ -999,8 +1003,12 @@ bool FGOutput::Load(Element* element)
if (!document) return false;
name = FDMExec->GetRootDir() + document->GetAttributeValue("name");
SetType(document->GetAttributeValue("type"));
name = document->GetAttributeValue("name");
if (((Type == otCSV) || (Type == otTab)) && (name != "cout") && (name !="COUT"))
name = FDMExec->GetRootDir() + name;
Port = document->GetAttributeValue("port");
if (!Port.empty() && (Type == otSocket || Type == otFlightGear)) {
port = atoi(Port.c_str());

View file

@ -62,16 +62,13 @@ INCLUDES
#include "FGPropagate.h"
#include "FGGroundReactions.h"
#include "FGFDMExec.h"
#include "FGAircraft.h"
#include "FGMassBalance.h"
#include "FGInertial.h"
#include "input_output/FGPropertyManager.h"
using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGPropagate.cpp,v 1.88 2011/05/20 03:18:36 jberndt Exp $";
static const char *IdSrc = "$Id: FGPropagate.cpp,v 1.96 2011/09/17 15:36:35 bcoconni Exp $";
static const char *IdHdr = ID_PROPAGATE;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -86,11 +83,7 @@ FGPropagate::FGPropagate(FGFDMExec* fdmex)
{
Debug(0);
Name = "FGPropagate";
gravType = gtWGS84;
vPQRidot.InitMatrix();
vQtrndot = FGQuaternion(0,0,0);
vUVWidot.InitMatrix();
vInertialVelocity.InitMatrix();
/// These define the indices use to select the various integrators.
@ -122,15 +115,12 @@ FGPropagate::~FGPropagate(void)
bool FGPropagate::InitModel(void)
{
// For initialization ONLY:
SeaLevelRadius = LocalTerrainRadius = FDMExec->GetInertial()->GetRefRadius();
SeaLevelRadius = LocalTerrainRadius = in.RefRadius;
FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(LocalTerrainRadius);
VState.vLocation.SetRadius( LocalTerrainRadius + 4.0 );
VState.vLocation.SetEllipse(FDMExec->GetInertial()->GetSemimajor(), FDMExec->GetInertial()->GetSemiminor());
vOmegaEarth = FGColumnVector3( 0.0, 0.0, FDMExec->GetInertial()->omega() ); // Earth rotation vector
VState.vLocation.SetEllipse(in.SemiMajor, in.SemiMinor);
vPQRidot.InitMatrix();
vQtrndot = FGQuaternion(0,0,0);
vUVWidot.InitMatrix();
vInertialVelocity.InitMatrix();
VState.dqPQRidot.resize(4, FGColumnVector3(0.0,0.0,0.0));
@ -150,7 +140,6 @@ bool FGPropagate::InitModel(void)
void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
{
SetSeaLevelRadius(FGIC->GetSeaLevelRadiusFtIC());
SetTerrainElevation(FGIC->GetTerrainElevationFtIC());
// Initialize the State Vector elements and the transformation matrices
@ -158,9 +147,9 @@ void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
// Set the position lat/lon/radius
VState.vLocation.SetPosition( FGIC->GetLongitudeRadIC(),
FGIC->GetLatitudeRadIC(),
FGIC->GetAltitudeASLFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
FGIC->GetAltitudeASLFtIC() + SeaLevelRadius);
VState.vLocation.SetEarthPositionAngle(FDMExec->GetInertial()->GetEarthPositionAngle());
VState.vLocation.SetEarthPositionAngle(0.0);
Ti2ec = VState.vLocation.GetTi2ec(); // ECI to ECEF transform
Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
@ -198,10 +187,22 @@ void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
FGIC->GetQRadpsIC(),
FGIC->GetRRadpsIC() );
VState.vPQRi = VState.vPQR + Ti2b * vOmegaEarth;
VState.vPQRi = VState.vPQR + Ti2b * in.vOmegaPlanet;
// Make an initial run and set past values
InitializeDerivatives();
CalculateInertialVelocity(); // Translational position derivative
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Initialize the past value deques
void FGPropagate::InitializeDerivatives()
{
for (int i=0; i<4; i++) {
VState.dqPQRidot[i] = in.vPQRidot;
VState.dqUVWidot[i] = in.vUVWidot;
VState.dqInertialVelocity[i] = VState.vInertialVelocity;
VState.dqQtrndot[i] = in.vQtrndot;
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -229,28 +230,22 @@ bool FGPropagate::Run(bool Holding)
if (FGModel::Run(Holding)) return true; // Fast return if we have nothing to do ...
if (Holding) return false;
double dt = FDMExec->GetDeltaT()*rate; // The 'stepsize'
double dt = in.DeltaT * rate; // The 'stepsize'
RunPreFunctions();
// Calculate state derivatives
CalculatePQRdot(); // Angular rate derivative
CalculateUVWdot(); // Translational rate derivative
ResolveFrictionForces(dt); // Update rate derivatives with friction forces
CalculateQuatdot(); // Angular orientation derivative
// Propagate rotational / translational velocity, angular /translational position, respectively.
Integrate(VState.vPQRi, vPQRidot, VState.dqPQRidot, dt, integrator_rotational_rate);
Integrate(VState.qAttitudeECI, vQtrndot, VState.dqQtrndot, dt, integrator_rotational_position);
Integrate(VState.vPQRi, in.vPQRidot, VState.dqPQRidot, dt, integrator_rotational_rate);
Integrate(VState.qAttitudeECI, in.vQtrndot, VState.dqQtrndot, dt, integrator_rotational_position);
Integrate(VState.vInertialPosition, VState.vInertialVelocity, VState.dqInertialVelocity, dt, integrator_translational_position);
Integrate(VState.vInertialVelocity, vUVWidot, VState.dqUVWidot, dt, integrator_translational_rate);
Integrate(VState.vInertialVelocity, in.vUVWidot, VState.dqUVWidot, dt, integrator_translational_rate);
// CAUTION : the order of the operations below is very important to get transformation
// matrices that are consistent with the new state of the vehicle
// 1. Update the Earth position angle (EPA)
VState.vLocation.SetEarthPositionAngle(FDMExec->GetInertial()->GetEarthPositionAngle());
VState.vLocation.IncrementEarthPositionAngle(in.vOmegaPlanet(eZ)*(in.DeltaT*rate));
// 2. Update the Ti2ec and Tec2i transforms from the updated EPA
Ti2ec = VState.vLocation.GetTi2ec(); // ECI to ECEF transform
@ -278,7 +273,7 @@ bool FGPropagate::Run(bool Holding)
VehicleRadius = GetRadius(); // Calculate current aircraft radius from center of planet
VState.vPQR = VState.vPQRi - Ti2b * vOmegaEarth;
VState.vPQR = VState.vPQRi - Ti2b * in.vOmegaPlanet;
VState.qAttitudeLocal = Tl2b.GetQuaternion();
@ -291,88 +286,6 @@ bool FGPropagate::Run(bool Holding)
return false;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Compute body frame rotational accelerations based on the current body moments
//
// vPQRdot is the derivative of the absolute angular velocity of the vehicle
// (body rate with respect to the inertial frame), expressed in the body frame,
// where the derivative is taken in the body frame.
// J is the inertia matrix
// Jinv is the inverse inertia matrix
// vMoments is the moment vector in the body frame
// VState.vPQRi is the total inertial angular velocity of the vehicle
// expressed in the body frame.
// Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
// Second edition (2004), eqn 1.5-16e (page 50)
void FGPropagate::CalculatePQRdot(void)
{
const FGColumnVector3& vMoments = FDMExec->GetAircraft()->GetMoments(); // current moments
const FGMatrix33& J = FDMExec->GetMassBalance()->GetJ(); // inertia matrix
const FGMatrix33& Jinv = FDMExec->GetMassBalance()->GetJinv(); // inertia matrix inverse
// Compute body frame rotational accelerations based on the current body
// moments and the total inertial angular velocity expressed in the body
// frame.
vPQRidot = Jinv*(vMoments - VState.vPQRi*(J*VState.vPQRi));
vPQRdot = vPQRidot - VState.vPQRi * (Ti2b * vOmegaEarth);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Compute the quaternion orientation derivative
//
// vQtrndot is the quaternion derivative.
// Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
// Second edition (2004), eqn 1.5-16b (page 50)
void FGPropagate::CalculateQuatdot(void)
{
// Compute quaternion orientation derivative on current body rates
vQtrndot = VState.qAttitudeECI.GetQDot( VState.vPQRi);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// This set of calculations results in the body and inertial frame accelerations
// being computed.
// Compute body and inertial frames accelerations based on the current body
// forces including centripetal and coriolis accelerations for the former.
// vOmegaEarth is the Earth angular rate - expressed in the inertial frame -
// so it has to be transformed to the body frame. More completely,
// vOmegaEarth is the rate of the ECEF frame relative to the Inertial
// frame (ECI), expressed in the Inertial frame.
// vForces is the total force on the vehicle in the body frame.
// VState.vPQR is the vehicle body rate relative to the ECEF frame, expressed
// in the body frame.
// VState.vUVW is the vehicle velocity relative to the ECEF frame, expressed
// in the body frame.
// Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
// Second edition (2004), eqns 1.5-13 (pg 48) and 1.5-16d (page 50)
void FGPropagate::CalculateUVWdot(void)
{
double mass = FDMExec->GetMassBalance()->GetMass(); // mass
const FGColumnVector3& vForces = FDMExec->GetAircraft()->GetForces(); // current forces
vUVWdot = vForces/mass - (VState.vPQR + 2.0*(Ti2b *vOmegaEarth)) * VState.vUVW;
// Include Centripetal acceleration.
vUVWdot -= Ti2b * (vOmegaEarth*(vOmegaEarth*VState.vInertialPosition));
// Include Gravitation accel
switch (gravType) {
case gtStandard:
vGravAccel = Tl2b * FGColumnVector3( 0.0, 0.0, FDMExec->GetInertial()->GetGAccel(VehicleRadius) );
break;
case gtWGS84:
vGravAccel = Tec2b * FDMExec->GetInertial()->GetGravityJ2(VState.vLocation);
break;
}
vUVWdot += vGravAccel;
vUVWidot = Tb2i * (vForces/mass + vGravAccel);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Transform the velocity vector of the body relative to the origin (Earth
// center) to be expressed in the inertial frame, and add the vehicle velocity
@ -382,7 +295,7 @@ void FGPropagate::CalculateUVWdot(void)
void FGPropagate::CalculateInertialVelocity(void)
{
VState.vInertialVelocity = Tb2i * VState.vUVW + (vOmegaEarth * VState.vInertialPosition);
VState.vInertialVelocity = Tb2i * VState.vUVW + (in.vOmegaPlanet * VState.vInertialPosition);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -392,7 +305,7 @@ void FGPropagate::CalculateInertialVelocity(void)
void FGPropagate::CalculateUVW(void)
{
VState.vUVW = Ti2b * (VState.vInertialVelocity - (vOmegaEarth * VState.vInertialPosition));
VState.vUVW = Ti2b * (VState.vInertialVelocity - (in.vOmegaPlanet * VState.vInertialPosition));
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -449,167 +362,6 @@ void FGPropagate::Integrate( FGQuaternion& Integrand,
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Evaluates the rates (translation or rotation) that the friction forces have
// to resist to. This includes the external forces and moments as well as the
// relative movement between the aircraft and the ground.
// Erin Catto's paper (see ref [6]) only supports Euler integration scheme and
// this algorithm has been adapted to handle the multistep algorithms that
// JSBSim supports (i.e. Trapezoidal, Adams-Bashforth 2, 3 and 4). The capacity
// to handle the multistep integration schemes adds some complexity but it
// significantly helps stabilizing the friction forces.
void FGPropagate::EvaluateRateToResistTo(FGColumnVector3& vdot,
const FGColumnVector3& Val,
const FGColumnVector3& ValDot,
const FGColumnVector3& LocalTerrainVal,
deque <FGColumnVector3>& dqValDot,
const double dt,
const eIntegrateType integration_type)
{
switch(integration_type) {
case eAdamsBashforth4:
vdot = ValDot + Ti2b * (-59.*dqValDot[0]+37.*dqValDot[1]-9.*dqValDot[2])/55.;
if (dt > 0.) // Zeroes out the relative movement between aircraft and ground
vdot += 24.*(Val - Tec2b * LocalTerrainVal) / (55.*dt);
break;
case eAdamsBashforth3:
vdot = ValDot + Ti2b * (-16.*dqValDot[0]+5.*dqValDot[1])/23.;
if (dt > 0.) // Zeroes out the relative movement between aircraft and ground
vdot += 12.*(Val - Tec2b * LocalTerrainVal) / (23.*dt);
break;
case eAdamsBashforth2:
vdot = ValDot - Ti2b * dqValDot[0]/3.;
if (dt > 0.) // Zeroes out the relative movement between aircraft and ground
vdot += 2.*(Val - Tec2b * LocalTerrainVal) / (3.*dt);
break;
case eTrapezoidal:
vdot = ValDot + Ti2b * dqValDot[0];
if (dt > 0.) // Zeroes out the relative movement between aircraft and ground
vdot += 2.*(Val - Tec2b * LocalTerrainVal) / dt;
break;
case eRectEuler:
vdot = ValDot;
if (dt > 0.) // Zeroes out the relative movement between aircraft and ground
vdot += (Val - Tec2b * LocalTerrainVal) / dt;
break;
case eNone:
break;
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Resolves the contact forces just before integrating the EOM.
// This routine is using Lagrange multipliers and the projected Gauss-Seidel
// (PGS) method.
// Reference: See Erin Catto, "Iterative Dynamics with Temporal Coherence",
// February 22, 2005
// In JSBSim there is only one rigid body (the aircraft) and there can be
// multiple points of contact between the aircraft and the ground. As a
// consequence our matrix J*M^-1*J^T is not sparse and the algorithm described
// in Catto's paper has been adapted accordingly.
// The friction forces are resolved in the body frame relative to the origin
// (Earth center).
void FGPropagate::ResolveFrictionForces(double dt)
{
const double invMass = 1.0 / FDMExec->GetMassBalance()->GetMass();
const FGMatrix33& Jinv = FDMExec->GetMassBalance()->GetJinv();
vector <FGColumnVector3> JacF, JacM;
vector<double> lambda, lambdaMin, lambdaMax;
FGColumnVector3 vdot, wdot;
FGColumnVector3 Fc, Mc;
int n = 0;
// Compiles data from the ground reactions to build up the jacobian matrix
for (MultiplierIterator it=MultiplierIterator(FDMExec->GetGroundReactions()); *it; ++it, n++) {
JacF.push_back((*it)->ForceJacobian);
JacM.push_back((*it)->MomentJacobian);
lambda.push_back((*it)->value);
lambdaMax.push_back((*it)->Max);
lambdaMin.push_back((*it)->Min);
}
// If no gears are in contact with the ground then return
if (!n) return;
vector<double> a(n*n); // Will contain J*M^-1*J^T
vector<double> rhs(n);
// Assemble the linear system of equations
for (int i=0; i < n; i++) {
for (int j=0; j < i; j++)
a[i*n+j] = a[j*n+i]; // Takes advantage of the symmetry of J^T*M^-1*J
for (int j=i; j < n; j++)
a[i*n+j] = DotProduct(JacF[i],invMass*JacF[j])+DotProduct(JacM[i],Jinv*JacM[j]);
}
// Assemble the RHS member
// Translation
EvaluateRateToResistTo(vdot, VState.vUVW, vUVWdot, LocalTerrainVelocity,
VState.dqUVWidot, dt, integrator_translational_rate);
// Rotation
EvaluateRateToResistTo(wdot, VState.vPQR, vPQRdot, LocalTerrainAngularVelocity,
VState.dqPQRidot, dt, integrator_rotational_rate);
// Prepare the linear system for the Gauss-Seidel algorithm :
// 1. Compute the right hand side member 'rhs'
// 2. Divide every line of 'a' and 'rhs' by a[i,i]. This is in order to save
// a division computation at each iteration of Gauss-Seidel.
for (int i=0; i < n; i++) {
double d = 1.0 / a[i*n+i];
rhs[i] = -(DotProduct(JacF[i],vdot)+DotProduct(JacM[i],wdot))*d;
for (int j=0; j < n; j++)
a[i*n+j] *= d;
}
// Resolve the Lagrange multipliers with the projected Gauss-Seidel method
for (int iter=0; iter < 50; iter++) {
double norm = 0.;
for (int i=0; i < n; i++) {
double lambda0 = lambda[i];
double dlambda = rhs[i];
for (int j=0; j < n; j++)
dlambda -= a[i*n+j]*lambda[j];
lambda[i] = Constrain(lambdaMin[i], lambda0+dlambda, lambdaMax[i]);
dlambda = lambda[i] - lambda0;
norm += fabs(dlambda);
}
if (norm < 1E-5) break;
}
// Calculate the total friction forces and moments
Fc.InitMatrix();
Mc.InitMatrix();
for (int i=0; i< n; i++) {
Fc += lambda[i]*JacF[i];
Mc += lambda[i]*JacM[i];
}
vUVWdot += invMass * Fc;
vUVWidot += invMass * Tb2i * Fc;
vPQRdot += Jinv * Mc;
vPQRidot += Jinv * Mc;
// Save the value of the Lagrange multipliers to accelerate the convergence
// of the Gauss-Seidel algorithm at next iteration.
int i = 0;
for (MultiplierIterator it=MultiplierIterator(FDMExec->GetGroundReactions()); *it; ++it)
(*it)->value = lambda[i++];
FDMExec->GetGroundReactions()->UpdateForcesAndMoments();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPropagate::UpdateLocationMatrices(void)
@ -653,31 +405,7 @@ void FGPropagate::SetInertialVelocity(FGColumnVector3 Vi) {
void FGPropagate::SetInertialRates(FGColumnVector3 vRates) {
VState.vPQRi = Ti2b * vRates;
VState.vPQR = VState.vPQRi - Ti2b * vOmegaEarth;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPropagate::InitializeDerivatives(void)
{
// Make an initial run and set past values
CalculatePQRdot(); // Angular rate derivative
CalculateUVWdot(); // Translational rate derivative
ResolveFrictionForces(0.); // Update rate derivatives with friction forces
CalculateQuatdot(); // Angular orientation derivative
CalculateInertialVelocity(); // Translational position derivative
// Initialize past values deques
VState.dqPQRidot.clear();
VState.dqUVWidot.clear();
VState.dqInertialVelocity.clear();
VState.dqQtrndot.clear();
for (int i=0; i<4; i++) {
VState.dqPQRidot.push_front(vPQRidot);
VState.dqUVWidot.push_front(vUVWidot);
VState.dqInertialVelocity.push_front(VState.vInertialVelocity);
VState.dqQtrndot.push_front(vQtrndot);
}
VState.vPQR = VState.vPQRi - Ti2b * in.vOmegaPlanet;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -685,13 +413,14 @@ void FGPropagate::InitializeDerivatives(void)
void FGPropagate::RecomputeLocalTerrainRadius(void)
{
FGLocation contactloc;
FGColumnVector3 dv;
FGColumnVector3 dummy;
double t = FDMExec->GetSimTime();
// Get the LocalTerrain radius.
FDMExec->GetGroundCallback()->GetAGLevel(t, VState.vLocation, contactloc, dv,
LocalTerrainVelocity, LocalTerrainAngularVelocity);
LocalTerrainRadius = contactloc.GetRadius();
FDMExec->GetGroundCallback()->GetAGLevel(t, VState.vLocation, contactloc,
dummy, LocalTerrainVelocity, LocalTerrainAngularVelocity);
LocalTerrainRadius = contactloc.GetRadius();
FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(LocalTerrainRadius);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -720,8 +449,9 @@ double FGPropagate::GetDistanceAGL(void) const
void FGPropagate::SetVState(const VehicleState& vstate)
{
//ToDo: Shouldn't all of these be set from the vstate vector passed in?
VState.vLocation = vstate.vLocation;
VState.vLocation.SetEarthPositionAngle(FDMExec->GetInertial()->GetEarthPositionAngle());
VState.vLocation.SetEarthPositionAngle(vstate.vLocation.GetEPA());
Ti2ec = VState.vLocation.GetTi2ec(); // useless ?
Tec2i = Ti2ec.Transposed();
UpdateLocationMatrices();
@ -731,10 +461,8 @@ void FGPropagate::SetVState(const VehicleState& vstate)
VState.vUVW = vstate.vUVW;
vVel = Tb2l * VState.vUVW;
VState.vPQR = vstate.vPQR;
VState.vPQRi = VState.vPQR + Ti2b * vOmegaEarth;
VState.vPQRi = VState.vPQR + Ti2b * in.vOmegaPlanet;
VState.vInertialPosition = vstate.vInertialPosition;
InitializeDerivatives();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -755,7 +483,7 @@ void FGPropagate::UpdateVehicleState(void)
void FGPropagate::SetLocation(const FGLocation& l)
{
VState.vLocation = l;
VState.vLocation.SetEarthPositionAngle(FDMExec->GetInertial()->GetEarthPositionAngle());
VState.vLocation.SetEarthPositionAngle(l.GetEPA());
Ti2ec = VState.vLocation.GetTi2ec(); // useless ?
Tec2i = Ti2ec.Transposed();
UpdateVehicleState();
@ -822,20 +550,12 @@ void FGPropagate::bind(void)
PropertyManager->Tie("velocities/eci-velocity-mag-fps", this, &FGPropagate::GetInertialVelocityMagnitude);
PropertyManager->Tie("accelerations/pdot-rad_sec2", this, eP, (PMF)&FGPropagate::GetPQRdot);
PropertyManager->Tie("accelerations/qdot-rad_sec2", this, eQ, (PMF)&FGPropagate::GetPQRdot);
PropertyManager->Tie("accelerations/rdot-rad_sec2", this, eR, (PMF)&FGPropagate::GetPQRdot);
PropertyManager->Tie("accelerations/udot-ft_sec2", this, eU, (PMF)&FGPropagate::GetUVWdot);
PropertyManager->Tie("accelerations/vdot-ft_sec2", this, eV, (PMF)&FGPropagate::GetUVWdot);
PropertyManager->Tie("accelerations/wdot-ft_sec2", this, eW, (PMF)&FGPropagate::GetUVWdot);
PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::GetAltitudeASL, &FGPropagate::SetAltitudeASL, true);
PropertyManager->Tie("position/h-sl-meters", this, &FGPropagate::GetAltitudeASLmeters, &FGPropagate::SetAltitudeASLmeters, true);
PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude);
PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude);
PropertyManager->Tie("position/lat-gc-deg", this, &FGPropagate::GetLatitudeDeg, &FGPropagate::SetLatitudeDeg);
PropertyManager->Tie("position/long-gc-deg", this, &FGPropagate::GetLongitudeDeg, &FGPropagate::SetLongitudeDeg);
PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude, false);
PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude, false);
PropertyManager->Tie("position/lat-gc-deg", this, &FGPropagate::GetLatitudeDeg, &FGPropagate::SetLatitudeDeg, false);
PropertyManager->Tie("position/long-gc-deg", this, &FGPropagate::GetLongitudeDeg, &FGPropagate::SetLongitudeDeg, false);
PropertyManager->Tie("position/lat-geod-rad", this, &FGPropagate::GetGeodLatitudeRad);
PropertyManager->Tie("position/lat-geod-deg", this, &FGPropagate::GetGeodLatitudeDeg);
PropertyManager->Tie("position/geod-alt-ft", this, &FGPropagate::GetGeodeticAltitude);
@ -845,6 +565,7 @@ void FGPropagate::bind(void)
&FGPropagate::GetTerrainElevation,
&FGPropagate::SetTerrainElevation, false);
PropertyManager->Tie("position/epa-rad", this, &FGPropagate::GetEarthPositionAngle);
PropertyManager->Tie("metrics/terrain-radius", this, &FGPropagate::GetLocalTerrainRadius);
PropertyManager->Tie("attitude/phi-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
@ -859,7 +580,6 @@ void FGPropagate::bind(void)
PropertyManager->Tie("simulation/integrator/rate/translational", (int*)&integrator_translational_rate);
PropertyManager->Tie("simulation/integrator/position/rotational", (int*)&integrator_rotational_position);
PropertyManager->Tie("simulation/integrator/position/translational", (int*)&integrator_translational_position);
PropertyManager->Tie("simulation/gravity-model", &gravType);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -902,7 +622,7 @@ void FGPropagate::Debug(int from)
<< reset << endl;
cout << endl;
cout << highint << " Earth Position Angle (deg): " << setw(8) << setprecision(3) << reset
<< FDMExec->GetInertial()->GetEarthPositionAngleDeg() << endl;
<< GetEarthPositionAngleDeg() << endl;
cout << endl;
cout << highint << " Body velocity (ft/sec): " << setw(8) << setprecision(3) << reset << VState.vUVW << endl;
cout << highint << " Local velocity (ft/sec): " << setw(8) << setprecision(3) << reset << vVel << endl;
@ -911,7 +631,7 @@ void FGPropagate::Debug(int from)
cout << highint << " Latitude (deg): " << setw(8) << setprecision(3) << reset << VState.vLocation.GetLatitudeDeg() << endl;
cout << highint << " Longitude (deg): " << setw(8) << setprecision(3) << reset << VState.vLocation.GetLongitudeDeg() << endl;
cout << highint << " Altitude ASL (ft): " << setw(8) << setprecision(3) << reset << GetAltitudeASL() << endl;
cout << highint << " Acceleration (NED, ft/sec^2): " << setw(8) << setprecision(3) << reset << Tb2l*GetUVWdot() << endl;
// cout << highint << " Acceleration (NED, ft/sec^2): " << setw(8) << setprecision(3) << reset << Tb2l*GetUVWdot() << endl;
cout << endl;
cout << highint << " Matrix ECEF to Body (Orientation of Body with respect to ECEF): "
<< reset << endl << Tec2b.Dump("\t", " ") << endl;

View file

@ -49,7 +49,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_PROPAGATE "$Id: FGPropagate.h,v 1.59 2011/05/20 03:18:36 jberndt Exp $"
#define ID_PROPAGATE "$Id: FGPropagate.h,v 1.63 2011/08/21 15:35:39 bcoconni Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -69,15 +69,6 @@ CLASS DOCUMENTATION
state of the vehicle given the forces and moments that act on it. The
integration accounts for a rotating Earth.
The general execution of this model follows this process:
-Calculate the angular accelerations
-Calculate the translational accelerations
-Calculate the angular rate
-Calculate the translational velocity
-Integrate accelerations and rates
Integration of rotational and translation position and rate can be
customized as needed or frozen by the selection of no integrator. The
selection of which integrator to use is done through the setting of
@ -101,8 +92,8 @@ CLASS DOCUMENTATION
5: Adams Bashforth 4
@endcode
@author Jon S. Berndt, Mathias Froehlich
@version $Id: FGPropagate.h,v 1.59 2011/05/20 03:18:36 jberndt Exp $
@author Jon S. Berndt, Mathias Froehlich, Bertrand Coconnier
@version $Id: FGPropagate.h,v 1.63 2011/08/21 15:35:39 bcoconni Exp $
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -169,14 +160,13 @@ public:
/// These define the indices use to select the various integrators.
enum eIntegrateType {eNone = 0, eRectEuler, eTrapezoidal, eAdamsBashforth2, eAdamsBashforth3, eAdamsBashforth4};
/// These define the indices use to select the gravitation models.
enum eGravType {gtStandard, gtWGS84};
/** Initializes the FGPropagate class after instantiation and prior to first execution.
The base class FGModel::InitModel is called first, initializing pointers to the
other FGModel objects (and others). */
bool InitModel(void);
void InitializeDerivatives();
/** Runs the state propagation model; called by the Executive
Can pass in a value indicating if the executive is directing the simulation to Hold.
@param Holding if true, the executive has been directed to hold the sim from
@ -186,8 +176,6 @@ public:
@return false if no error */
bool Run(bool Holding);
const FGQuaternion& GetQuaterniondot(void) const {return vQtrndot;}
/** Retrieves the velocity vector.
The vector returned is represented by an FGColumnVector reference. The vector
for the velocity in Local frame is organized (Vnorth, Veast, Vdown). The vector
@ -213,20 +201,6 @@ public:
*/
const FGColumnVector3& GetUVW(void) const { return VState.vUVW; }
/** Retrieves the body axis acceleration.
Retrieves the computed body axis accelerations based on the
applied forces and accounting for a rotating body frame.
The vector returned is represented by an FGColumnVector reference. The vector
for the acceleration in Body frame is organized (Ax, Ay, Az). The vector
is 1-based, so that the first element can be retrieved using the "()" operator.
In other words, vUVWdot(1) is Ax. Various convenience enumerators are defined
in FGJSBBase. The relevant enumerators for the vector returned by this call are,
eX=1, eY=2, eZ=3.
units ft/sec^2
@return Body axis translational acceleration in ft/sec^2.
*/
const FGColumnVector3& GetUVWdot(void) const { return vUVWdot; }
/** Retrieves the body angular rates vector, relative to the ECEF frame.
Retrieves the body angular rates (p, q, r), which are calculated by integration
of the angular acceleration.
@ -255,21 +229,6 @@ public:
*/
const FGColumnVector3& GetPQRi(void) const {return VState.vPQRi;}
/** Retrieves the body axis angular acceleration vector.
Retrieves the body axis angular acceleration vector in rad/sec^2. The
angular acceleration vector is determined from the applied forces and
accounts for a rotating frame.
The vector returned is represented by an FGColumnVector reference. The vector
for the angular acceleration in Body frame is organized (Pdot, Qdot, Rdot). The vector
is 1-based, so that the first element can be retrieved using the "()" operator.
In other words, vPQRdot(1) is Pdot. Various convenience enumerators are defined
in FGJSBBase. The relevant enumerators for the vector returned by this call are,
eP=1, eQ=2, eR=3.
units rad/sec^2
@return The angular acceleration vector.
*/
const FGColumnVector3& GetPQRdot(void) const {return vPQRdot;}
/** Retrieves the Euler angles that define the vehicle orientation.
Extracts the Euler angles from the quaternion that stores the orientation
in the Local frame. The order of rotation used is Yaw-Pitch-Roll. The
@ -300,19 +259,6 @@ public:
*/
double GetUVW (int idx) const { return VState.vUVW(idx); }
/** Retrieves a body frame acceleration component.
Retrieves a body frame acceleration component. The acceleration returned
is extracted from the vUVWdot vector (an FGColumnVector). The vector for
the acceleration in Body frame is organized (Ax, Ay, Az). The vector is
1-based. In other words, GetUVWdot(1) returns Ax. Various convenience
enumerators are defined in FGJSBBase. The relevant enumerators for the
acceleration returned by this call are, eX=1, eY=2, eZ=3.
units ft/sec^2
@param idx the index of the acceleration component desired (1-based).
@return The body frame acceleration component.
*/
double GetUVWdot(int idx) const { return vUVWdot(idx); }
/** Retrieves a Local frame velocity component.
Retrieves a Local frame velocity component. The velocity returned is
extracted from the vVel vector (an FGColumnVector). The vector for the
@ -382,20 +328,6 @@ public:
*/
double GetPQRi(int axis) const {return VState.vPQRi(axis);}
/** Retrieves a body frame angular acceleration component.
Retrieves a body frame angular acceleration component. The angular
acceleration returned is extracted from the vPQRdot vector (an
FGColumnVector). The vector for the angular acceleration in Body frame
is organized (Pdot, Qdot, Rdot). The vector is 1-based. In other words,
GetPQRdot(1) returns Pdot (roll acceleration). Various convenience
enumerators are defined in FGJSBBase. The relevant enumerators for the
angular acceleration returned by this call are, eP=1, eQ=2, eR=3.
units rad/sec^2
@param axis the index of the angular acceleration component desired (1-based).
@return The body frame angular acceleration component.
*/
double GetPQRdot(int axis) const {return vPQRdot(axis);}
/** Retrieves a vehicle Euler angle component.
Retrieves an Euler angle (Phi, Theta, or Psi) from the quaternion that
stores the vehicle orientation relative to the Local frame. The order of
@ -447,7 +379,12 @@ public:
*/
double GetLocalTerrainRadius(void) const { return LocalTerrainRadius; }
double GetSeaLevelRadius(void) const { return SeaLevelRadius; }
double GetEarthPositionAngle(void) const { return VState.vLocation.GetEPA(); }
double GetEarthPositionAngleDeg(void) const { return GetEarthPositionAngle()*radtodeg;}
const FGColumnVector3& GetTerrainVelocity(void) const { return LocalTerrainVelocity; }
const FGColumnVector3& GetTerrainAngularVelocity(void) const { return LocalTerrainAngularVelocity; }
double GetTerrainElevation(void) const;
double GetDistanceAGL(void) const;
double GetRadius(void) const {
@ -526,13 +463,14 @@ public:
void SetVState(const VehicleState& vstate);
void InitializeDerivatives(void);
void SetEarthPositionAngle(double epa) {VState.vLocation.SetEarthPositionAngle(epa);}
void SetInertialOrientation(FGQuaternion Qi);
void SetInertialVelocity(FGColumnVector3 Vi);
void SetInertialRates(FGColumnVector3 vRates);
const FGQuaternion GetQuaternion(void) const { return VState.qAttitudeLocal; }
const FGQuaternion GetQuaternionECI(void) const { return VState.qAttitudeECI; }
void SetPQR(unsigned int i, double val) {
if ((i>=1) && (i<=3) )
@ -589,16 +527,19 @@ public:
VState.vLocation -= Tb2ec*deltaLoc;
}
struct LagrangeMultiplier {
FGColumnVector3 ForceJacobian;
FGColumnVector3 MomentJacobian;
double Min;
double Max;
double value;
};
void DumpState(void);
struct Inputs {
FGColumnVector3 vPQRidot;
FGQuaternion vQtrndot;
FGColumnVector3 vUVWidot;
FGColumnVector3 vOmegaPlanet;
double RefRadius;
double SemiMajor;
double SemiMinor;
double DeltaT;
} in;
private:
// state vector
@ -606,14 +547,9 @@ private:
struct VehicleState VState;
FGColumnVector3 vVel;
FGColumnVector3 vPQRdot, vPQRidot;
FGColumnVector3 vUVWdot, vUVWidot;
FGColumnVector3 vInertialVelocity;
FGColumnVector3 vLocation;
FGColumnVector3 vDeltaXYZEC;
FGColumnVector3 vGravAccel;
FGColumnVector3 vOmegaEarth; // The Earth angular velocity vector
FGQuaternion vQtrndot;
FGMatrix33 Tec2b;
FGMatrix33 Tb2ec;
FGMatrix33 Tl2b; // local to body frame matrix copy for immediate local use
@ -633,13 +569,9 @@ private:
eIntegrateType integrator_translational_rate;
eIntegrateType integrator_rotational_position;
eIntegrateType integrator_translational_position;
int gravType;
void CalculatePQRdot(void);
void CalculateQuatdot(void);
void CalculateInertialVelocity(void);
void CalculateUVW(void);
void CalculateUVWdot(void);
void Integrate( FGColumnVector3& Integrand,
FGColumnVector3& Val,
@ -653,16 +585,6 @@ private:
double dt,
eIntegrateType integration_type);
void EvaluateRateToResistTo(FGColumnVector3& vdot,
const FGColumnVector3& Val,
const FGColumnVector3& ValDot,
const FGColumnVector3& LocalTerrainVal,
deque <FGColumnVector3>& dqValDot,
const double dt,
const eIntegrateType integration_type);
void ResolveFrictionForces(double dt);
void UpdateLocationMatrices(void);
void UpdateBodyMatrices(void);
void UpdateVehicleState(void);

View file

@ -44,10 +44,14 @@ HISTORY
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <iomanip>
#include "FGFDMExec.h"
#include "FGPropulsion.h"
#include "models/FGFCS.h"
#include "models/FGMassBalance.h"
#include "models/propulsion/FGThruster.h"
#include "models/propulsion/FGRocket.h"
#include "models/propulsion/FGTurbine.h"
#include "models/propulsion/FGPiston.h"
@ -57,15 +61,12 @@ INCLUDES
#include "input_output/FGPropertyManager.h"
#include "input_output/FGXMLParse.h"
#include "math/FGColumnVector3.h"
#include <iostream>
#include <sstream>
#include <cstdlib>
using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGPropulsion.cpp,v 1.46 2011/05/20 03:18:36 jberndt Exp $";
static const char *IdSrc = "$Id: FGPropulsion.cpp,v 1.51 2011/09/11 11:36:04 bcoconni Exp $";
static const char *IdHdr = ID_PROPULSION;
extern short debug_lvl;
@ -87,7 +88,7 @@ FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
tankJ.InitMatrix();
refuel = dump = false;
DumpRate = 0.0;
fuel_freeze = false;
FuelFreeze = false;
TotalFuelQuantity = 0.0;
IsBound =
HavePistonEngine =
@ -158,33 +159,132 @@ bool FGPropulsion::Run(bool Holding)
RunPreFunctions();
double dt = FDMExec->GetDeltaT();
vForces.InitMatrix();
vMoments.InitMatrix();
for (i=0; i<numEngines; i++) {
Engines[i]->Calculate();
ConsumeFuel(Engines[i]);
vForces += Engines[i]->GetBodyForces(); // sum body frame forces
vMoments += Engines[i]->GetMoments(); // sum body frame moments
}
TotalFuelQuantity = 0.0;
for (i=0; i<numTanks; i++) {
Tanks[i]->Calculate( dt * rate );
Tanks[i]->Calculate( in.TotalDeltaT, in.TAT_c);
if (Tanks[i]->GetType() == FGTank::ttFUEL) {
TotalFuelQuantity += Tanks[i]->GetContents();
}
}
if (refuel) DoRefuel( dt * rate );
if (dump) DumpFuel( dt * rate );
if (refuel) DoRefuel( in.TotalDeltaT );
if (dump) DumpFuel( in.TotalDeltaT );
RunPostFunctions();
return false;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// The engine can tell us how much fuel it needs, but it is up to the propulsion
// subsystem manager class FGPropulsion to manage fuel flow amongst tanks. Engines
// May burn fuel from more than one tank at a time, and may burn from one tank
// before another - that is, may burn from one tank until the tank is depleted,
// then burn from the next highest priority tank. This can be accompished
// by defining a fuel management system, but this way of specifying priorities
// is more automatic from a user perspective.
void FGPropulsion::ConsumeFuel(FGEngine* engine)
{
if (FuelFreeze) return;
if (FDMExec->GetTrimStatus()) return;
unsigned int TanksWithFuel=0, CurrentFuelTankPriority=1;
unsigned int TanksWithOxidizer=0, CurrentOxidizerTankPriority=1;
vector <int> FeedListFuel, FeedListOxi;
bool Starved = true; // Initially set Starved to true. Set to false in code below.
// bool hasOxTanks = false;
// For this engine,
// 1) Count how many fuel tanks with the current priority level have fuel
// 2) If there none, then try next lower priority (higher number) - that is,
// increment CurrentPriority.
// 3) Build the feed list.
// 4) Do the same for oxidizer tanks, if needed.
// Process fuel tanks, if any
while ((TanksWithFuel == 0) && (CurrentFuelTankPriority <= numTanks)) {
for (unsigned int i=0; i<engine->GetNumSourceTanks(); i++) {
unsigned int TankId = engine->GetSourceTank(i);
FGTank* Tank = Tanks[TankId];
unsigned int TankPriority = Tank->GetPriority();
if (TankPriority != 0) {
switch(Tank->GetType()) {
case FGTank::ttFUEL:
if ((Tank->GetContents() > 0.0) && Tank->GetSelected() && (TankPriority == CurrentFuelTankPriority)) {
TanksWithFuel++;
Starved = false;
FeedListFuel.push_back(TankId);
}
break;
case FGTank::ttOXIDIZER:
// Skip this here (done below)
break;
}
}
}
if (TanksWithFuel == 0) CurrentFuelTankPriority++; // No tanks at this priority, try next priority
}
// Process Oxidizer tanks, if any
if (engine->GetType() == FGEngine::etRocket) {
while ((TanksWithOxidizer == 0) && (CurrentOxidizerTankPriority <= numTanks)) {
for (unsigned int i=0; i<engine->GetNumSourceTanks(); i++) {
unsigned int TankId = engine->GetSourceTank(i);
FGTank* Tank = Tanks[TankId];
unsigned int TankPriority = Tank->GetPriority();
if (TankPriority != 0) {
switch(Tank->GetType()) {
case FGTank::ttFUEL:
// Skip this here (done above)
break;
case FGTank::ttOXIDIZER:
// hasOxTanks = true;
if (Tank->GetContents() > 0.0 && Tank->GetSelected() && TankPriority == CurrentOxidizerTankPriority) {
TanksWithOxidizer++;
if (TanksWithFuel > 0) Starved = false;
FeedListOxi.push_back(TankId);
}
break;
}
}
}
if (TanksWithOxidizer == 0) CurrentOxidizerTankPriority++; // No tanks at this priority, try next priority
}
}
engine->SetStarved(Starved); // Tanks can be refilled, so be sure to reset engine Starved flag here.
// No fuel or fuel/oxidizer found at any priority!
if (Starved) return;
double FuelToBurn = engine->CalcFuelNeed(); // How much fuel does this engine need?
double FuelNeededPerTank = FuelToBurn / TanksWithFuel; // Determine fuel needed per tank.
for (unsigned int i=0; i<FeedListFuel.size(); i++) {
Tanks[FeedListFuel[i]]->Drain(FuelNeededPerTank);
}
if (engine->GetType() == FGEngine::etRocket) {
double OxidizerToBurn = engine->CalcOxidizerNeed(); // How much fuel does this engine need?
double OxidizerNeededPerTank = OxidizerToBurn / TanksWithOxidizer; // Determine fuel needed per tank.
for (unsigned int i=0; i<FeedListOxi.size(); i++) {
Tanks[FeedListOxi[i]]->Drain(OxidizerNeededPerTank);
}
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGPropulsion::GetSteadyState(void)
@ -201,28 +301,23 @@ bool FGPropulsion::GetSteadyState(void)
FDMExec->SetTrimStatus(true);
for (unsigned int i=0; i<numEngines; i++) {
// cout << " Finding steady state for engine " << i << endl;
steady=false;
steady_count=0;
j=0;
while (!steady && j < 6000) {
Engines[i]->Calculate();
lastThrust = currentThrust;
currentThrust = Engines[i]->GetThruster()->GetThrust();
currentThrust = Engines[i]->GetThrust();
if (fabs(lastThrust-currentThrust) < 0.0001) {
steady_count++;
if (steady_count > 120) {
steady=true;
// cout << " Steady state found at thrust: " << currentThrust << " lbs." << endl;
}
} else {
steady_count=0;
}
j++;
}
// if (j >= 6000) {
// cout << " Could not find a steady state for this engine." << endl;
// }
vForces += Engines[i]->GetBodyForces(); // sum body frame forces
vMoments += Engines[i]->GetMoments(); // sum body frame moments
}
@ -244,8 +339,10 @@ void FGPropulsion::InitRunning(int n)
if (n >= (int)GetNumEngines() ) {
throw(string("Tried to initialize a non-existent engine!"));
}
FDMExec->GetFCS()->SetThrottleCmd(n,1);
FDMExec->GetFCS()->SetMixtureCmd(n,1);
in.ThrottleCmd[n] = in.ThrottlePos[n] = 1; // Set the throttle command and position
in.MixtureCmd[n] = in.MixturePos[n] = 1; // Set the mixture command and position
GetEngine(n)->InitRunning();
GetSteadyState();
@ -255,14 +352,14 @@ void FGPropulsion::InitRunning(int n)
} else if (n < 0) { // -1 refers to "All Engines"
for (unsigned int i=0; i<GetNumEngines(); i++) {
FDMExec->GetFCS()->SetThrottleCmd(i,1);
FDMExec->GetFCS()->SetMixtureCmd(i,1);
in.ThrottleCmd[i] = in.ThrottlePos[i] = 1; // Set the throttle command and position
in.MixtureCmd[i] = in.MixturePos[i] = 1; // Set the mixture command and position
GetEngine(i)->InitRunning();
}
GetSteadyState();
InitializedEngines = -1;
HasInitializedEngines = true;
}
}
@ -271,7 +368,6 @@ void FGPropulsion::InitRunning(int n)
bool FGPropulsion::Load(Element* el)
{
string type, engine_filename;
bool ThrottleAdded = false;
Debug(2);
@ -301,6 +397,11 @@ bool FGPropulsion::Load(Element* el)
}
engine_filename = FindEngineFullPathname(engine_filename);
if (engine_filename.empty()) {
// error message already printed by FindEngineFullPathname()
return false;
}
document = LoadXMLDocument(engine_filename);
document->SetParent(engine_element);
@ -309,23 +410,23 @@ bool FGPropulsion::Load(Element* el)
if (type == "piston_engine") {
HavePistonEngine = true;
if (!IsBound) bind();
Engines.push_back(new FGPiston(FDMExec, document, numEngines));
Engines.push_back(new FGPiston(FDMExec, document, numEngines, in));
} else if (type == "turbine_engine") {
HaveTurbineEngine = true;
if (!IsBound) bind();
Engines.push_back(new FGTurbine(FDMExec, document, numEngines));
Engines.push_back(new FGTurbine(FDMExec, document, numEngines, in));
} else if (type == "turboprop_engine") {
HaveTurboPropEngine = true;
if (!IsBound) bind();
Engines.push_back(new FGTurboProp(FDMExec, document, numEngines));
Engines.push_back(new FGTurboProp(FDMExec, document, numEngines, in));
} else if (type == "rocket_engine") {
HaveRocketEngine = true;
if (!IsBound) bind();
Engines.push_back(new FGRocket(FDMExec, document, numEngines));
Engines.push_back(new FGRocket(FDMExec, document, numEngines, in));
} else if (type == "electric_engine") {
HaveElectricEngine = true;
if (!IsBound) bind();
Engines.push_back(new FGElectric(FDMExec, document, numEngines));
Engines.push_back(new FGElectric(FDMExec, document, numEngines, in));
} else {
cerr << "Unknown engine type: " << type << endl;
exit(-5);
@ -335,9 +436,6 @@ bool FGPropulsion::Load(Element* el)
return false;
}
FDMExec->GetFCS()->AddThrottle();
ThrottleAdded = true;
numEngines++;
engine_element = el->FindNextElement("engine");
@ -345,7 +443,6 @@ bool FGPropulsion::Load(Element* el)
}
CalculateTankInertias();
if (!ThrottleAdded) FDMExec->GetFCS()->AddThrottle(); // need to have at least one throttle
// Process fuel dump rate
if (el->FindElement("dump-rate"))
@ -459,6 +556,34 @@ string FGPropulsion::GetPropulsionValues(const string& delimiter) const
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGPropulsion::GetPropulsionTankReport()
{
string out="";
stringstream outstream;
for (unsigned int i=0; i<numTanks; i++)
{
FGTank* tank = Tanks[i];
string tankname="";
if (tank->GetType() == FGTank::ttFUEL && tank->GetGrainType() != FGTank::gtUNKNOWN) {
tankname = "Solid Fuel";
} else if (tank->GetType() == FGTank::ttFUEL) {
tankname = "Fuel";
} else if (tank->GetType() == FGTank::ttOXIDIZER) {
tankname = "Oxidizer";
} else {
tankname = "(Unknown tank type)";
}
outstream << highint << left << setw(4) << i << setw(30) << tankname << normint
<< right << setw(10) << tank->GetContents() << setw(8) << tank->GetXYZ(eX)
<< setw(8) << tank->GetXYZ(eY) << setw(8) << tank->GetXYZ(eZ)
<< setw(12) << "*" << setw(12) << "*"
<< setw(12) << "*" << endl;
}
return outstream.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector3& FGPropulsion::GetTanksMoment(void)
{
vXYZtank_arm.InitMatrix();
@ -633,7 +758,7 @@ void FGPropulsion::DumpFuel(double time_slice)
void FGPropulsion::SetFuelFreeze(bool f)
{
fuel_freeze = f;
FuelFreeze = f;
for (unsigned int i=0; i<numEngines; i++) {
Engines[i]->SetFuelFreeze(f);
}

View file

@ -42,6 +42,7 @@ INCLUDES
#include <iosfwd>
#include "FGModel.h"
#include "propulsion/FGEngine.h"
#include "math/FGMatrix33.h"
#include "input_output/FGXMLFileRead.h"
@ -49,7 +50,7 @@ INCLUDES
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_PROPULSION "$Id: FGPropulsion.h,v 1.27 2011/05/20 03:18:36 jberndt Exp $"
#define ID_PROPULSION "$Id: FGPropulsion.h,v 1.30 2011/08/03 03:21:06 jberndt Exp $"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
@ -91,7 +92,7 @@ CLASS DOCUMENTATION
@endcode
@author Jon S. Berndt
@version $Id: FGPropulsion.h,v 1.27 2011/05/20 03:18:36 jberndt Exp $
@version $Id: FGPropulsion.h,v 1.30 2011/08/03 03:21:06 jberndt Exp $
@see
FGEngine
FGTank
@ -164,6 +165,7 @@ public:
std::string GetPropulsionStrings(const std::string& delimiter) const;
std::string GetPropulsionValues(const std::string& delimiter) const;
std::string GetPropulsionTankReport();
const FGColumnVector3& GetForces(void) const {return vForces; }
double GetForces(int n) const { return vForces(n);}
@ -184,7 +186,7 @@ public:
std::ifstream* FindEngineFile(const std::string& filename);
std::string FindEngineFullPathname(const std::string& engine_filename);
inline int GetActiveEngine(void) const {return ActiveEngine;}
inline bool GetFuelFreeze(void) {return fuel_freeze;}
inline bool GetFuelFreeze(void) {return FuelFreeze;}
double GetTotalFuelQuantity(void) const {return TotalFuelQuantity;}
void SetMagnetos(int setting);
@ -194,6 +196,8 @@ public:
void SetFuelFreeze(bool f);
FGMatrix33& CalculateTankInertias(void);
struct FGEngine::Inputs in;
private:
std::vector <FGEngine*> Engines;
std::vector <FGTank*> Tanks;
@ -211,7 +215,7 @@ private:
FGMatrix33 tankJ;
bool refuel;
bool dump;
bool fuel_freeze;
bool FuelFreeze;
double TotalFuelQuantity;
double DumpRate;
bool IsBound;
@ -220,6 +224,7 @@ private:
bool HaveTurboPropEngine;
bool HaveRocketEngine;
bool HaveElectricEngine;
void ConsumeFuel(FGEngine* engine);
int InitializedEngines;
bool HasInitializedEngines;

View file

@ -7,12 +7,12 @@ libModels_a_SOURCES = FGAerodynamics.cpp FGAircraft.cpp FGAtmosphere.cpp \
FGInertial.cpp FGBuoyantForces.cpp FGExternalForce.cpp \
FGLGear.cpp FGMassBalance.cpp FGModel.cpp FGOutput.cpp \
FGPropagate.cpp FGPropulsion.cpp FGInput.cpp \
FGExternalReactions.cpp FGGasCell.cpp
FGExternalReactions.cpp FGGasCell.cpp FGAccelerations.cpp
noinst_HEADERS = FGAerodynamics.h FGAircraft.h FGAtmosphere.h FGAuxiliary.h \
FGFCS.h FGGroundReactions.h FGInertial.h FGLGear.h \
FGMassBalance.h FGBuoyantForces.h FGExternalForce.h \
FGModel.h FGOutput.h FGPropagate.h FGPropulsion.h FGInput.h \
FGExternalReactions.h FGGasCell.h
FGExternalReactions.h FGGasCell.h FGAccelerations.h
INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim

44
src/FDM/JSBSim/models/atmosphere/FGMSIS.cpp Executable file → Normal file
View file

@ -66,7 +66,7 @@ using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id: FGMSIS.cpp,v 1.17 2011/05/20 03:18:36 jberndt Exp $";
static const char *IdSrc = "$Id: FGMSIS.cpp,v 1.18 2011/06/21 13:54:40 jberndt Exp $";
static const char *IdHdr = ID_MSIS;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -140,16 +140,16 @@ bool MSIS::InitModel(void)
input.f107 = 150.0;
input.ap = 4.0;
UseInternal();
// UseInternal();
SLtemperature = intTemperature = 518.0;
SLpressure = intPressure = 2116.7;
SLdensity = intDensity = 0.002378;
SLsoundspeed = sqrt(2403.0832 * SLtemperature);
rSLtemperature = 1.0/intTemperature;
rSLpressure = 1.0/intPressure;
rSLdensity = 1.0/intDensity;
rSLsoundspeed = 1.0/SLsoundspeed;
// SLtemperature = intTemperature = 518.0;
// SLpressure = intPressure = 2116.7;
// SLdensity = intDensity = 0.002378;
// SLsoundspeed = sqrt(2403.0832 * SLtemperature);
// rSLtemperature = 1.0/intTemperature;
// rSLpressure = 1.0/intPressure;
// rSLdensity = 1.0/intDensity;
// rSLsoundspeed = 1.0/SLsoundspeed;
return true;
}
@ -163,10 +163,10 @@ bool MSIS::Run(bool Holding)
RunPreFunctions();
h = FDMExec->GetPropagate()->GetAltitudeASL();
double h = FDMExec->GetPropagate()->GetAltitudeASL();
//do temp, pressure, and density first
if (!useExternal) {
// if (!useExternal) {
// get sea-level values
Calculate(FDMExec->GetAuxiliary()->GetDayOfYear(),
FDMExec->GetAuxiliary()->GetSecondsInDay(),
@ -188,14 +188,12 @@ bool MSIS::Run(bool Holding)
h,
FDMExec->GetPropagate()->GetLocation().GetLatitudeDeg(),
FDMExec->GetPropagate()->GetLocation().GetLongitudeDeg());
intTemperature = output.t[1] * 1.8;
intDensity = output.d[5] * 1.940321;
intPressure = 1716.488 * intDensity * intTemperature;
// intTemperature = output.t[1] * 1.8;
// intDensity = output.d[5] * 1.940321;
// intPressure = 1716.488 * intDensity * intTemperature;
//cout << "T=" << intTemperature << " D=" << intDensity << " P=";
//cout << intPressure << " a=" << soundspeed << endl;
}
CalculateDerived();
// }
RunPostFunctions();
@ -1660,16 +1658,6 @@ void MSIS::Debug(int from)
if (debug_lvl & 16) { // Sanity checking
}
if (debug_lvl & 32) { // Turbulence
if (first_pass && from == 2) {
cout << "vTurbulenceNED(X), vTurbulenceNED(Y), vTurbulenceNED(Z), "
<< "vTurbulenceGrad(X), vTurbulenceGrad(Y), vTurbulenceGrad(Z), "
<< "vDirection(X), vDirection(Y), vDirection(Z), "
<< "Magnitude, "
<< "vTurbPQR(P), vTurbPQR(Q), vTurbPQR(R), " << endl;
}
if (from == 2) {
cout << vTurbulenceNED << ", " << vTurbulenceGrad << ", " << vDirection << ", " << Magnitude << ", " << vTurbPQR << endl;
}
}
if (debug_lvl & 64) {
if (from == 0) { // Constructor

0
src/FDM/JSBSim/models/atmosphere/FGMSIS.h Executable file → Normal file
View file

Some files were not shown because too many files have changed in this diff Show more