Spectrum display for IqData meta API

This commit is contained in:
30hours 2023-12-12 14:40:52 +00:00
parent f1576d40b7
commit f842ca0258
7 changed files with 344 additions and 14 deletions

69
api/iqdata.js Normal file
View file

@ -0,0 +1,69 @@
const http = require('http');
var nCpi = 20;
var iqdata = '';
var spectrum = [];
frequency = [];
var timestamp = [];
var detection = '';
var ts = '';
var output = [];
const options_timestamp = {
host: '127.0.0.1',
path: '/api/timestamp',
port: 3000
};
const options_iqdata = {
host: '127.0.0.1',
path: '/api/iqdata',
port: 3000
};
function update_data() {
// check if timestamp is updated
http.get(options_timestamp, function(res) {
res.setEncoding('utf8');
res.on('data', function (body) {
if (ts != body)
{
ts = body;
http.get(options_iqdata, function(res) {
let body_map = '';
res.setEncoding('utf8');
res.on('data', (chunk) => {
body_map += chunk;
});
res.on('end', () => {
try {
output = JSON.parse(body_map);
// spectrum
spectrum.push(output.spectrum);
if (spectrum.length > nCpi) {
spectrum.shift();
}
output.spectrum = spectrum;
// frequency
frequency.push(output.frequency);
if (frequency.length > nCpi) {
frequency.shift();
}
output.frequency = frequency;
} catch (e) {
console.error(e.message);
}
});
});
}
});
});
};
setInterval(update_data, 100);
function get_data() {
return output;
};
module.exports.get_data_iqdata = get_data;

View file

