mirror of
https://github.com/30hours/blah2.git
synced 2024-11-08 12:25:42 +00:00
Add spectrum processing and API
This commit is contained in:
parent
386c65280e
commit
f1576d40b7
10 changed files with 244 additions and 2 deletions
|
@ -24,6 +24,7 @@ add_executable(blah2
|
|||
${PROJECT_SOURCE_DIR}/process/detection/CfarDetector1D.cpp
|
||||
${PROJECT_SOURCE_DIR}/process/detection/Centroid.cpp
|
||||
${PROJECT_SOURCE_DIR}/process/detection/Interpolate.cpp
|
||||
${PROJECT_SOURCE_DIR}/process/spectrum/SpectrumAnalyser.cpp
|
||||
${PROJECT_SOURCE_DIR}/data/IqData.cpp
|
||||
${PROJECT_SOURCE_DIR}/data/Map.cpp
|
||||
${PROJECT_SOURCE_DIR}/data/Detection.cpp
|
||||
|
@ -67,5 +68,6 @@ include_directories("${PROJECT_SOURCE_DIR}/capture/rspduo/")
|
|||
include_directories("${PROJECT_SOURCE_DIR}/process/ambiguity/")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/process/clutter/")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/process/detection/")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/process/spectrum/")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/data/")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/data/meta/")
|
||||
|
|
|
@ -12,6 +12,7 @@ var map = '';
|
|||
var detection = '';
|
||||
var timestamp = '';
|
||||
var timing = '';
|
||||
var iqdata = '';
|
||||
var data = '';
|
||||
var capture = false;
|
||||
|
||||
|
@ -40,6 +41,9 @@ app.get('/api/timestamp', (req, res) => {
|
|||
app.get('/api/timing', (req, res) => {
|
||||
res.send(timing);
|
||||
});
|
||||
app.get('/api/iqdata', (req, res) => {
|
||||
res.send(iqdata);
|
||||
});
|
||||
app.get('/stash/map', (req, res) => {
|
||||
res.send(data_map.get_data_map());
|
||||
});
|
||||
|
@ -123,3 +127,20 @@ const server_timing = net.createServer((socket)=>{
|
|||
})
|
||||
});
|
||||
server_timing.listen(4001);
|
||||
|
||||
// tcp listener iqdata metadata
|
||||
const server_iqdata = net.createServer((socket)=>{
|
||||
socket.write("Hello From Server!")
|
||||
socket.on("data",(msg)=>{
|
||||
data = data + msg.toString();
|
||||
if (data.slice(-1) === "}")
|
||||
{
|
||||
iqdata = data;
|
||||
data = '';
|
||||
}
|
||||
});
|
||||
socket.on("close",()=>{
|
||||
console.log("Connection closed.");
|
||||
})
|
||||
});
|
||||
server_iqdata.listen(4002);
|
||||
|
|
|
@ -36,6 +36,7 @@ network:
|
|||
detection: 3002
|
||||
timestamp: 4000
|
||||
timing: 4001
|
||||
iqdata: 4002
|
||||
|
||||
save:
|
||||
iq: true
|
||||
|
|
|
@ -36,6 +36,7 @@ network:
|
|||
detection: 3002
|
||||
timestamp: 4000
|
||||
timing: 4001
|
||||
iqdata: 4002
|
||||
|
||||
save:
|
||||
iq: true
|
||||
|
|
|
@ -107,7 +107,7 @@
|
|||
<li class="py-1"><a class="text-reset text-decoration-none" href="/display/maxhold">Max-hold delay Doppler map</a></li>
|
||||
<li class="py-1"><a class="text-reset text-decoration-none" href="/display/detection/delay">Detections in delay over time</a></li>
|
||||
<li class="py-1"><a class="text-reset text-decoration-none" href="/display/detection/doppler">Detections in Doppler over time</a></li>
|
||||
<li class="py-1"><a class="text-reset text-decoration-none" href="/display/detection/delay-Doppler">Detections in delay-Doppler over time</a></li>
|
||||
<li class="py-1"><a class="text-reset text-decoration-none" href="/display/detection/delay-doppler">Detections in delay-Doppler over time</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
@ -117,6 +117,7 @@
|
|||
<li class="py-1"><a class="text-reset text-decoration-none" href="/api/map">Map data</a></li>
|
||||
<li class="py-1"><a class="text-reset text-decoration-none" href="/api/detection">Detection data</a></li>
|
||||
<li class="py-1"><a class="text-reset text-decoration-none" href="/api/timing">Timing data</a></li>
|
||||
<li class="py-1"><a class="text-reset text-decoration-none" href="/api/iqdata">IQ metadata</a></li>
|
||||
<li class="py-1"><a class="text-reset text-decoration-none" href="/api/timestamp">Latest timestamp</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <Centroid.h>
|
||||
#include <Interpolate.h>
|
||||
#include <Timing.h>
|
||||
#include <SpectrumAnalyser.h>
|
||||
#include <sys/types.h>
|
||||
#include <getopt.h>
|
||||
#include <string>
|
||||
|
@ -100,22 +101,25 @@ int main(int argc, char **argv)
|
|||
fftw_plan_with_nthreads(4);
|
||||
|
||||
// setup socket
|
||||
uint16_t port_map, port_detection, port_timestamp, port_timing;
|
||||
uint16_t port_map, port_detection, port_timestamp, port_timing, port_iqdata;
|
||||
std::string ip;
|
||||
tree["network"]["ports"]["map"] >> port_map;
|
||||
tree["network"]["ports"]["detection"] >> port_detection;
|
||||
tree["network"]["ports"]["timestamp"] >> port_timestamp;
|
||||
tree["network"]["ports"]["timing"] >> port_timing;
|
||||
tree["network"]["ports"]["iqdata"] >> port_iqdata;
|
||||
tree["network"]["ip"] >> ip;
|
||||
asio::io_service io_service;
|
||||
asio::ip::tcp::socket socket_map(io_service);
|
||||
asio::ip::tcp::socket socket_detection(io_service);
|
||||
asio::ip::tcp::socket socket_timestamp(io_service);
|
||||
asio::ip::tcp::socket socket_timing(io_service);
|
||||
asio::ip::tcp::socket socket_iqdata(io_service);
|
||||
asio::ip::tcp::endpoint endpoint_map;
|
||||
asio::ip::tcp::endpoint endpoint_detection;
|
||||
asio::ip::tcp::endpoint endpoint_timestamp;
|
||||
asio::ip::tcp::endpoint endpoint_timing;
|
||||
asio::ip::tcp::endpoint endpoint_iqdata;
|
||||
endpoint_map = asio::ip::tcp::endpoint(
|
||||
asio::ip::address::from_string(ip), port_map);
|
||||
endpoint_detection = asio::ip::tcp::endpoint(
|
||||
|
@ -124,10 +128,13 @@ int main(int argc, char **argv)
|
|||
asio::ip::address::from_string(ip), port_timestamp);
|
||||
endpoint_timing = asio::ip::tcp::endpoint(
|
||||
asio::ip::address::from_string(ip), port_timing);
|
||||
endpoint_iqdata = asio::ip::tcp::endpoint(
|
||||
asio::ip::address::from_string(ip), port_iqdata);
|
||||
socket_map.connect(endpoint_map);
|
||||
socket_detection.connect(endpoint_detection);
|
||||
socket_timestamp.connect(endpoint_timestamp);
|
||||
socket_timing.connect(endpoint_timing);
|
||||
socket_iqdata.connect(endpoint_iqdata);
|
||||
asio::error_code err;
|
||||
std::string subdata;
|
||||
uint32_t MTU = 1024;
|
||||
|
@ -165,6 +172,10 @@ int main(int argc, char **argv)
|
|||
tree["process"]["detection"]["nCentroid"] >> nCentroid;
|
||||
Centroid *centroid = new Centroid(nCentroid, nCentroid, 1/tCpi);
|
||||
|
||||
// setup process spectrum analyser
|
||||
double spectrumBandwidth = 2000;
|
||||
SpectrumAnalyser *spectrumAnalyser = new SpectrumAnalyser(nSamples, spectrumBandwidth);
|
||||
|
||||
// setup output data
|
||||
bool saveMap;
|
||||
tree["save"]["map"] >> saveMap;
|
||||
|
@ -189,6 +200,9 @@ int main(int argc, char **argv)
|
|||
std::vector<double> timing_time;
|
||||
std::string jsonTiming;
|
||||
|
||||
// setup output signal
|
||||
std::string jsonIqData;
|
||||
|
||||
// run process
|
||||
std::thread t2([&]{
|
||||
while (true)
|
||||
|
@ -212,6 +226,9 @@ int main(int argc, char **argv)
|
|||
timing_name.push_back("extract_buffer");
|
||||
timing_time.push_back(delta_t1);
|
||||
|
||||
// spectrum
|
||||
spectrumAnalyser->process(x);
|
||||
|
||||
// clutter filter
|
||||
if (!filter->process(x, y))
|
||||
{
|
||||
|
@ -240,6 +257,14 @@ int main(int argc, char **argv)
|
|||
timing_name.push_back("detector");
|
||||
timing_time.push_back(delta_t4);
|
||||
|
||||
// output IqData meta data
|
||||
jsonIqData = x->to_json(t0/1000);
|
||||
for (int i = 0; i < (jsonIqData.size() + MTU - 1) / MTU; i++)
|
||||
{
|
||||
subdata = jsonIqData.substr(i * MTU, MTU);
|
||||
socket_iqdata.write_some(asio::buffer(subdata, subdata.size()), err);
|
||||
}
|
||||
|
||||
// output map data
|
||||
mapJson = map->to_json();
|
||||
mapJson = map->delay_bin_to_km(mapJson, fs);
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
|
||||
// constructor
|
||||
IqData::IqData(uint32_t _n)
|
||||
{
|
||||
|
@ -71,4 +76,49 @@ void IqData::clear()
|
|||
{
|
||||
data->pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
void IqData::update_spectrum(std::vector<std::complex<double>> _spectrum)
|
||||
{
|
||||
spectrum = _spectrum;
|
||||
}
|
||||
|
||||
void IqData::update_frequency(std::vector<double> _frequency)
|
||||
{
|
||||
frequency = _frequency;
|
||||
}
|
||||
|
||||
std::string IqData::to_json(uint64_t timestamp)
|
||||
{
|
||||
rapidjson::Document document;
|
||||
document.SetObject();
|
||||
rapidjson::Document::AllocatorType &allocator = document.GetAllocator();
|
||||
|
||||
// store frequency array
|
||||
rapidjson::Value arrayFrequency(rapidjson::kArrayType);
|
||||
for (int i = 0; i < frequency.size(); i++)
|
||||
{
|
||||
arrayFrequency.PushBack(frequency[i], allocator);
|
||||
}
|
||||
|
||||
// store spectrum array
|
||||
rapidjson::Value arraySpectrum(rapidjson::kArrayType);
|
||||
for (int i = 0; i < spectrum.size(); i++)
|
||||
{
|
||||
arraySpectrum.PushBack(10 * std::log10(std::abs(spectrum[i])), allocator);
|
||||
}
|
||||
|
||||
document.AddMember("timestamp", timestamp, allocator);
|
||||
document.AddMember("min", min, allocator);
|
||||
document.AddMember("max", max, allocator);
|
||||
document.AddMember("mean", mean, allocator);
|
||||
document.AddMember("frequency", arrayFrequency, allocator);
|
||||
document.AddMember("spectrum", arraySpectrum, allocator);
|
||||
|
||||
rapidjson::StringBuffer strbuf;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(strbuf);
|
||||
writer.SetMaxDecimalPlaces(2);
|
||||
document.Accept(writer);
|
||||
|
||||
return strbuf.GetString();
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
#include <complex>
|
||||
#include <mutex>
|
||||
|
||||
|
@ -24,6 +25,21 @@ private:
|
|||
/// @brief Pointer to IQ data.
|
||||
std::deque<std::complex<double>> *data;
|
||||
|
||||
/// @brief Minimum value.
|
||||
double min;
|
||||
|
||||
/// @brief Maximum value.
|
||||
double max;
|
||||
|
||||
/// @brief Mean value.
|
||||
double mean;
|
||||
|
||||
/// @brief Spectrum vector.
|
||||
std::vector<std::complex<double>> spectrum;
|
||||
|
||||
/// @brief Frequency vector (Hz).
|
||||
std::vector<double> frequency;
|
||||
|
||||
public:
|
||||
/// @brief Constructor.
|
||||
/// @param n Number of samples.
|
||||
|
@ -66,6 +82,21 @@ public:
|
|||
/// @brief Clear samples from the queue.
|
||||
/// @return Void.
|
||||
void clear();
|
||||
|
||||
/// @brief Update the time differences and names.
|
||||
/// @param spectrum Spectrum vector.
|
||||
/// @return Void.
|
||||
void update_spectrum(std::vector<std::complex<double>> spectrum);
|
||||
|
||||
/// @brief Update the time differences and names.
|
||||
/// @param frequency Frequency vector.
|
||||
/// @return Void.
|
||||
void update_frequency(std::vector<double> frequency);
|
||||
|
||||
/// @brief Generate JSON of the signal and metadata.
|
||||
/// @param timestamp Current time (POSIX ms).
|
||||
/// @return JSON string.
|
||||
std::string to_json(uint64_t timestamp);
|
||||
};
|
||||
|
||||
#endif
|
54
src/process/spectrum/SpectrumAnalyser.cpp
Normal file
54
src/process/spectrum/SpectrumAnalyser.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
#include "SpectrumAnalyser.h"
|
||||
#include <complex>
|
||||
#include <iostream>
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
#include <math.h>
|
||||
|
||||
// constructor
|
||||
SpectrumAnalyser::SpectrumAnalyser(uint32_t _n, double _bandwidth)
|
||||
{
|
||||
// input
|
||||
n = _n;
|
||||
bandwidth = _bandwidth;
|
||||
|
||||
// compute nfft
|
||||
decimation = n/bandwidth;
|
||||
nfft = n/decimation;
|
||||
|
||||
// compute FFTW plans in constructor
|
||||
dataX = new std::complex<double>[nfft];
|
||||
fftX = fftw_plan_dft_1d(nfft, reinterpret_cast<fftw_complex *>(dataX),
|
||||
reinterpret_cast<fftw_complex *>(dataX), FFTW_FORWARD, FFTW_ESTIMATE);
|
||||
}
|
||||
|
||||
SpectrumAnalyser::~SpectrumAnalyser()
|
||||
{
|
||||
fftw_destroy_plan(fftX);
|
||||
}
|
||||
|
||||
void SpectrumAnalyser::process(IqData *x)
|
||||
{
|
||||
// decimate
|
||||
int16_t iData = 0;
|
||||
std::deque<std::complex<double>> data = x->get_data();
|
||||
for (int i = 0; i < x->get_length(); i+=decimation)
|
||||
{
|
||||
dataX[iData] = data[i];
|
||||
iData++;
|
||||
}
|
||||
|
||||
fftw_execute(fftX);
|
||||
|
||||
// update spectrum
|
||||
std::vector<std::complex<double>> spectrum;
|
||||
for (int i = 0; i < nfft; i++)
|
||||
{
|
||||
spectrum.push_back(dataX[i]);
|
||||
}
|
||||
x->update_spectrum(spectrum);
|
||||
|
||||
// update frequency
|
||||
|
||||
return;
|
||||
}
|
56
src/process/spectrum/SpectrumAnalyser.h
Normal file
56
src/process/spectrum/SpectrumAnalyser.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/// @file SpectrumAnalyser.h
|
||||
/// @class SpectrumAnalyser
|
||||
/// @brief A class to generate frequency spectrum plots.
|
||||
/// @details Simple decimate and FFT on CPI IQ data for frequency spectrum.
|
||||
/// @author 30hours
|
||||
/// @todo Potentially create k spectrum plots from sub-CPIs.
|
||||
|
||||
#ifndef SPECTRUMANALYSER_H
|
||||
#define SPECTRUMANALYSER_H
|
||||
|
||||
#include <IqData.h>
|
||||
#include <stdint.h>
|
||||
#include <fftw3.h>
|
||||
|
||||
class SpectrumAnalyser
|
||||
{
|
||||
private:
|
||||
/// @brief Number of samples on input.
|
||||
uint32_t n;
|
||||
|
||||
/// @brief Minimum bandwidth of frequency bin (Hz).
|
||||
double bandwidth;
|
||||
|
||||
/// @brief Decimation factor.
|
||||
uint32_t decimation;
|
||||
|
||||
/// @brief FFTW plans for ambiguity processing.
|
||||
fftw_plan fftX;
|
||||
|
||||
/// @brief FFTW storage for ambiguity processing.
|
||||
std::complex<double> *dataX;
|
||||
|
||||
/// @brief Number of samples to perform FFT.
|
||||
uint32_t nfft;
|
||||
|
||||
/// @brief Resolution of spectrum (Hz).
|
||||
double resolution;
|
||||
|
||||
public:
|
||||
/// @brief Constructor.
|
||||
/// @param n Number of samples on input.
|
||||
/// @param bandwidth Minimum bandwidth of frequency bin (Hz).
|
||||
/// @return The object.
|
||||
SpectrumAnalyser(uint32_t n, double bandwidth);
|
||||
|
||||
/// @brief Destructor.
|
||||
/// @return Void.
|
||||
~SpectrumAnalyser();
|
||||
|
||||
/// @brief Process spectrum data.
|
||||
/// @param x Reference samples.
|
||||
/// @return Void.
|
||||
void process(IqData *x);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue