Merge branch 'next' into comm-subsystem
Conflicts: src/ATC/trafficcontrol.cxx src/ATC/trafficcontrol.hxx src/Instrumentation/CMakeLists.txt
This commit is contained in:
commit
312447c565
210 changed files with 10719 additions and 5866 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -22,4 +22,5 @@ CPackConfig.cmake
|
|||
CPackSourceConfig.cmake
|
||||
cmake_uninstall.cmake
|
||||
CTestTestfile.cmake
|
||||
|
||||
.kdev4
|
||||
*.kdev4
|
||||
|
|
120
CMakeLists.txt
120
CMakeLists.txt
|
@ -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} )
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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!"
|
||||
|
|
153
package/Win-NSIS/flightgear-nightly-vs2010.nsi
Normal file
153
package/Win-NSIS/flightgear-nightly-vs2010.nsi
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -71,7 +71,6 @@ bool FGAIWaypoint::contains(string target) {
|
|||
|
||||
FGAIFlightPlan::FGAIFlightPlan()
|
||||
{
|
||||
rwy = 0;
|
||||
sid = 0;
|
||||
repeat = false;
|
||||
distance_to_go = 0;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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_
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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_
|
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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
|
||||
|
|
544
src/Aircraft/flightrecorder.cxx
Normal file
544
src/Aircraft/flightrecorder.cxx
Normal 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))));
|
||||
}
|
||||
}
|
||||
}
|
89
src/Aircraft/flightrecorder.hxx
Normal file
89
src/Aircraft/flightrecorder.hxx
Normal 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_ */
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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
0
src/FDM/JSBSim/input_output/FGPropertyManager.cpp
Executable file → Normal file
18
src/FDM/JSBSim/input_output/FGScript.cpp
Executable file → Normal file
18
src/FDM/JSBSim/input_output/FGScript.cpp
Executable file → Normal 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:
|
||||
|
|
|
@ -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 "run" section, where the conditions are
|
||||
described in "event" 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
6
src/FDM/JSBSim/input_output/FGXMLElement.cpp
Executable file → Normal 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
412
src/FDM/JSBSim/math/FGFunction.cpp
Executable file → Normal 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;
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
0
src/FDM/JSBSim/math/FGParameter.h
Executable file → Normal file
0
src/FDM/JSBSim/math/FGPropertyValue.cpp
Executable file → Normal file
0
src/FDM/JSBSim/math/FGPropertyValue.cpp
Executable file → Normal file
0
src/FDM/JSBSim/math/FGPropertyValue.h
Executable file → Normal file
0
src/FDM/JSBSim/math/FGPropertyValue.h
Executable file → Normal 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
|
|
@ -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
|
||||
|
|
397
src/FDM/JSBSim/models/FGAccelerations.cpp
Normal file
397
src/FDM/JSBSim/models/FGAccelerations.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
230
src/FDM/JSBSim/models/FGAccelerations.h
Normal file
230
src/FDM/JSBSim/models/FGAccelerations.h
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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. 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
313
src/FDM/JSBSim/models/FGAuxiliary.cpp
Executable file → Normal 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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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
27
src/FDM/JSBSim/models/FGExternalReactions.cpp
Executable file → Normal 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
9
src/FDM/JSBSim/models/FGExternalReactions.h
Executable file → Normal 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);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -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
0
src/FDM/JSBSim/models/FGInput.cpp
Executable file → Normal file
0
src/FDM/JSBSim/models/FGInput.h
Executable file → Normal file
0
src/FDM/JSBSim/models/FGInput.h
Executable file → Normal 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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
44
src/FDM/JSBSim/models/atmosphere/FGMSIS.cpp
Executable file → Normal 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
0
src/FDM/JSBSim/models/atmosphere/FGMSIS.h
Executable file → Normal file
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue