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) | 
