#include #include #include #include #include "filters.h" class PhaseDetector { public: PhaseDetector() {} PhaseDetector(const std::vector>& _symbolMap) : symbolMap(_symbolMap) {} uint8_t getSymbol(const std::complex& input) { double phase = std::atan2(input.imag(), input.real()); return symbolFromPhase(phase); } private: std::vector> symbolMap; uint8_t symbolFromPhase(const double phase) { // Calculate the closest symbol based on phase difference double min_distance = 2 * M_PI; // Maximum possible phase difference uint8_t closest_symbol = 0; for (uint8_t i = 0; i < symbolMap.size(); ++i) { double symbol_phase = std::atan2(symbolMap[i].imag(), symbolMap[i].real()); double distance = std::abs(symbol_phase - phase); if (distance < min_distance) { min_distance = distance; closest_symbol = i; } } return closest_symbol; } }; class CostasLoop { public: CostasLoop(const double _carrier_freq, const double _sample_rate, const std::vector>& _symbolMap, const double _vco_gain, const double _alpha, const double _beta) : carrier_freq(_carrier_freq), sample_rate(_sample_rate), vco_gain(_vco_gain), alpha(_alpha), beta(_beta), freq_error(0.0), k_factor(-1 / (_sample_rate * _vco_gain)), prev_in_iir(0), prev_out_iir(0), prev_in_vco(0), feedback(1.0, 0.0), error_total(0), out_iir_total(0), in_vco_total(0), srrc_filter(SRRCFilter(48, _sample_rate, 2400, 0.35)) {} std::vector> process(const std::vector& input_signal) { std::vector> output_signal(input_signal.size()); double current_phase = 0.0; error_total = 0; out_iir_total = 0; in_vco_total = 0; for (size_t i = 0; i < input_signal.size(); ++i) { // Multiply input by feedback signal std::complex multiplied = input_signal[i] * feedback; // Filter signal std::complex filtered = srrc_filter.filterSample(multiplied); // Output best-guess corrected I/Q components output_signal[i] = filtered; // Generate limited components std::complex limited = limiter(filtered); // IIR Filter double error_real = (limited.real() > 0 ? 1.0 : -1.0) * limited.imag(); double error_imag = (limited.imag() > 0 ? 1.0 : -1.0) * limited.real(); double phase_error = error_real - error_imag; phase_error = 0.5 * (std::abs(phase_error + 1) - std::abs(phase_error - 1)); freq_error += beta * phase_error; double phase_adjust = alpha * phase_error + freq_error; current_phase += 2 * M_PI * carrier_freq / sample_rate + k_factor * phase_adjust; if (current_phase > M_PI) current_phase -= 2 * M_PI; else if (current_phase < -M_PI) current_phase += 2 * M_PI; // Generate feedback signal for next iteration double feedback_real = std::cos(current_phase); double feedback_imag = -std::sin(current_phase); feedback = std::complex(feedback_real, feedback_imag); } return output_signal; } private: double carrier_freq; double sample_rate; double k_factor; double prev_in_iir; double prev_out_iir; double prev_in_vco; std::complex feedback; double error_total; double out_iir_total; double in_vco_total; SRRCFilter srrc_filter; double vco_gain; double alpha; double beta; double freq_error; std::complex limiter(const std::complex& sample) const { double limited_I = std::clamp(sample.real(), -1.0, 1.0); double limited_Q = std::clamp(sample.imag(), -1.0, 1.0); return std::complex(limited_I, limited_Q); } };