UNit-tests for the NavRadio
Still needs ILS and GS tests, but starting to be useful already.
This commit is contained in:
parent
1e636ce4cf
commit
c7b28a1960
9 changed files with 335 additions and 6 deletions
src/Sound
test_suite
FGTestApi
unit_tests
|
@ -37,22 +37,29 @@ AudioIdent::AudioIdent( const std::string & fx_name, const double interval_secs,
|
|||
|
||||
void AudioIdent::init()
|
||||
{
|
||||
auto soundManager = globals->get_subsystem<SGSoundMgr>();
|
||||
if (!soundManager)
|
||||
return; // sound disabled
|
||||
|
||||
_timer = 0.0;
|
||||
_ident = "";
|
||||
_running = false;
|
||||
_sgr = globals->get_subsystem<SGSoundMgr>()->find("avionics", true);
|
||||
_sgr = soundManager->find("avionics", true);
|
||||
_sgr->tie_to_listener();
|
||||
}
|
||||
|
||||
void AudioIdent::stop()
|
||||
{
|
||||
if( _sgr->exists( _fx_name ) )
|
||||
if (_sgr && _sgr->exists( _fx_name ) )
|
||||
_sgr->stop( _fx_name );
|
||||
_running = false;
|
||||
}
|
||||
|
||||
void AudioIdent::start()
|
||||
{
|
||||
if (!_sgr)
|
||||
return;
|
||||
|
||||
_timer = _interval;
|
||||
_sgr->play_once(_fx_name);
|
||||
_running = true;
|
||||
|
@ -60,10 +67,11 @@ void AudioIdent::start()
|
|||
|
||||
void AudioIdent::setVolumeNorm( double volumeNorm )
|
||||
{
|
||||
if (!_sgr)
|
||||
return;
|
||||
|
||||
SG_CLAMP_RANGE(volumeNorm, 0.0, 1.0);
|
||||
|
||||
SGSoundSample *sound = _sgr->find( _fx_name );
|
||||
|
||||
if ( sound != NULL ) {
|
||||
sound->set_volume( volumeNorm );
|
||||
}
|
||||
|
@ -71,6 +79,9 @@ void AudioIdent::setVolumeNorm( double volumeNorm )
|
|||
|
||||
void AudioIdent::setIdent( const std::string & ident, double volumeNorm )
|
||||
{
|
||||
if (!_sgr)
|
||||
return;
|
||||
|
||||
// Signal may flicker very frequently (due to our realistic newnavradio...).
|
||||
// Avoid recreating identical sound samples all the time, instead turn off
|
||||
// volume when signal is lost, and save the most recent sample.
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include <simgear/structure/event_mgr.hxx>
|
||||
#include <simgear/timing/timestamp.hxx>
|
||||
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
|
||||
namespace FGTestApi {
|
||||
|
||||
|
@ -59,6 +59,12 @@ void initTestGlobals(const std::string& testName)
|
|||
|
||||
} // End of namespace setUp.
|
||||
|
||||
void setPosition(const SGGeod& g)
|
||||
{
|
||||
globals->get_props()->setDoubleValue("position/latitude-deg", g.getLatitudeDeg());
|
||||
globals->get_props()->setDoubleValue("position/longitude-deg", g.getLongitudeDeg());
|
||||
globals->get_props()->setDoubleValue("position/altitude-ft", g.getElevationFt());
|
||||
}
|
||||
|
||||
namespace tearDown {
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
class SGGeod;
|
||||
|
||||
namespace FGTestApi {
|
||||
|
||||
namespace setUp {
|
||||
|
@ -11,6 +13,7 @@ void initTestGlobals(const std::string& testName);
|
|||
|
||||
} // End of namespace setUp.
|
||||
|
||||
void setPosition(const SGGeod& g);
|
||||
|
||||
namespace tearDown {
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ foreach( unit_test_category
|
|||
Input
|
||||
Main
|
||||
Navaids
|
||||
Instrumentation
|
||||
Scripting
|
||||
)
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include "test_hidinput.hxx"
|
||||
|
||||
#include "test_suite/helpers/globals.hxx"
|
||||
#include "test_suite/FGTestApi/globals.hxx"
|
||||
|
||||
#include <simgear/misc/test_macros.hxx>
|
||||
|
||||
|
|
12
test_suite/unit_tests/Instrumentation/CMakeLists.txt
Normal file
12
test_suite/unit_tests/Instrumentation/CMakeLists.txt
Normal file
|
@ -0,0 +1,12 @@
|
|||
set(TESTSUITE_SOURCES
|
||||
${TESTSUITE_SOURCES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TestSuite.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_navRadio.cxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
set(TESTSUITE_HEADERS
|
||||
${TESTSUITE_HEADERS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_navRadio.hxx
|
||||
PARENT_SCOPE
|
||||
)
|
23
test_suite/unit_tests/Instrumentation/TestSuite.cxx
Normal file
23
test_suite/unit_tests/Instrumentation/TestSuite.cxx
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (C) 2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "test_navRadio.hxx"
|
||||
|
||||
// Set up the unit tests.
|
||||
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(NavRadioTests, "Unit tests");
|
206
test_suite/unit_tests/Instrumentation/test_navRadio.cxx
Normal file
206
test_suite/unit_tests/Instrumentation/test_navRadio.cxx
Normal file
|
@ -0,0 +1,206 @@
|
|||
#include "test_navRadio.hxx"
|
||||
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
|
||||
#include "test_suite/FGTestApi/globals.hxx"
|
||||
#include "test_suite/FGTestApi/NavDataCache.hxx"
|
||||
|
||||
#include <Navaids/NavDataCache.hxx>
|
||||
#include <Navaids/navrecord.hxx>
|
||||
#include <Navaids/navlist.hxx>
|
||||
|
||||
#include <Instrumentation/navradio.hxx>
|
||||
|
||||
// Set up function for each test.
|
||||
void NavRadioTests::setUp()
|
||||
{
|
||||
FGTestApi::setUp::initTestGlobals("navradio");
|
||||
FGTestApi::setUp::initNavDataCache();
|
||||
}
|
||||
|
||||
|
||||
// Clean up after each test.
|
||||
void NavRadioTests::tearDown()
|
||||
{
|
||||
FGTestApi::tearDown::shutdownTestGlobals();
|
||||
}
|
||||
|
||||
void NavRadioTests::setPositionAndStabilise(FGNavRadio* r, const SGGeod& g)
|
||||
{
|
||||
FGTestApi::setPosition(g);
|
||||
for (int i=0; i<60; ++i) {
|
||||
r->update(0.1);
|
||||
}
|
||||
}
|
||||
|
||||
void NavRadioTests::testBasic()
|
||||
{
|
||||
SGPropertyNode_ptr configNode(new SGPropertyNode);
|
||||
configNode->setStringValue("name", "navtest");
|
||||
configNode->setIntValue("number", 2);
|
||||
std::unique_ptr<FGNavRadio> r(new FGNavRadio(configNode));
|
||||
|
||||
r->bind();
|
||||
r->init();
|
||||
|
||||
SGPropertyNode_ptr node = globals->get_props()->getNode("instrumentation/navtest[2]");
|
||||
node->setBoolValue("serviceable", true);
|
||||
// needed for the radio to power up
|
||||
globals->get_props()->setDoubleValue("systems/electrical/outputs/navtest", 6.0);
|
||||
node->setDoubleValue("frequencies/selected-mhz", 113.8);
|
||||
|
||||
SGGeod pos = SGGeod::fromDegFt(-3.352780, 55.499199, 20000);
|
||||
setPositionAndStabilise(r.get(), pos);
|
||||
|
||||
CPPUNIT_ASSERT(!strcmp("TLA", node->getStringValue("nav-id")));
|
||||
CPPUNIT_ASSERT_EQUAL(true, node->getBoolValue("in-range"));
|
||||
}
|
||||
|
||||
void NavRadioTests::testCDIDeflection()
|
||||
{
|
||||
SGPropertyNode_ptr configNode(new SGPropertyNode);
|
||||
configNode->setStringValue("name", "navtest");
|
||||
configNode->setIntValue("number", 2);
|
||||
std::unique_ptr<FGNavRadio> r(new FGNavRadio(configNode));
|
||||
|
||||
r->bind();
|
||||
r->init();
|
||||
|
||||
SGPropertyNode_ptr node = globals->get_props()->getNode("instrumentation/navtest[2]");
|
||||
node->setBoolValue("serviceable", true);
|
||||
// needed for the radio to power up
|
||||
globals->get_props()->setDoubleValue("systems/electrical/outputs/navtest", 6.0);
|
||||
node->setDoubleValue("frequencies/selected-mhz", 113.55);
|
||||
|
||||
node->setDoubleValue("radials/selected-deg", 25);
|
||||
|
||||
FGPositioned::TypeFilter f{FGPositioned::VOR};
|
||||
FGNavRecordRef nav = fgpositioned_cast<FGNavRecord>(FGPositioned::findClosestWithIdent("MCT", SGGeod::fromDeg(-2.26, 53.3), &f));
|
||||
|
||||
// twist of MCT is 5.0, so we use a bearing of 20 here, not 25
|
||||
SGGeod posOnRadial = SGGeodesy::direct(nav->geod(), 20.0, 10 * SG_NM_TO_METER);
|
||||
posOnRadial.setElevationFt(10000);
|
||||
setPositionAndStabilise(r.get(), posOnRadial);
|
||||
|
||||
CPPUNIT_ASSERT(!strcmp("MCT", node->getStringValue("nav-id")));
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, node->getDoubleValue("heading-needle-deflection"), 0.01);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, node->getDoubleValue("heading-needle-deflection-norm"), 0.01);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, node->getDoubleValue("signal-quality-norm"), 0.01);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, node->getDoubleValue("crosstrack-error-m"), 0.01);
|
||||
CPPUNIT_ASSERT(node->getBoolValue("from-flag"));
|
||||
CPPUNIT_ASSERT(!node->getBoolValue("to-flag"));
|
||||
|
||||
|
||||
// move off course
|
||||
SGGeod posOffRadial = SGGeodesy::direct(nav->geod(), 15.0, 20 * SG_NM_TO_METER); // 5 degress off
|
||||
posOffRadial.setElevationFt(12000);
|
||||
setPositionAndStabilise(r.get(), posOffRadial);
|
||||
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(5.0, node->getDoubleValue("heading-needle-deflection"), 0.1);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.5, node->getDoubleValue("heading-needle-deflection-norm"), 0.01);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, node->getDoubleValue("signal-quality-norm"), 0.01);
|
||||
|
||||
double xtkE = sin(5.0 * SG_DEGREES_TO_RADIANS) * 20 * SG_NM_TO_METER;
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(xtkE, node->getDoubleValue("crosstrack-error-m"), 50.0);
|
||||
CPPUNIT_ASSERT(node->getBoolValue("from-flag"));
|
||||
CPPUNIT_ASSERT(!node->getBoolValue("to-flag"));
|
||||
|
||||
posOffRadial = SGGeodesy::direct(nav->geod(), 28.0, 30 * SG_NM_TO_METER); // 8 degress off
|
||||
posOffRadial.setElevationFt(16000);
|
||||
setPositionAndStabilise(r.get(), posOffRadial);
|
||||
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, node->getDoubleValue("signal-quality-norm"), 0.01);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(-8.0, node->getDoubleValue("heading-needle-deflection"), 0.1);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(-0.8, node->getDoubleValue("heading-needle-deflection-norm"), 0.01);
|
||||
|
||||
xtkE = sin(-8.0 * SG_DEGREES_TO_RADIANS) * 30 * SG_NM_TO_METER;
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(xtkE, node->getDoubleValue("crosstrack-error-m"), 50.0);
|
||||
|
||||
// move more than ten degrees off course
|
||||
posOffRadial = SGGeodesy::direct(nav->geod(), 33.0, 40 * SG_NM_TO_METER); // 13 degress off
|
||||
posOffRadial.setElevationFt(16000);
|
||||
setPositionAndStabilise(r.get(), posOffRadial);
|
||||
|
||||
// pegged to full deflection
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, node->getDoubleValue("signal-quality-norm"), 0.01);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(-10.0, node->getDoubleValue("heading-needle-deflection"), 0.1);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.0, node->getDoubleValue("heading-needle-deflection-norm"), 0.01);
|
||||
|
||||
// cross track error is computed based on true deflection, not clamped
|
||||
xtkE = sin(-13.0 * SG_DEGREES_TO_RADIANS) * 40 * SG_NM_TO_METER;
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(xtkE, node->getDoubleValue("crosstrack-error-m"), 50.0);
|
||||
CPPUNIT_ASSERT(node->getBoolValue("from-flag"));
|
||||
CPPUNIT_ASSERT(!node->getBoolValue("to-flag"));
|
||||
|
||||
// try on the TO side of the station
|
||||
// let's use Perth VOR, but the Australian one to check southern
|
||||
// hemisphere operation
|
||||
node->setDoubleValue("frequencies/selected-mhz", 113.7);
|
||||
node->setDoubleValue("radials/selected-deg", 42.0); // twist is -2.0
|
||||
CPPUNIT_ASSERT(!strcmp("113.70", node->getStringValue("frequencies/selected-mhz-fmt")));
|
||||
|
||||
auto perthVOR = fgpositioned_cast<FGNavRecord>(
|
||||
FGPositioned::findClosestWithIdent("PH", SGGeod::fromDeg(115.95, -31.9), &f));
|
||||
|
||||
SGGeod p = SGGeodesy::direct(perthVOR->geod(), 220.0, 20 * SG_NM_TO_METER); // on the reciprocal radial
|
||||
p.setElevationFt(12000);
|
||||
setPositionAndStabilise(r.get(), p);
|
||||
|
||||
CPPUNIT_ASSERT(!strcmp("PH", node->getStringValue("nav-id")));
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, node->getDoubleValue("signal-quality-norm"), 0.01);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(40.0, node->getDoubleValue("heading-deg"), 0.5);
|
||||
|
||||
// actual radial has twist subtracted
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(222.0, node->getDoubleValue("radials/actual-deg"), 0.01);
|
||||
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, node->getDoubleValue("heading-needle-deflection"), 0.1);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, node->getDoubleValue("heading-needle-deflection-norm"), 0.01);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, node->getDoubleValue("crosstrack-error-m"), 50.0);
|
||||
CPPUNIT_ASSERT(!node->getBoolValue("from-flag"));
|
||||
CPPUNIT_ASSERT(node->getBoolValue("to-flag"));
|
||||
|
||||
// off course on the TO side
|
||||
p = SGGeodesy::direct(perthVOR->geod(), 227.0, 100 * SG_NM_TO_METER);
|
||||
p.setElevationFt(18000);
|
||||
setPositionAndStabilise(r.get(), p);
|
||||
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, node->getDoubleValue("signal-quality-norm"), 0.01);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(47.0, node->getDoubleValue("heading-deg"), 1);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(229.0, node->getDoubleValue("radials/actual-deg"), 0.01);
|
||||
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(7.0, node->getDoubleValue("heading-needle-deflection"), 0.1);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.7, node->getDoubleValue("heading-needle-deflection-norm"), 0.01);
|
||||
|
||||
xtkE = sin(7.0 * SG_DEGREES_TO_RADIANS) * 100 * SG_NM_TO_METER;
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(xtkE, node->getDoubleValue("crosstrack-error-m"), 50.0);
|
||||
CPPUNIT_ASSERT(!node->getBoolValue("from-flag"));
|
||||
CPPUNIT_ASSERT(node->getBoolValue("to-flag"));
|
||||
}
|
||||
|
||||
void NavRadioTests::testILSBasic()
|
||||
{
|
||||
|
||||
// also check ILS back course
|
||||
}
|
||||
|
||||
void NavRadioTests::testGS()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void NavRadioTests::testILSFalseCourse()
|
||||
{
|
||||
|
||||
// also GS false lobes
|
||||
}
|
||||
|
||||
void NavRadioTests::testILSPaired()
|
||||
{
|
||||
// EGPH and countless more
|
||||
}
|
||||
|
||||
void NavRadioTests::testILSAdjacentPaired()
|
||||
{
|
||||
// eg KJFK
|
||||
}
|
67
test_suite/unit_tests/Instrumentation/test_navRadio.hxx
Normal file
67
test_suite/unit_tests/Instrumentation/test_navRadio.hxx
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (C) 2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FG_NAVRADIO_UNIT_TESTS_HXX
|
||||
#define _FG_NAVRADIO_UNIT_TESTS_HXX
|
||||
|
||||
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include <cppunit/TestFixture.h>
|
||||
|
||||
class FGNavRadio;
|
||||
class SGGeod;
|
||||
|
||||
// The flight plan unit tests.
|
||||
class NavRadioTests : public CppUnit::TestFixture
|
||||
{
|
||||
// Set up the test suite.
|
||||
CPPUNIT_TEST_SUITE(NavRadioTests);
|
||||
CPPUNIT_TEST(testBasic);
|
||||
CPPUNIT_TEST(testCDIDeflection);
|
||||
|
||||
CPPUNIT_TEST(testILSBasic);
|
||||
CPPUNIT_TEST(testGS);
|
||||
CPPUNIT_TEST(testILSFalseCourse);
|
||||
CPPUNIT_TEST(testILSPaired);
|
||||
CPPUNIT_TEST(testILSAdjacentPaired);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
void setPositionAndStabilise(FGNavRadio* r, const SGGeod& g);
|
||||
|
||||
public:
|
||||
// Set up function for each test.
|
||||
void setUp();
|
||||
|
||||
// Clean up after each test.
|
||||
void tearDown();
|
||||
|
||||
// The tests.
|
||||
void testBasic();
|
||||
void testCDIDeflection();
|
||||
|
||||
void testILSBasic();
|
||||
void testGS();
|
||||
void testILSFalseCourse();
|
||||
void testILSPaired();
|
||||
void testILSAdjacentPaired();
|
||||
};
|
||||
|
||||
#endif // _FG_NAVRADIO_UNIT_TESTS_HXX
|
Loading…
Add table
Reference in a new issue