mirror of
https://github.com/30hours/blah2.git
synced 2024-11-18 12:33:58 +00:00
Update test architecture and TestAmbiguity
This commit is contained in:
parent
25d0b6d1b7
commit
d9a26299c7
3 changed files with 104 additions and 44 deletions
|
@ -8,11 +8,14 @@ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
||||||
|
|
||||||
SET (PROJECT_ROOT "${PROJECT_SOURCE_DIR}")
|
SET (PROJECT_ROOT "${PROJECT_SOURCE_DIR}")
|
||||||
SET (CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_ROOT}/bin")
|
SET (CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_ROOT}/bin")
|
||||||
|
SET (PROJECT_TEST_DIR "${PROJECT_SOURCE_DIR}/test")
|
||||||
SET (PROJECT_SOURCE_DIR "${PROJECT_SOURCE_DIR}/src")
|
SET (PROJECT_SOURCE_DIR "${PROJECT_SOURCE_DIR}/src")
|
||||||
SET (PROJECT_BINARY_DIR "${PROJECT_ROOT}/bin")
|
SET (PROJECT_BINARY_DIR "${PROJECT_ROOT}/bin")
|
||||||
|
SET (PROJECT_BINARY_TEST_DIR "${PROJECT_ROOT}/bin/test")
|
||||||
SET (PROJECT_LIB_DIR "${PROJECT_ROOT}/lib")
|
SET (PROJECT_LIB_DIR "${PROJECT_ROOT}/lib")
|
||||||
MESSAGE ("Source path: ${PROJECT_SOURCE_DIR}")
|
MESSAGE ("Source path: ${PROJECT_SOURCE_DIR}")
|
||||||
MESSAGE ("Binary path: ${PROJECT_BINARY_DIR}")
|
MESSAGE ("Binary path: ${PROJECT_BINARY_DIR}")
|
||||||
|
MESSAGE ("Binary test path: ${PROJECT_BINARY_TEST_DIR}")
|
||||||
MESSAGE ("Lib path: ${PROJECT_LIB_DIR}")
|
MESSAGE ("Lib path: ${PROJECT_LIB_DIR}")
|
||||||
|
|
||||||
add_executable(blah2
|
add_executable(blah2
|
||||||
|
@ -74,9 +77,11 @@ include_directories("${PROJECT_SOURCE_DIR}/process/spectrum/")
|
||||||
include_directories("${PROJECT_SOURCE_DIR}/data/")
|
include_directories("${PROJECT_SOURCE_DIR}/data/")
|
||||||
include_directories("${PROJECT_SOURCE_DIR}/data/meta/")
|
include_directories("${PROJECT_SOURCE_DIR}/data/meta/")
|
||||||
|
|
||||||
add_executable(test_ambiguity
|
# unit tests
|
||||||
|
add_executable(testAmbiguity
|
||||||
|
${PROJECT_TEST_DIR}/unit/process/ambiguity/TestAmbiguity.cpp
|
||||||
${PROJECT_SOURCE_DIR}/data/IqData.cpp
|
${PROJECT_SOURCE_DIR}/data/IqData.cpp
|
||||||
${PROJECT_SOURCE_DIR}/data/Map.cpp
|
${PROJECT_SOURCE_DIR}/data/Map.cpp
|
||||||
${PROJECT_SOURCE_DIR}/process/ambiguity/Ambiguity.cpp
|
${PROJECT_SOURCE_DIR}/process/ambiguity/Ambiguity.cpp)
|
||||||
${PROJECT_SOURCE_DIR}/process/ambiguity/test_ambiguity.cpp)
|
target_link_libraries(testAmbiguity catch2 fftw3 fftw3_threads)
|
||||||
target_link_libraries(test_ambiguity catch2 fftw3 fftw3_threads)
|
set_target_properties(testAmbiguity PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_TEST_DIR}")
|
||||||
|
|
31
test/README.md
Normal file
31
test/README.md
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# blah2 Test
|
||||||
|
|
||||||
|
**TODO: Tests not implemented yet. Describing desired behaviour for the time being.**
|
||||||
|
|
||||||
|
## Framework
|
||||||
|
|
||||||
|
The test framework is [catch2](https://github.com/catchorg/Catch2).
|
||||||
|
|
||||||
|
## Types
|
||||||
|
|
||||||
|
The test files are split across directories defined by the type of test.
|
||||||
|
|
||||||
|
- **Unit tests** will test the class in isolation. The directory structure mirrors *src*.
|
||||||
|
- **Functional tests** will test that expected outputs are achieved from defined inputs. An example would be checking the program turns a specific IQ data set to a specific delay-Doppler map. This test category will rely on golden data.
|
||||||
|
- **Comparison tests** will compare different methods of performing the same task. An example would be comparing 2 methods of clutter filtering. Metrics to be compared may include time and performance. Note there is no pass/fail criteria for comparison tests - this is purely for information.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
All tests are compiled when building, however tests be run manually.
|
||||||
|
|
||||||
|
- Run a single test case for "TestClass".
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo docker compose run blah2-test TestClass
|
||||||
|
```
|
||||||
|
|
||||||
|
- Run all test cases.
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo docker compose run blah2-test *
|
||||||
|
```
|
|
@ -1,3 +1,10 @@
|
||||||
|
/// @file TestAmbiguity.cpp
|
||||||
|
/// @brief Unit test for Ambiguity.cpp
|
||||||
|
/// @author 30hours
|
||||||
|
/// @author Dan G
|
||||||
|
/// @todo Add golden data IqData file for testing.
|
||||||
|
/// @todo Declaration match to coding style?
|
||||||
|
|
||||||
#define CATCH_CONFIG_MAIN
|
#define CATCH_CONFIG_MAIN
|
||||||
#include "catch_amalgamated.hpp"
|
#include "catch_amalgamated.hpp"
|
||||||
|
|
||||||
|
@ -5,9 +12,13 @@
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
/// @brief Use random_device as RNG.
|
||||||
std::random_device g_rd;
|
std::random_device g_rd;
|
||||||
|
|
||||||
// Have to use out ref parameter because there's no copy/move ctors
|
/// @brief Generate random IQ data.
|
||||||
|
/// @param iqData Address of IqData object.
|
||||||
|
/// @details Have to use out ref parameter because there's no copy/move ctors.
|
||||||
|
/// @return Void.
|
||||||
void random_iq(IqData& iq_data) {
|
void random_iq(IqData& iq_data) {
|
||||||
std::mt19937 gen(g_rd());
|
std::mt19937 gen(g_rd());
|
||||||
std::uniform_real_distribution<> dist(-100.0, 100.0);
|
std::uniform_real_distribution<> dist(-100.0, 100.0);
|
||||||
|
@ -17,6 +28,11 @@ void random_iq(IqData& iq_data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Read file to IqData buffer.
|
||||||
|
/// @param buffer1 IqData buffer reference.
|
||||||
|
/// @param buffer2 IqData buffer surveillance.
|
||||||
|
/// @param file String of file name.
|
||||||
|
/// @return Void.
|
||||||
void read_file(IqData& buffer1, IqData& buffer2, const std::string& file)
|
void read_file(IqData& buffer1, IqData& buffer2, const std::string& file)
|
||||||
{
|
{
|
||||||
short i1, q1, i2, q2;
|
short i1, q1, i2, q2;
|
||||||
|
@ -40,7 +56,7 @@ void read_file(IqData& buffer1, IqData& buffer2, const std::string& file)
|
||||||
buffer1.push_back({(double)i1, (double)q1});
|
buffer1.push_back({(double)i1, (double)q1});
|
||||||
buffer2.push_back({(double)i2, (double)q2});
|
buffer2.push_back({(double)i2, (double)q2});
|
||||||
|
|
||||||
// Only read for the buffer length - this class is very poorly designed.
|
// only read for the buffer length - this class is very poorly designed
|
||||||
if (buffer1.get_length() == buffer1.get_n()) {
|
if (buffer1.get_length() == buffer1.get_n()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -49,67 +65,72 @@ void read_file(IqData& buffer1, IqData& buffer2, const std::string& file)
|
||||||
fclose(file_replay);
|
fclose(file_replay);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the constructor is calculating the parameters correctly.
|
/// @brief Test constructor.
|
||||||
|
/// @details Check constructor parameters created correctly.
|
||||||
TEST_CASE("Constructor", "[constructor]")
|
TEST_CASE("Constructor", "[constructor]")
|
||||||
{
|
{
|
||||||
int32_t delay_min{-10};
|
int32_t delayMin{-10};
|
||||||
int32_t delay_max{300};
|
int32_t delayMax{300};
|
||||||
int32_t doppler_min{-300};
|
int32_t dopplerMin{-300};
|
||||||
int32_t doppler_max{300};
|
int32_t dopplerMax{300};
|
||||||
|
|
||||||
uint32_t fs{2'000'000};
|
uint32_t fs{2'000'000};
|
||||||
float cpi_s{0.5};
|
float tCpi{0.5};
|
||||||
uint32_t n_samples = cpi_s * fs; // narrow on purpose
|
uint32_t nSamples = tCpi * fs; // narrow on purpose
|
||||||
|
|
||||||
Ambiguity ambiguity(delay_min,delay_max,doppler_min,doppler_max,fs,n_samples);
|
Ambiguity ambiguity(delayMin, delayMax, dopplerMin,
|
||||||
|
dopplerMax, fs, nSamples);
|
||||||
|
|
||||||
CHECK_THAT(ambiguity.cpi_length_seconds(), Catch::Matchers::WithinAbs(cpi_s, 0.02));
|
CHECK_THAT(ambiguity.cpi_length_seconds(), Catch::Matchers::WithinAbs(tCpi, 0.02));
|
||||||
CHECK(ambiguity.doppler_middle() == 0);
|
CHECK(ambiguity.doppler_middle() == 0);
|
||||||
CHECK(ambiguity.corr_samples_per_pulse() == 3322);
|
CHECK(ambiguity.corr_samples_per_pulse() == 3322);
|
||||||
CHECK(ambiguity.delay_bin_count() == delay_max + std::abs(delay_min) + 1);
|
CHECK(ambiguity.delay_bin_count() == delayMax + std::abs(delayMin) + 1);
|
||||||
CHECK(ambiguity.doppler_bin_count() == 301);
|
CHECK(ambiguity.doppler_bin_count() == 301);
|
||||||
CHECK(ambiguity.fft_bin_count() == 6643);
|
CHECK(ambiguity.fft_bin_count() == 6643);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the constructor is calculating the parameters correctly with rounded FFT length
|
/// @brief Test constructor with rounded Hamming number FFT length.
|
||||||
TEST_CASE("Constructor_Round", "[constructor]")
|
TEST_CASE("Constructor_Round", "[constructor]")
|
||||||
{
|
{
|
||||||
int32_t delay_min{-10};
|
int32_t delayMin{-10};
|
||||||
int32_t delay_max{300};
|
int32_t delayMax{300};
|
||||||
int32_t doppler_min{-300};
|
int32_t dopplerMin{-300};
|
||||||
int32_t doppler_max{300};
|
int32_t dopplerMax{300};
|
||||||
|
|
||||||
uint32_t fs{2'000'000};
|
uint32_t fs{2'000'000};
|
||||||
float cpi_s{0.5};
|
float tCpi{0.5};
|
||||||
uint32_t n_samples = cpi_s * fs; // narrow on purpose
|
uint32_t nSamples = tCpi * fs; // narrow on purpose
|
||||||
|
|
||||||
Ambiguity ambiguity(delay_min,delay_max,doppler_min,doppler_max,fs,n_samples,true);
|
Ambiguity ambiguity(delayMin, delayMax, dopplerMin,
|
||||||
|
dopplerMax, fs, nSamples, true);
|
||||||
|
|
||||||
CHECK_THAT(ambiguity.cpi_length_seconds(), Catch::Matchers::WithinAbs(cpi_s, 0.02));
|
CHECK_THAT(ambiguity.cpi_length_seconds(), Catch::Matchers::WithinAbs(tCpi, 0.02));
|
||||||
CHECK(ambiguity.doppler_middle() == 0);
|
CHECK(ambiguity.doppler_middle() == 0);
|
||||||
CHECK(ambiguity.corr_samples_per_pulse() == 3322);
|
CHECK(ambiguity.corr_samples_per_pulse() == 3322);
|
||||||
CHECK(ambiguity.delay_bin_count() == delay_max + std::abs(delay_min) + 1);
|
CHECK(ambiguity.delay_bin_count() == delayMax + std::abs(delayMin) + 1);
|
||||||
CHECK(ambiguity.doppler_bin_count() == 301);
|
CHECK(ambiguity.doppler_bin_count() == 301);
|
||||||
CHECK(ambiguity.fft_bin_count() == 6750);
|
CHECK(ambiguity.fft_bin_count() == 6750);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Test simple ambiguity processing.
|
||||||
TEST_CASE("Process_Simple", "[process]")
|
TEST_CASE("Process_Simple", "[process]")
|
||||||
{
|
{
|
||||||
auto round_hamming = GENERATE(true, false);
|
auto round_hamming = GENERATE(true, false);
|
||||||
|
|
||||||
int32_t delay_min{-10};
|
int32_t delayMin{-10};
|
||||||
int32_t delay_max{300};
|
int32_t delayMax{300};
|
||||||
int32_t doppler_min{-300};
|
int32_t dopplerMin{-300};
|
||||||
int32_t doppler_max{300};
|
int32_t dopplerMax{300};
|
||||||
|
|
||||||
uint32_t fs{2'000'000};
|
uint32_t fs{2'000'000};
|
||||||
float cpi_s{0.5};
|
float tCpi{0.5};
|
||||||
uint32_t n_samples = cpi_s * fs; // narrow on purpose
|
uint32_t nSamples = tCpi * fs; // narrow on purpose
|
||||||
|
|
||||||
Ambiguity ambiguity(delay_min,delay_max,doppler_min,doppler_max,fs,n_samples, round_hamming);
|
Ambiguity ambiguity(delayMin, delayMax, dopplerMin,
|
||||||
|
dopplerMax, fs, nSamples, round_hamming);
|
||||||
|
|
||||||
IqData x{n_samples};
|
IqData x{nSamples};
|
||||||
IqData y{n_samples};
|
IqData y{nSamples};
|
||||||
|
|
||||||
random_iq(x);
|
random_iq(x);
|
||||||
random_iq(y);
|
random_iq(y);
|
||||||
|
@ -122,22 +143,24 @@ TEST_CASE("Process_Simple", "[process]")
|
||||||
<< ambiguity.get_latest_performance() << "\n-----------" << std::endl;
|
<< ambiguity.get_latest_performance() << "\n-----------" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Test processing from a file.
|
||||||
TEST_CASE("Process_File", "[process]")
|
TEST_CASE("Process_File", "[process]")
|
||||||
{
|
{
|
||||||
auto round_hamming = GENERATE(true, false);
|
auto round_hamming = GENERATE(true, false);
|
||||||
|
|
||||||
int32_t delay_min{-10};
|
int32_t delayMin{-10};
|
||||||
int32_t delay_max{300};
|
int32_t delayMax{300};
|
||||||
int32_t doppler_min{-300};
|
int32_t dopplerMin{-300};
|
||||||
int32_t doppler_max{300};
|
int32_t dopplerMax{300};
|
||||||
|
|
||||||
uint32_t fs{2'000'000};
|
uint32_t fs{2'000'000};
|
||||||
float cpi_s{0.5};
|
float tCpi{0.5};
|
||||||
uint32_t n_samples = cpi_s * fs; // narrow on purpose
|
uint32_t nSamples = tCpi * fs; // narrow on purpose
|
||||||
|
|
||||||
Ambiguity ambiguity(delay_min,delay_max,doppler_min,doppler_max,fs,n_samples, round_hamming);
|
Ambiguity ambiguity(delayMin, delayMax, dopplerMin,
|
||||||
IqData x{n_samples};
|
dopplerMax, fs, nSamples, round_hamming);
|
||||||
IqData y{n_samples};
|
IqData x{nSamples};
|
||||||
|
IqData y{nSamples};
|
||||||
|
|
||||||
read_file(x, y, "20231214-230611.rspduo");
|
read_file(x, y, "20231214-230611.rspduo");
|
||||||
REQUIRE(x.get_length() == x.get_n());
|
REQUIRE(x.get_length() == x.get_n());
|
||||||
|
@ -151,6 +174,7 @@ TEST_CASE("Process_File", "[process]")
|
||||||
<< ambiguity.get_latest_performance() << "\n-----------" << std::endl;
|
<< ambiguity.get_latest_performance() << "\n-----------" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Test Hamming number calculation.
|
||||||
TEST_CASE("Next_Hamming", "[hamming]")
|
TEST_CASE("Next_Hamming", "[hamming]")
|
||||||
{
|
{
|
||||||
CHECK(next_hamming(104) == 108);
|
CHECK(next_hamming(104) == 108);
|
Loading…
Reference in a new issue