diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2015-11-06 17:55:46 +0100 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2015-11-06 17:55:46 +0100 |
commit | 823043497a9fd59ac86e9596c56df8e692340974 (patch) | |
tree | 0cba1739c400ae4c2d2c22549f99157ca25d7d24 | |
parent | ff7a3d92d6192f6dd201ef165978b1d3df3815b6 (diff) | |
download | odr-dpd-823043497a9fd59ac86e9596c56df8e692340974.tar.gz odr-dpd-823043497a9fd59ac86e9596c56df8e692340974.tar.bz2 odr-dpd-823043497a9fd59ac86e9596c56df8e692340974.zip |
Move AlignSample to separate file
-rw-r--r-- | AlignSample.cpp | 156 | ||||
-rw-r--r-- | AlignSample.hpp | 98 | ||||
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | main.cpp | 176 | ||||
-rw-r--r-- | utils.hpp | 6 |
5 files changed, 262 insertions, 175 deletions
diff --git a/AlignSample.cpp b/AlignSample.cpp new file mode 100644 index 0000000..d2d9339 --- /dev/null +++ b/AlignSample.cpp @@ -0,0 +1,156 @@ +/* + Copyright (C) 2015 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org + */ +/* + This file is part of ODR-DPD. + + ODR-DPD 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 3 of the + License, or (at your option) any later version. + + ODR-DPD 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 ODR-DPD. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "AlignSample.hpp" + +void AlignSample::push_tx_samples(complexf* samps, size_t len, double first_sample_time) +{ + std::lock_guard<std::mutex> lock(m_mutex); + std::copy(samps, samps + len, std::back_inserter(m_txsamples)); + + if (m_first_tx_sample_time == 0) { + m_first_tx_sample_time = first_sample_time; + } +} + +void AlignSample::push_rx_samples(complexf* samps, size_t len, double first_sample_time) +{ + std::lock_guard<std::mutex> lock(m_mutex); + std::copy(samps, samps + len, std::back_inserter(m_rxsamples)); + + if (m_first_rx_sample_time == 0) { + m_first_rx_sample_time = first_sample_time; + } +} + +bool AlignSample::ready(size_t min_samples) +{ + std::lock_guard<std::mutex> lock(m_mutex); + return align() and m_rxsamples.size() > min_samples and m_txsamples.size() > min_samples; +} + +CorrelationResult AlignSample::crosscorrelate(size_t max_offset, size_t len) +{ + std::vector<complexf> rxsamps; + std::vector<complexf> txsamps; + double rx_ts = 0; + double tx_ts = 0; + + // Do a quick copy, so as to free the mutex + { + std::lock_guard<std::mutex> lock(m_mutex); + + if (!align() or + m_rxsamples.size() < len or + m_txsamples.size() < len + max_offset) { + CorrelationResult result(0); + return result; + } + + std::copy(m_rxsamples.begin(), m_rxsamples.begin() + len, std::back_inserter(rxsamps)); + std::copy(m_txsamples.begin(), m_txsamples.begin() + len + max_offset, std::back_inserter(txsamps)); + + m_rxsamples.erase(m_rxsamples.begin(), m_rxsamples.begin() + len); + m_txsamples.erase(m_txsamples.begin(), m_txsamples.begin() + len + max_offset); + + rx_ts = m_rx_sample_time(); + tx_ts = m_tx_sample_time(); + } + + CorrelationResult result(max_offset); + result.rx_timestamp = rx_ts; + result.tx_timestamp = tx_ts; + + auto& xcorrs = result.correlation; + + // Calculate power + for (auto sample : rxsamps) { + result.rx_power += std::norm(sample); + } + result.rx_power = std::sqrt(result.rx_power); + + for (auto sample : txsamps) { + result.tx_power += std::norm(sample); + } + result.tx_power = std::sqrt(result.tx_power); + + // Calculate correlation + for (size_t offset = 0; offset < max_offset; offset++) { + complexf xcorr(0, 0); + + for (size_t i = 0; i < len; i++) { + xcorr += rxsamps[i] * std::conj(txsamps[i+offset]); + } + xcorrs[offset] = xcorr; + } + + return result; +} + +void AlignSample::consume(size_t samples) +{ + std::lock_guard<std::mutex> lock(m_mutex); + if (align() and m_rxsamples.size() > samples and m_txsamples.size() > samples) { + m_rxsamples.erase(m_rxsamples.begin(), m_rxsamples.begin() + samples); + m_num_rx_samples_dropped += samples; + + m_txsamples.erase(m_txsamples.begin(), m_txsamples.begin() + samples); + m_num_tx_samples_dropped += samples; + } +} + +bool AlignSample::align() +{ + if (std::abs(m_rx_sample_time() - m_tx_sample_time()) < 1e-6) { + return true; + } + else if (m_rx_sample_time() < m_tx_sample_time()) { + size_t rx_samples_to_skip = + (m_tx_sample_time() - m_rx_sample_time()) * samplerate; + + if (rx_samples_to_skip > m_rxsamples.size()) { + return false; + } + + m_rxsamples.erase( + m_rxsamples.begin(), m_rxsamples.begin() + rx_samples_to_skip); + + m_num_rx_samples_dropped += rx_samples_to_skip; + return true; + } + else if (m_rx_sample_time() > m_tx_sample_time()) { + size_t tx_samples_to_skip = + (m_rx_sample_time() - m_tx_sample_time()) * samplerate; + + if (tx_samples_to_skip > m_txsamples.size()) { + return false; + } + + m_txsamples.erase( + m_txsamples.begin(), m_txsamples.begin() + tx_samples_to_skip); + + m_num_tx_samples_dropped += tx_samples_to_skip; + return true; + } + return false; +} diff --git a/AlignSample.hpp b/AlignSample.hpp new file mode 100644 index 0000000..31b5de2 --- /dev/null +++ b/AlignSample.hpp @@ -0,0 +1,98 @@ +/* + Copyright (C) 2015 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org + */ +/* + This file is part of ODR-DPD. + + ODR-DPD 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 3 of the + License, or (at your option) any later version. + + ODR-DPD 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 ODR-DPD. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "utils.hpp" +#include <thread> +#include <vector> +#include <deque> +#include <mutex> +#include <complex> + +typedef std::complex<float> complexf; + +struct CorrelationResult { + CorrelationResult(size_t len) : + correlation(len), + rx_power(0), + tx_power(0), + rx_timestamp(0), + tx_timestamp(0) {} + + std::vector<complexf> correlation; + double rx_power; + double tx_power; + + double rx_timestamp; + double tx_timestamp; +}; + +class AlignSample { + public: + AlignSample() { + m_first_rx_sample_time = 0; + m_first_tx_sample_time = 0; + m_num_rx_samples_dropped = 0; + m_num_tx_samples_dropped = 0; + } + + void push_tx_samples(complexf* samps, size_t len, double first_sample_time); + + void push_rx_samples(complexf* samps, size_t len, double first_sample_time); + + bool ready(size_t min_samples); + + void debug() { + std::lock_guard<std::mutex> lock(m_mutex); + MDEBUG("Aligner\n"); + MDEBUG(" RX: %f %zu\n", m_rx_sample_time(), m_rxsamples.size()); + MDEBUG(" TX: %f %zu\n", m_tx_sample_time(), m_txsamples.size()); + } + + CorrelationResult crosscorrelate(size_t max_offset, size_t len); + + void consume(size_t samples); + + private: + bool align(); + + double m_rx_sample_time() const { + return m_first_rx_sample_time + + (double)m_num_rx_samples_dropped / samplerate; + } + + double m_tx_sample_time() const { + return m_first_tx_sample_time + + (double)m_num_tx_samples_dropped / samplerate; + } + + std::mutex m_mutex; + double m_first_rx_sample_time; + size_t m_num_rx_samples_dropped; + std::deque<complexf> m_rxsamples; + + double m_first_tx_sample_time; + size_t m_num_tx_samples_dropped; + std::deque<complexf> m_txsamples; +}; + + diff --git a/CMakeLists.txt b/CMakeLists.txt index e4a53a0..891b853 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,7 @@ find_package(Threads REQUIRED) list(APPEND odrdpd_sources main.cpp OutputUHD.cpp + AlignSample.cpp ) list(APPEND common_link_list ${UHD_LIBRARIES} ${ZMQ_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) @@ -22,6 +22,7 @@ */ #include "OutputUHD.hpp" +#include "AlignSample.hpp" #include "utils.hpp" #include <zmq.hpp> #include <thread> @@ -39,9 +40,6 @@ void sig_int_handler(int) { running = false; } -const size_t samps_per_buffer = 20480; -const size_t samplerate = 2048000; - size_t read_samples(FILE* fd, std::vector<complexf>& samples, size_t count) { if (samples.size() < count) { @@ -58,178 +56,6 @@ size_t read_samples(FILE* fd, std::vector<complexf>& samples, size_t count) return num_read; } -struct CorrelationResult { - CorrelationResult(size_t len) : - correlation(len), - rx_power(0), - tx_power(0), - rx_timestamp(0), - tx_timestamp(0) {} - - std::vector<complexf> correlation; - double rx_power; - double tx_power; - - double rx_timestamp; - double tx_timestamp; -}; - -class AlignSample { - public: - AlignSample() { - m_first_rx_sample_time = 0; - m_first_tx_sample_time = 0; - m_num_rx_samples_dropped = 0; - m_num_tx_samples_dropped = 0; - } - - void push_tx_samples(complexf* samps, size_t len, double first_sample_time) { - std::lock_guard<std::mutex> lock(m_mutex); - std::copy(samps, samps + len, std::back_inserter(m_txsamples)); - - if (m_first_tx_sample_time == 0) { - m_first_tx_sample_time = first_sample_time; - } - } - - void push_rx_samples(complexf* samps, size_t len, double first_sample_time) { - std::lock_guard<std::mutex> lock(m_mutex); - std::copy(samps, samps + len, std::back_inserter(m_rxsamples)); - - if (m_first_rx_sample_time == 0) { - m_first_rx_sample_time = first_sample_time; - } - } - - bool ready(size_t min_samples) { - std::lock_guard<std::mutex> lock(m_mutex); - return align() and m_rxsamples.size() > min_samples and m_txsamples.size() > min_samples; - } - - void debug() { - std::lock_guard<std::mutex> lock(m_mutex); - MDEBUG("Aligner\n"); - MDEBUG(" RX: %f %zu\n", m_rx_sample_time(), m_rxsamples.size()); - MDEBUG(" TX: %f %zu\n", m_tx_sample_time(), m_txsamples.size()); - } - - CorrelationResult crosscorrelate(size_t max_offset, size_t len) { - std::vector<complexf> rxsamps; - std::vector<complexf> txsamps; - double rx_ts = 0; - double tx_ts = 0; - - // Do a quick copy, so as to free the mutex - { - std::lock_guard<std::mutex> lock(m_mutex); - - if (!align() or - m_rxsamples.size() < len or - m_txsamples.size() < len + max_offset) { - CorrelationResult result(0); - return result; - } - - std::copy(m_rxsamples.begin(), m_rxsamples.begin() + len, std::back_inserter(rxsamps)); - std::copy(m_txsamples.begin(), m_txsamples.begin() + len + max_offset, std::back_inserter(txsamps)); - - m_rxsamples.erase(m_rxsamples.begin(), m_rxsamples.begin() + len); - m_txsamples.erase(m_txsamples.begin(), m_txsamples.begin() + len + max_offset); - - rx_ts = m_rx_sample_time(); - tx_ts = m_tx_sample_time(); - } - - CorrelationResult result(max_offset); - result.rx_timestamp = rx_ts; - result.tx_timestamp = tx_ts; - - auto& xcorrs = result.correlation; - - // Calculate power - for (auto sample : rxsamps) { - result.rx_power += std::norm(sample); - } - result.rx_power = std::sqrt(result.rx_power); - - for (auto sample : txsamps) { - result.tx_power += std::norm(sample); - } - result.tx_power = std::sqrt(result.tx_power); - - // Calculate correlation - for (size_t offset = 0; offset < max_offset; offset++) { - complexf xcorr(0, 0); - - for (size_t i = 0; i < len; i++) { - xcorr += rxsamps[i] * std::conj(txsamps[i+offset]); - } - xcorrs[offset] = xcorr; - } - - return result; - } - - void consume(size_t samples) - { - std::lock_guard<std::mutex> lock(m_mutex); - if (align() and m_rxsamples.size() > samples and m_txsamples.size() > samples) { - m_rxsamples.erase(m_rxsamples.begin(), m_rxsamples.begin() + samples); - m_num_rx_samples_dropped += samples; - - m_txsamples.erase(m_txsamples.begin(), m_txsamples.begin() + samples); - m_num_tx_samples_dropped += samples; - } - } - - private: - bool align() { - if (std::abs(m_rx_sample_time() - m_tx_sample_time()) < 1e-6) { - return true; - } - else if (m_rx_sample_time() < m_tx_sample_time()) { - size_t rx_samples_to_skip = (m_tx_sample_time() - m_rx_sample_time()) * samplerate; - - if (rx_samples_to_skip > m_rxsamples.size()) { - return false; - } - - m_rxsamples.erase(m_rxsamples.begin(), m_rxsamples.begin() + rx_samples_to_skip); - m_num_rx_samples_dropped += rx_samples_to_skip; - return true; - } - else if (m_rx_sample_time() > m_tx_sample_time()) { - size_t tx_samples_to_skip = (m_rx_sample_time() - m_tx_sample_time()) * samplerate; - - if (tx_samples_to_skip > m_txsamples.size()) { - return false; - } - - m_txsamples.erase(m_txsamples.begin(), m_txsamples.begin() + tx_samples_to_skip); - m_num_tx_samples_dropped += tx_samples_to_skip; - return true; - } - return false; - } - - double m_rx_sample_time() { - return m_first_rx_sample_time + (double)m_num_rx_samples_dropped / samplerate; - } - - double m_tx_sample_time() { - return m_first_tx_sample_time + (double)m_num_tx_samples_dropped / samplerate; - } - - std::mutex m_mutex; - double m_first_rx_sample_time; - size_t m_num_rx_samples_dropped; - std::deque<complexf> m_rxsamples; - - double m_first_tx_sample_time; - size_t m_num_tx_samples_dropped; - std::deque<complexf> m_txsamples; -}; - AlignSample aligner; size_t do_receive(OutputUHD* output_uhd) @@ -1,5 +1,11 @@ #ifndef __UTILS_H_ +#include <cstddef> + +const size_t samps_per_buffer = 20480; +const size_t samplerate = 2048000; + + #include <cstdio> #define MDEBUG(fmt, args...) fprintf (stderr, fmt , ## args) |