@ -4,6 +4,7 @@ const net = require("net");
var data_map = require('./maxhold.js'); var data_map = require('./maxhold.js');
var data_detection = require('./detection.js'); var data_detection = require('./detection.js');
var data_iqdata = require('./iqdata.js');
// constants // constants
const PORT = 3000; const PORT = 3000;
@ -44,12 +45,18 @@ app.get('/api/timing', (req, res) => {
app.get('/api/iqdata', (req, res) => { app.get('/api/iqdata', (req, res) => {
res.send(iqdata); res.send(iqdata);
}); });
// stash API
app.get('/stash/map', (req, res) => { app.get('/stash/map', (req, res) => {
res.send(data_map.get_data_map()); res.send(data_map.get_data_map());
}); });
app.get('/stash/detection', (req, res) => { app.get('/stash/detection', (req, res) => {
res.send(data_detection.get_data_detection()); res.send(data_detection.get_data_detection());
}); });
app.get('/stash/iqdata', (req, res) => {
res.send(data_iqdata.get_data_iqdata());
});
// read state of capture // read state of capture
app.get('/capture', (req, res) => { app.get('/capture', (req, res) => {
res.send(capture); res.send(capture);

View file

@ -108,6 +108,7 @@
<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/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/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>
<li class="py-1"><a class="text-reset text-decoration-none" href="/display/spectrum">Spectrum reference</a></li>
</ul> </ul>
</div> </div>
@ -127,6 +128,7 @@
<li class="py-1 title">Stash</li> <li class="py-1 title">Stash</li>
<li class="py-1"><a class="text-reset text-decoration-none" href="/stash/map">Map data</a></li> <li class="py-1"><a class="text-reset text-decoration-none" href="/stash/map">Map data</a></li>
<li class="py-1"><a class="text-reset text-decoration-none" href="/stash/detection">Detection data</a></li> <li class="py-1"><a class="text-reset text-decoration-none" href="/stash/detection">Detection data</a></li>
<li class="py-1"><a class="text-reset text-decoration-none" href="/stash/iqdata">IqData metadata</a></li>
</ul> </ul>
</div> </div>

View file

@ -0,0 +1,109 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>blah2</title>
<!-- load lib js -->
<script src="../../lib/bootstrap-5.2.3.min.js"></script>
<script src="../../lib/plotly-2.20.0.min.js"></script>
<script src="../../lib/jquery-3.6.4.min.js"></script>
<!-- load lib css -->
<link rel="stylesheet" href="../../lib/bootstrap-5.2.3.min.css">
<style>
h1 {
font-family: 'Helvetica', sans-serif !important;
font-weight: bold;
font-size: 3.5rem !important;
}
.menu {
font-family: 'Helvetica', sans-serif !important;
font-size: 1.5rem;
font-weight: bold;
}
.title {
font-family: 'Helvetica', sans-serif !important;
font-size: 1.5rem;
font-weight: bold;
text-decoration: underline;
}
.label {
font-family: 'Helvetica', sans-serif !important;
font-size: 1rem;
}
@media (min-width: 768px) {
h1 {
font-family: 'Helvetica', sans-serif !important;
font-weight: bold;
font-size: 5rem !important;
}
.menu {
font-family: 'Helvetica', sans-serif !important;
font-size: 2rem;
}
.title {
font-family: 'Helvetica', sans-serif !important;
font-size: 2.5rem;
font-weight: bold;
text-decoration: underline;
}
.label {
font-family: 'Helvetica', sans-serif !important;
font-size: 2rem;
}
}
.navbar-nav {
flex-wrap: wrap;
}
div.plotly-notifier {
visibility: hidden;
}
</style>
</head>
<body style="background-color:#f78c58;">
<div style="height: 100vh; width: 95vw" class="container-fluid">
<div style="height: 100vh; width: 95vw" class="row d-flex">
<div class="justify-content-center" id="data"></div>
</div>
</body>
<script>
var host = window.location.hostname;
var isLocalHost = (host === "localhost" || host === "127.0.0.1" || host === "192.168.0.112");
var urlMap = ''
if (isLocalHost) {
urlMap = '//' + host + ':3000/stash/iqdata?timestamp=' + Date.now();
} else {
urlMap = '//' + host + '/stash/iqdata?timestamp=' + Date.now();
}
</script>
<script src="../../js/plot_spectrum.js"></script>
</html>

124
html/js/plot_spectrum.js Normal file
View file

@ -0,0 +1,124 @@
var timestamp = -1;
var nRows = 3;
var host = window.location.hostname;
var isLocalHost = (host === "localhost" || host === "127.0.0.1" || host === "192.168.0.112");
var range_x = [];
var range_y = [];
// setup API
var urlTimestamp = '';
if (isLocalHost) {
urlTimestamp = '//' + host + ':3000/api/timestamp?timestamp=' + Date.now();
} else {
urlTimestamp = '//' + host + '/api/timestamp?timestamp=' + Date.now();
}
// setup plotly
var layout = {
autosize: true,
margin: {
l: 50,
r: 50,
b: 50,
t: 10,
pad: 0
},
hoverlabel: {
namelength: 0
},
plot_bgcolor: "rgba(0,0,0,0)",
paper_bgcolor: "rgba(0,0,0,0)",
annotations: [],
displayModeBar: false,
xaxis: {
title: {
text: 'Frequency (MHz)',
font: {
size: 24
}
},
ticks: '',
side: 'bottom'
},
yaxis: {
title: {
text: 'Timestamp',
font: {
size: 24
}
},
ticks: '',
ticksuffix: ' ',
autosize: false,
categoryorder: "total descending"
}
};
var config = {
responsive: true,
displayModeBar: false
//scrollZoom: true
}
// setup plotly data
var data = [
{
z: [[0, 0, 0], [0, 0, 0], [0, 0, 0]],
colorscale: 'Jet',
type: 'heatmap'
}
];
var detection = [];
Plotly.newPlot('data', data, layout, config);
// callback function
var intervalId = window.setInterval(function () {
// check if timestamp is updated
var timestampData = $.get(urlTimestamp, function () { })
.done(function (data) {
if (timestamp != data) {
timestamp = data;
// get new map data
var apiData = $.getJSON(urlMap, function () { })
.done(function (data) {
// case draw new plot
if (data.nRows != nRows) {
nRows = data.nRows;
var trace1 = {
z: data.spectrum,
colorscale: 'Jet',
zauto: false,
//zmin: 0,
//zmax: Math.max(13, data.maxPower),
type: 'heatmap'
};
var data_trace = [trace1];
Plotly.newPlot('data', data_trace, layout, config);
}
// case update plot
else {
var trace_update = {
z: [data.spectrum]
//zmax: [Math.max(13, data.maxPower), []]
};
Plotly.update('data', trace_update);
}
})
.fail(function () {
})
.always(function () {
});
}
})
.fail(function () {
})
.always(function () {
});
}, 100);

View file

@ -14,7 +14,8 @@ SpectrumAnalyser::SpectrumAnalyser(uint32_t _n, double _bandwidth)
// compute nfft // compute nfft
decimation = n/bandwidth; decimation = n/bandwidth;
nfft = n/decimation; nSpectrum = n/decimation;
nfft = nSpectrum*decimation;
// compute FFTW plans in constructor // compute FFTW plans in constructor
dataX = new std::complex<double>[nfft]; dataX = new std::complex<double>[nfft];
@ -29,26 +30,41 @@ SpectrumAnalyser::~SpectrumAnalyser()
void SpectrumAnalyser::process(IqData *x) void SpectrumAnalyser::process(IqData *x)
{ {
// decimate // load data and FFT
int16_t iData = 0;
std::deque<std::complex<double>> data = x->get_data(); 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++) for (int i = 0; i < nfft; i++)
{ {
spectrum.push_back(dataX[i]); dataX[i] = data[i];
}
fftw_execute(fftX);
// fftshift
std::vector<std::complex<double>> fftshift;
for (int i = 0; i < nfft; i++)
{
fftshift.push_back(dataX[(i + int(nfft / 2) + 1) % nfft]);
}
// decimate
std::vector<std::complex<double>> spectrum;
for (int i = 0; i < nfft; i+=decimation)
{
spectrum.push_back(fftshift[i]);
} }
x->update_spectrum(spectrum); x->update_spectrum(spectrum);
// update frequency // update frequency
std::vector<double> frequency;
double offset = 0;
if (decimation % 2 == 0)
{
offset = bandwidth/2;
}
for (int i = -nSpectrum/2; i < nSpectrum/2; i++)
{
frequency.push_back(((i*bandwidth)+offset+204640000)/1000);
}
x->update_frequency(frequency);
return; return;
} }

View file

@ -33,6 +33,9 @@ private:
/// @brief Number of samples to perform FFT. /// @brief Number of samples to perform FFT.
uint32_t nfft; uint32_t nfft;
/// @brief Number of samples in decimated spectrum.
uint32_t nSpectrum;
/// @brief Resolution of spectrum (Hz). /// @brief Resolution of spectrum (Hz).
double resolution; double resolution;