mirror of
https://github.com/30hours/blah2.git
synced 2024-11-18 12:33:58 +00:00
added class to generate returns from false targets. Currently only static targets implemented
This commit is contained in:
parent
440d74bcbc
commit
6cdc7e0289
11 changed files with 360 additions and 20 deletions
|
@ -44,6 +44,7 @@ add_executable(blah2
|
|||
src/capture/rspduo/RspDuo.cpp
|
||||
src/capture/usrp/Usrp.cpp
|
||||
src/capture/iqsimulator/IqSimulator.cpp
|
||||
src/capture/iqsimulator/TgtGen.cpp
|
||||
src/process/ambiguity/Ambiguity.cpp
|
||||
src/process/clutter/WienerHopf.cpp
|
||||
src/process/detection/CfarDetector1D.cpp
|
||||
|
@ -58,6 +59,7 @@ add_executable(blah2
|
|||
src/data/Detection.cpp
|
||||
src/data/Track.cpp
|
||||
src/data/meta/Timing.cpp
|
||||
src/utilities/Conversions.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(blah2 PRIVATE
|
||||
|
|
18
config/false_targets.yml
Normal file
18
config/false_targets.yml
Normal file
|
@ -0,0 +1,18 @@
|
|||
targets:
|
||||
- id: 1
|
||||
type: "static"
|
||||
location:
|
||||
range: 10000 # meters
|
||||
velocity:
|
||||
doppler: 50 # Hertz
|
||||
rcs: -20 # dBsm - this is a bit contrived for a static target
|
||||
state: "active"
|
||||
|
||||
- id: 2
|
||||
type: "static"
|
||||
location:
|
||||
range: 30000 # meters
|
||||
velocity:
|
||||
doppler: -150 # Hertz
|
||||
rcs: -20 # dBsm
|
||||
state: "active"
|
|
@ -63,11 +63,11 @@ void Capture::process(IqData *buffer1, IqData *buffer2, c4::yml::NodeRef config)
|
|||
|
||||
std::unique_ptr<Source> Capture::factory_source(const std::string &type, c4::yml::NodeRef config)
|
||||
{
|
||||
if (type == VALID_TYPE[0])
|
||||
if (type == VALID_TYPE[0]) // RspDuo
|
||||
{
|
||||
return std::make_unique<RspDuo>(type, fc, fs, path, &saveIq);
|
||||
}
|
||||
else if (type == VALID_TYPE[1])
|
||||
else if (type == VALID_TYPE[1]) // Usrp
|
||||
{
|
||||
std::string address, subdev;
|
||||
std::vector<std::string> antenna;
|
||||
|
@ -88,11 +88,13 @@ std::unique_ptr<Source> Capture::factory_source(const std::string &type, c4::yml
|
|||
return std::make_unique<Usrp>(type, fc, fs, path, &saveIq,
|
||||
address, subdev, antenna, gain);
|
||||
}
|
||||
else if (type == VALID_TYPE[2])
|
||||
else if (type == VALID_TYPE[2]) // IqSimulator
|
||||
{
|
||||
uint32_t n, n_min;
|
||||
uint32_t n_min;
|
||||
n_min = 2000000;
|
||||
return std::make_unique<IqSimulator>(type, fc, fs, path, &saveIq, n_min);
|
||||
std::string false_targets_config_file_path = "config/false_targets.yml";
|
||||
return std::make_unique<IqSimulator>(type, fc, fs, path, &saveIq, n_min,
|
||||
false_targets_config_file_path);
|
||||
}
|
||||
// Handle unknown type
|
||||
std::cerr << "Error: Source type does not exist." << std::endl;
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
#include "IqSimulator.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <complex>
|
||||
#include <random>
|
||||
|
||||
// constructor
|
||||
IqSimulator::IqSimulator(std::string _type, uint32_t _fc, uint32_t _fs,
|
||||
std::string _path, bool *_saveIq, uint32_t _n_min = 1000)
|
||||
std::string _path, bool *_saveIq,
|
||||
uint32_t _n_min = 1000,
|
||||
std::string _falseTargetsConfigFilePath = "config/false_targets.yml")
|
||||
: Source(_type, _fc, _fs, _path, _saveIq)
|
||||
{
|
||||
n_min = _n_min;
|
||||
u_int64_t total_samples = 0;
|
||||
false_targets_config_file_path = _falseTargetsConfigFilePath;
|
||||
}
|
||||
|
||||
void IqSimulator::start()
|
||||
|
@ -24,10 +22,15 @@ void IqSimulator::stop()
|
|||
|
||||
void IqSimulator::process(IqData *buffer1, IqData *buffer2)
|
||||
{
|
||||
const u_int32_t samples_per_iteration = 1000;
|
||||
|
||||
TgtGen false_targets = TgtGen(false_targets_config_file_path, fs);
|
||||
while (true)
|
||||
{
|
||||
if (buffer1->get_length() < n_min)
|
||||
uint32_t n_start = buffer1->get_length();
|
||||
if (n_start < n_min)
|
||||
{
|
||||
|
||||
// create a random number generator
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
|
@ -35,11 +38,22 @@ void IqSimulator::process(IqData *buffer1, IqData *buffer2)
|
|||
|
||||
buffer1->lock();
|
||||
buffer2->lock();
|
||||
for (int i = 0; i < 1000; i++)
|
||||
for (uint16_t i = 0; i < samples_per_iteration; i++)
|
||||
{
|
||||
|
||||
buffer1->push_back({(double)dis(gen), (double)dis(gen)});
|
||||
try
|
||||
{
|
||||
std::complex<double> response = false_targets.process(buffer1);
|
||||
response += std::complex<double>((double)dis(gen), (double)dis(gen));
|
||||
buffer2->push_back(response);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
buffer2->push_back({(double)dis(gen), (double)dis(gen)});
|
||||
}
|
||||
}
|
||||
total_samples += samples_per_iteration;
|
||||
buffer1->unlock();
|
||||
buffer2->unlock();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
/// @file IQSimulator.h
|
||||
/// @class IQSimulator
|
||||
/// @file IqSimulator.h
|
||||
/// @class IqSimulator
|
||||
/// @brief A class to generate simulated IQ data with false targets
|
||||
/// @details
|
||||
/// @details This class generates simulated IQ data with false targets.
|
||||
/// It generates a random reference and surveillance signal and uses the
|
||||
/// TgtGen class to add false targets to the surveillance signal.
|
||||
///
|
||||
/// @author bennysomers
|
||||
/// @todo Simulate a single false target
|
||||
|
@ -13,18 +15,32 @@
|
|||
#define IQSIMULATOR_H
|
||||
|
||||
#include "capture/Source.h"
|
||||
#include "TgtGen.h"
|
||||
#include "data/IqData.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <complex>
|
||||
#include <random>
|
||||
|
||||
class IqSimulator : public Source
|
||||
{
|
||||
private:
|
||||
/// @brief Number of samples to generate each loop.
|
||||
/// @details This is the number of samples to generate each time the process method is called. It is also the threshold for the minimum number of samples left in the buffer before new samples will be generated.
|
||||
/// @details This is the threshold for the minimum number of samples
|
||||
/// left in the buffer before new samples will be generated.
|
||||
uint32_t n_min;
|
||||
|
||||
/// @brief Total number of samples generated.
|
||||
/// @details This is used to keep track of the total number of samples
|
||||
/// generated, so that the Doppler shift can be calculated.
|
||||
u_int64_t total_samples;
|
||||
|
||||
/// @brief Path to the false targets configuration file.
|
||||
std::string false_targets_config_file_path;
|
||||
|
||||
public:
|
||||
/// @brief Constructor.
|
||||
/// @param type Type of source. = "IQSimulator"
|
||||
|
@ -35,7 +51,7 @@ public:
|
|||
/// @param n Number of samples.
|
||||
/// @return The object.
|
||||
IqSimulator(std::string type, uint32_t fc, uint32_t fs, std::string path,
|
||||
bool *saveIq, uint32_t n_min);
|
||||
bool *saveIq, uint32_t n_min, std::string false_targets_config_file_path);
|
||||
|
||||
/// @brief Implement capture function on IQSimulator.
|
||||
/// @param buffer1 Pointer to reference buffer.
|
||||
|
|
125
src/capture/iqsimulator/TgtGen.cpp
Normal file
125
src/capture/iqsimulator/TgtGen.cpp
Normal file
|
@ -0,0 +1,125 @@
|
|||
#include "TgtGen.h"
|
||||
|
||||
// this is straight up copied from blah2.cpp, but I don't know the best way to access that function here.
|
||||
// edit: put it in utilities?
|
||||
std::string ryml_get_file_copy(const char *filename);
|
||||
|
||||
// constants
|
||||
const std::string TgtGen::VALID_TYPE[1] = {"static"};
|
||||
const std::string TgtGen::VALID_STATE[1] = {"active"};
|
||||
|
||||
// constructor
|
||||
TgtGen::TgtGen(std::string configPath, uint32_t fs)
|
||||
{
|
||||
// Read in the config file
|
||||
std::string config = ryml_get_file_copy(configPath.c_str());
|
||||
ryml::Tree tree = ryml::parse_in_arena(ryml::to_csubstr(config));
|
||||
|
||||
// Create a FalseTarget object for each target in the config file
|
||||
for (auto target_node : tree["targets"].children())
|
||||
{
|
||||
if (target_node["state"].val() == VALID_STATE[0])
|
||||
{
|
||||
try
|
||||
{
|
||||
targets.push_back(FalseTarget(target_node, fs));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << e.what() << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::complex<double> TgtGen::process(IqData *ref_buffer)
|
||||
{
|
||||
std::complex<double> response = std::complex<double>(0, 0);
|
||||
// loop through each target
|
||||
for (auto target : targets)
|
||||
{
|
||||
response += target.process(ref_buffer);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
std::string FalseTarget::get_type()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
double FalseTarget::get_range()
|
||||
{
|
||||
return range;
|
||||
}
|
||||
|
||||
double FalseTarget::get_doppler()
|
||||
{
|
||||
return doppler;
|
||||
}
|
||||
|
||||
double FalseTarget::get_rcs()
|
||||
{
|
||||
return rcs;
|
||||
}
|
||||
|
||||
double FalseTarget::get_delay()
|
||||
{
|
||||
return delay;
|
||||
}
|
||||
|
||||
u_int32_t FalseTarget::get_id()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
FalseTarget::FalseTarget(c4::yml::NodeRef target_node, uint32_t _fs)
|
||||
{
|
||||
|
||||
target_node["id"] >> id;
|
||||
target_node["type"] >> type;
|
||||
fs = _fs;
|
||||
|
||||
if (type == TgtGen::VALID_TYPE[0])
|
||||
{
|
||||
target_node["location"]["range"] >> range;
|
||||
delay = range / 3e8;
|
||||
delay_samples = delay * fs;
|
||||
target_node["velocity"]["doppler"] >> doppler;
|
||||
target_node["rcs"] >> rcs;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::invalid_argument("Invalid target type");
|
||||
}
|
||||
}
|
||||
|
||||
std::complex<double> FalseTarget::process(IqData *buffer)
|
||||
{
|
||||
uint32_t buffer_length = buffer->get_length();
|
||||
std::complex<double> response = 0;
|
||||
try
|
||||
{
|
||||
response = Conversions::db2lin(rcs) * buffer->get_sample(buffer_length - delay_samples);
|
||||
response *= std::exp(std::polar<double>(1, 2 * M_PI * doppler * buffer_length / fs));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
std::string ryml_get_file_copy(const char *filename)
|
||||
{
|
||||
std::ifstream in(filename, std::ios::in | std::ios::binary);
|
||||
if (!in)
|
||||
{
|
||||
std::cerr << "could not open " << filename << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
std::ostringstream contents;
|
||||
contents << in.rdbuf();
|
||||
return contents.str();
|
||||
}
|
115
src/capture/iqsimulator/TgtGen.h
Normal file
115
src/capture/iqsimulator/TgtGen.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
/// @file TgtGen.h
|
||||
/// @class TgtGen
|
||||
/// @brief A class to generate false targets.
|
||||
|
||||
/// @details
|
||||
/// Static Targets: remain at a fixed range/delay and Doppler.
|
||||
|
||||
/// @author bennysomers
|
||||
/// @todo Simulate a false target moving in radar coordinates
|
||||
/// @todo Simulate a false target moving in spatial coordinates
|
||||
|
||||
#ifndef TGTGEN_H
|
||||
#define TGTGEN_H
|
||||
|
||||
#include "data/IqData.h"
|
||||
#include "utilities/Conversions.h"
|
||||
|
||||
#include <ryml/ryml.hpp>
|
||||
#include <ryml/ryml_std.hpp>
|
||||
#include <c4/format.hpp>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <complex>
|
||||
|
||||
class FalseTarget
|
||||
{
|
||||
private:
|
||||
/// @brief fs
|
||||
uint32_t fs;
|
||||
|
||||
/// @brief Target type.
|
||||
std::string type;
|
||||
|
||||
/// @brief Target delay
|
||||
double delay;
|
||||
|
||||
/// @brief Target delay in samples
|
||||
uint32_t delay_samples;
|
||||
|
||||
/// @brief Target range
|
||||
double range;
|
||||
|
||||
/// @brief Target Doppler
|
||||
double doppler;
|
||||
|
||||
/// @brief Target RCS
|
||||
double rcs;
|
||||
|
||||
/// @brief Target ID
|
||||
u_int32_t id;
|
||||
|
||||
public:
|
||||
/// @brief Constructor for targets.
|
||||
/// @return The object.
|
||||
FalseTarget(c4::yml::NodeRef target_node, uint32_t _fs);
|
||||
|
||||
/// @brief Generate the signal from a false target.
|
||||
/// @param buffer Pointer to reference buffer.
|
||||
/// @return Target reflection signal.
|
||||
std::complex<double> process(IqData *buffer);
|
||||
|
||||
/// @brief Getter for target type.
|
||||
/// @return Target type.
|
||||
std::string get_type();
|
||||
|
||||
/// @brief Getter for target range.type
|
||||
/// @return Target range.
|
||||
double get_range();
|
||||
|
||||
/// @brief Getter for target Doppler.
|
||||
/// @return Target Doppler.
|
||||
double get_doppler();
|
||||
|
||||
/// @brief Getter for target RCS.
|
||||
/// @return Target RCS.
|
||||
double get_rcs();
|
||||
|
||||
/// @brief Getter for target delay.
|
||||
/// @return Target delay.
|
||||
double get_delay();
|
||||
|
||||
/// @brief Getter for target id.
|
||||
/// @return Target id.
|
||||
u_int32_t get_id();
|
||||
};
|
||||
|
||||
class TgtGen
|
||||
{
|
||||
private:
|
||||
/// @brief Vector of false targets.
|
||||
std::vector<FalseTarget> targets;
|
||||
|
||||
public:
|
||||
/// @brief The valid false target types.
|
||||
static const std::string VALID_TYPE[1];
|
||||
|
||||
/// @brief The valid false target states.
|
||||
static const std::string VALID_STATE[1];
|
||||
|
||||
/// @brief Constructor.
|
||||
/// @return The object.
|
||||
TgtGen(std::string configPath, uint32_t fs);
|
||||
|
||||
/// @brief Generate the signal from all false targets.
|
||||
/// @param ref_buffer Pointer to reference buffer.
|
||||
/// @return Targets reflection signal.
|
||||
std::complex<double> process(IqData *ref_buffer);
|
||||
};
|
||||
|
||||
#endif
|
||||
std::string ryml_get_file(const char *filename);
|
|
@ -39,6 +39,11 @@ std::deque<std::complex<double>> IqData::get_data()
|
|||
return *data;
|
||||
}
|
||||
|
||||
std::complex<double> IqData::get_sample(int64_t index)
|
||||
{
|
||||
return data->at(index);
|
||||
}
|
||||
|
||||
void IqData::push_back(std::complex<double> sample)
|
||||
{
|
||||
if (data->size() < n)
|
||||
|
|
|
@ -66,6 +66,11 @@ public:
|
|||
/// @return IQ data.
|
||||
std::deque<std::complex<double>> get_data();
|
||||
|
||||
/// @brief Getter for single sample.
|
||||
/// @param index Index of sample.
|
||||
/// @return Sample at index.
|
||||
std::complex<double> get_sample(int64_t index);
|
||||
|
||||
/// @brief Push a sample to the queue.
|
||||
/// @param sample A single sample.
|
||||
/// @return Void.
|
||||
|
|
11
src/utilities/Conversions.cpp
Normal file
11
src/utilities/Conversions.cpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include "Conversions.h"
|
||||
|
||||
double Conversions::db2lin(double db)
|
||||
{
|
||||
return pow(10, db / 10);
|
||||
}
|
||||
|
||||
double Conversions::lin2db(double lin)
|
||||
{
|
||||
return 10 * log10(lin);
|
||||
}
|
27
src/utilities/Conversions.h
Normal file
27
src/utilities/Conversions.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/// @file Conversions.h
|
||||
/// @class Conversions
|
||||
/// @brief A class to convert between different units.
|
||||
|
||||
/// @author bennysomers
|
||||
/// @todo Add more conversions
|
||||
|
||||
#ifndef CONVERSIONS_H
|
||||
#define CONVERSIONS_H
|
||||
|
||||
#include <math.h>
|
||||
|
||||
class Conversions
|
||||
{
|
||||
public:
|
||||
/// @brief Convert from dB to linear.
|
||||
/// @param db Value in dB.
|
||||
/// @return Value in linear.
|
||||
static double db2lin(double db);
|
||||
|
||||
/// @brief Convert from linear to dB.
|
||||
/// @param lin Value in linear.
|
||||
/// @return Value in dB.
|
||||
static double lin2db(double lin);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue