From dc16aa478ff213f45fb601653c97cbe2d230cae9 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 11 Apr 2016 11:50:03 -0700 Subject: [PATCH] OOK slicer, clock recovery classes. --- firmware/baseband/ook.hpp | 93 +++++++++++++++++++++++++ firmware/baseband/phase_accumulator.hpp | 50 +++++++++++++ firmware/baseband/phase_detector.hpp | 68 ++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 firmware/baseband/ook.hpp create mode 100644 firmware/baseband/phase_accumulator.hpp create mode 100644 firmware/baseband/phase_detector.hpp diff --git a/firmware/baseband/ook.hpp b/firmware/baseband/ook.hpp new file mode 100644 index 00000000..27333922 --- /dev/null +++ b/firmware/baseband/ook.hpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. + * + * This file is part of PortaPack. + * + * This program 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 2, or (at your option) + * any later version. + * + * This program 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 this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __OOK_HPP__ +#define __OOK_HPP__ + +#include "phase_detector.hpp" +#include "phase_accumulator.hpp" + +#include +#include +#include +#include + +class OOKSlicerMagSquaredInt { +public: + using symbol_t = bool; + + constexpr OOKSlicerMagSquaredInt( + const float samples_per_symbol + ) : mag2_threshold_leak_factor { + static_cast( + factor_sq(-1.0f / (8.0f * samples_per_symbol)) * float(1ULL << 32) + ) + } + { + } + + symbol_t operator()(const std::complex in) { + const uint32_t real2 = in.real() * in.real(); + const uint32_t imag2 = in.imag() * in.imag(); + const uint32_t mag2 = real2 + imag2; + + const uint32_t mag2_attenuated = mag2 >> 3; // Approximation of (-4.5dB)^2 + mag2_threshold = (uint64_t(mag2_threshold) * uint64_t(mag2_threshold_leak_factor)) >> 32; + mag2_threshold = std::max(mag2_threshold, mag2_attenuated); + const bool symbol = (mag2 > mag2_threshold); + return symbol; + } + +private: + const uint32_t mag2_threshold_leak_factor; + uint32_t mag2_threshold = 0; + + constexpr float factor_sq(float db) { + return std::pow(10.0f, db / (10.0f / 2)); + } +}; + +class OOKClockRecovery { +public: + constexpr OOKClockRecovery( + const float samples_per_symbol + ) : symbol_phase_inc_nominal { static_cast(std::round((1ULL << 32) / samples_per_symbol)) }, + phase_detector { samples_per_symbol }, + phase_accumulator { symbol_phase_inc_nominal } + { + } + + template + void operator()(const uint32_t slicer_history, SymbolHandler symbol_handler) { + if( phase_accumulator() ) { + const auto detector_result = phase_detector(slicer_history); + phase_accumulator.set_inc(symbol_phase_inc_nominal + detector_result.error * (symbol_phase_inc_nominal >> 3)); + symbol_handler(detector_result.symbol); + } + } + +private: + const uint32_t symbol_phase_inc_nominal; + PhaseDetectorEarlyLateGate phase_detector; + PhaseAccumulator phase_accumulator; +}; + +#endif/*__OOK_HPP__*/ diff --git a/firmware/baseband/phase_accumulator.hpp b/firmware/baseband/phase_accumulator.hpp new file mode 100644 index 00000000..bf3b331a --- /dev/null +++ b/firmware/baseband/phase_accumulator.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. + * + * This file is part of PortaPack. + * + * This program 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 2, or (at your option) + * any later version. + * + * This program 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 this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __PHASE_ACCUMULATOR_HPP__ +#define __PHASE_ACCUMULATOR_HPP__ + +#include + +class PhaseAccumulator { +public: + constexpr PhaseAccumulator( + const uint32_t phase_inc + ) : phase_inc { phase_inc } + { + } + + bool operator()() { + const auto last_phase = phase; + phase += phase_inc; + return (phase < last_phase); + } + + void set_inc(const uint32_t new_phase_inc) { + phase_inc = new_phase_inc; + } + +private: + uint32_t phase { 0 }; + uint32_t phase_inc; +}; + +#endif/*__PHASE_ACCUMULATOR_HPP__*/ diff --git a/firmware/baseband/phase_detector.hpp b/firmware/baseband/phase_detector.hpp new file mode 100644 index 00000000..89cf4b5c --- /dev/null +++ b/firmware/baseband/phase_detector.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. + * + * This file is part of PortaPack. + * + * This program 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 2, or (at your option) + * any later version. + * + * This program 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 this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __PHASE_DETECTOR_HPP__ +#define __PHASE_DETECTOR_HPP__ + +#include +#include +#include + +class PhaseDetectorEarlyLateGate { +public: + using history_t = uint32_t; + + using symbol_t = bool; + using error_t = int; + + struct result_t { + symbol_t symbol; + error_t error; + }; + + constexpr PhaseDetectorEarlyLateGate( + const float samples_per_symbol + ) : late_mask { (1U << static_cast(std::ceil(samples_per_symbol / 2))) - 1 }, + early_mask { late_mask << static_cast(std::floor(samples_per_symbol / 2)) }, + sample_bit { static_cast(std::floor(samples_per_symbol / 2)) } + { + } + + result_t operator()(const history_t symbol_history) const { + // history = ...0111, early + // history = ...1110, late + + const symbol_t symbol = (symbol_history >> sample_bit) & 1; + const int late_side = __builtin_popcount(symbol_history & late_mask); + const int early_side = __builtin_popcount(symbol_history & early_mask); + const int lateness = late_side - early_side; + const int direction = lateness; //std::min(std::max(lateness, -1), 1); + const error_t error = direction; + return { symbol, error }; + } + +private: + const history_t late_mask; + const history_t early_mask; + const size_t sample_bit; +}; + +#endif/*__PHASE_DETECTOR_HPP__*/