I'm a little lost again
This commit is contained in:
parent
010e479f89
commit
cfbbacdd0f
@ -22,8 +22,9 @@ static constexpr double SCALE_FACTOR = 32767.0;
|
|||||||
class PSKModulator {
|
class PSKModulator {
|
||||||
public:
|
public:
|
||||||
PSKModulator(const double _sample_rate, const bool _is_frequency_hopping, const size_t _num_taps)
|
PSKModulator(const double _sample_rate, const bool _is_frequency_hopping, const size_t _num_taps)
|
||||||
: sample_rate(validateSampleRate(_sample_rate)), gain(1.0/sqrt(2.0)), is_frequency_hopping(_is_frequency_hopping), samples_per_symbol(static_cast<size_t>(sample_rate / SYMBOL_RATE)), phase_detector(symbolMap), srrc_filter(48, _sample_rate, SYMBOL_RATE, ROLLOFF_FACTOR) {
|
: sample_rate(validateSampleRate(_sample_rate)), gain(1.0/sqrt(2.0)), is_frequency_hopping(_is_frequency_hopping), samples_per_symbol(static_cast<size_t>(sample_rate / SYMBOL_RATE)), srrc_filter(48, _sample_rate, SYMBOL_RATE, ROLLOFF_FACTOR) {
|
||||||
initializeSymbolMap();
|
initializeSymbolMap();
|
||||||
|
phase_detector = PhaseDetector(symbolMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int16_t> modulate(const std::vector<uint8_t>& symbols) {
|
std::vector<int16_t> modulate(const std::vector<uint8_t>& symbols) {
|
||||||
@ -78,7 +79,7 @@ public:
|
|||||||
|
|
||||||
std::vector<uint8_t> demodulate(const std::vector<int16_t> passband_signal) {
|
std::vector<uint8_t> demodulate(const std::vector<int16_t> passband_signal) {
|
||||||
// Carrier recovery. initialize the Costas loop.
|
// Carrier recovery. initialize the Costas loop.
|
||||||
CostasLoop costas_loop(sample_rate, symbolMap);
|
CostasLoop costas_loop(CARRIER_FREQ, sample_rate, symbolMap, 5.0);
|
||||||
|
|
||||||
// Convert passband signal to doubles.
|
// Convert passband signal to doubles.
|
||||||
std::vector<double> normalized_passband(passband_signal.size());
|
std::vector<double> normalized_passband(passband_signal.size());
|
||||||
@ -91,8 +92,17 @@ public:
|
|||||||
|
|
||||||
// Phase detection and symbol formation
|
// Phase detection and symbol formation
|
||||||
std::vector<uint8_t> baseband_symbols;
|
std::vector<uint8_t> baseband_symbols;
|
||||||
for (size_t i = 0; i < baseband_IQ.size(); i++) {
|
size_t samples_per_symbol = sample_rate / SYMBOL_RATE;
|
||||||
baseband_symbols.emplace_back(phase_detector.getSymbol(baseband_IQ[i]));
|
|
||||||
|
for (size_t i = 0; i < baseband_IQ.size(); i += samples_per_symbol) {
|
||||||
|
std::complex<double> symbol_avg(0.0, 0.0);
|
||||||
|
for (size_t j = 0; j < samples_per_symbol; ++j) {
|
||||||
|
symbol_avg += baseband_IQ[i + j];
|
||||||
|
}
|
||||||
|
symbol_avg /= static_cast<double>(samples_per_symbol);
|
||||||
|
|
||||||
|
// Detect symbol from averaged signal
|
||||||
|
baseband_symbols.emplace_back(phase_detector.getSymbol(symbol_avg));
|
||||||
}
|
}
|
||||||
|
|
||||||
return baseband_symbols;
|
return baseband_symbols;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
class PhaseDetector {
|
class PhaseDetector {
|
||||||
public:
|
public:
|
||||||
|
PhaseDetector() {}
|
||||||
PhaseDetector(const std::vector<std::complex<double>>& _symbolMap) : symbolMap(_symbolMap) {}
|
PhaseDetector(const std::vector<std::complex<double>>& _symbolMap) : symbolMap(_symbolMap) {}
|
||||||
|
|
||||||
uint8_t getSymbol(const std::complex<double>& input) {
|
uint8_t getSymbol(const std::complex<double>& input) {
|
||||||
@ -38,8 +39,8 @@ private:
|
|||||||
|
|
||||||
class CostasLoop {
|
class CostasLoop {
|
||||||
public:
|
public:
|
||||||
CostasLoop(const double _sample_rate, const std::vector<std::complex<double>>& _symbolMap)
|
CostasLoop(const double _carrier_freq, const double _sample_rate, const std::vector<std::complex<double>>& _symbolMap, const double _vco_gain)
|
||||||
: sample_rate(_sample_rate), k_factor(-5 / _sample_rate),
|
: carrier_freq(_carrier_freq), sample_rate(_sample_rate), vco_gain(_vco_gain), k_factor(-1 / (_sample_rate * _vco_gain)),
|
||||||
prev_in_iir(0), prev_out_iir(0), prev_in_vco(0), feedback(1.0, 0.0),
|
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),
|
error_total(0), out_iir_total(0), in_vco_total(0),
|
||||||
srrc_filter(SRRCFilter(48, _sample_rate, 2400, 0.35)) {}
|
srrc_filter(SRRCFilter(48, _sample_rate, 2400, 0.35)) {}
|
||||||
@ -80,15 +81,19 @@ public:
|
|||||||
prev_in_vco = in_vco;
|
prev_in_vco = in_vco;
|
||||||
|
|
||||||
// Generate feedback signal for next iteration
|
// Generate feedback signal for next iteration
|
||||||
double feedback_real = std::cos(k_factor * in_vco);
|
double feedback_real = std::cos(current_phase);
|
||||||
double feedback_imag = -std::sin(k_factor * in_vco);
|
double feedback_imag = -std::sin(current_phase);
|
||||||
feedback = std::complex<double>(feedback_real, feedback_imag);
|
feedback = std::complex<double>(feedback_real, feedback_imag);
|
||||||
|
|
||||||
|
current_phase += 2 * M_PI * carrier_freq / sample_rate + k_factor * in_vco;
|
||||||
|
if (current_phase > 2 * M_PI) current_phase -= 2 * M_PI;
|
||||||
}
|
}
|
||||||
|
|
||||||
return output_signal;
|
return output_signal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
double carrier_freq;
|
||||||
double sample_rate;
|
double sample_rate;
|
||||||
double k_factor;
|
double k_factor;
|
||||||
double prev_in_iir;
|
double prev_in_iir;
|
||||||
@ -99,6 +104,7 @@ private:
|
|||||||
double out_iir_total;
|
double out_iir_total;
|
||||||
double in_vco_total;
|
double in_vco_total;
|
||||||
SRRCFilter srrc_filter;
|
SRRCFilter srrc_filter;
|
||||||
|
double vco_gain;
|
||||||
|
|
||||||
std::complex<double> limiter(const std::complex<double>& sample) const {
|
std::complex<double> limiter(const std::complex<double>& sample) const {
|
||||||
double limited_I = std::clamp(sample.real(), -1.0, 1.0);
|
double limited_I = std::clamp(sample.real(), -1.0, 1.0);
|
||||||
|
42
main.cpp
42
main.cpp
@ -6,6 +6,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "ModemController.h"
|
#include "ModemController.h"
|
||||||
|
#include "PSKModulator.h"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// Sample test data
|
// Sample test data
|
||||||
@ -16,37 +17,40 @@ int main() {
|
|||||||
BitStream input_data(sample_data, sample_data.size() * 8);
|
BitStream input_data(sample_data, sample_data.size() * 8);
|
||||||
|
|
||||||
// Configuration for modem
|
// Configuration for modem
|
||||||
size_t baud_rate = 300;
|
size_t baud_rate = 150;
|
||||||
bool is_voice = false; // False indicates data mode
|
bool is_voice = false; // False indicates data mode
|
||||||
bool is_frequency_hopping = false; // Fixed frequency operation
|
bool is_frequency_hopping = false; // Fixed frequency operation
|
||||||
size_t interleave_setting = 1; // Short interleave
|
size_t interleave_setting = 1; // Short interleave
|
||||||
|
|
||||||
// Create ModemController instance
|
// Create ModemController instance
|
||||||
ModemController modem(baud_rate, is_voice, is_frequency_hopping, interleave_setting, input_data);
|
ModemController modem(baud_rate, is_voice, is_frequency_hopping, interleave_setting, input_data);
|
||||||
|
PSKModulator modulator(48000, is_frequency_hopping, 48);
|
||||||
|
|
||||||
const char* file_name = "modulated_signal_600bps_shortinterleave.wav";
|
const char* file_name = "modulated_signal_75bps_shortinterleave.wav";
|
||||||
|
|
||||||
// Perform transmit operation to generate modulated signal
|
// Perform transmit operation to generate modulated signal
|
||||||
std::vector<int16_t> modulated_signal = modem.transmit();
|
std::vector<int16_t> modulated_signal = modem.transmit();
|
||||||
|
|
||||||
// Output modulated signal to a WAV file using libsndfile
|
std::vector<uint8_t> demodulated_symbols = modulator.demodulate(modulated_signal);
|
||||||
SF_INFO sfinfo;
|
|
||||||
sfinfo.channels = 1;
|
|
||||||
sfinfo.samplerate = 48000;
|
|
||||||
sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
|
|
||||||
|
|
||||||
SNDFILE* sndfile = sf_open(file_name, SFM_WRITE, &sfinfo);
|
//// Output modulated signal to a WAV file using libsndfile
|
||||||
if (sndfile == nullptr) {
|
//SF_INFO sfinfo;
|
||||||
std::cerr << "Unable to open WAV file for writing modulated signal: " << sf_strerror(sndfile) << "\n";
|
//sfinfo.channels = 1;
|
||||||
return 1;
|
//sfinfo.samplerate = 48000;
|
||||||
}
|
//sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
|
||||||
|
//
|
||||||
sf_write_short(sndfile, modulated_signal.data(), modulated_signal.size());
|
//SNDFILE* sndfile = sf_open(file_name, SFM_WRITE, &sfinfo);
|
||||||
sf_close(sndfile);
|
//if (sndfile == nullptr) {
|
||||||
std::cout << "Modulated signal written to " << file_name << '\n';
|
// std::cerr << "Unable to open WAV file for writing modulated signal: " << sf_strerror(sndfile) << "\n";
|
||||||
|
// return 1;
|
||||||
// Success message
|
//}
|
||||||
std::cout << "Modem test completed successfully.\n";
|
//
|
||||||
|
//sf_write_short(sndfile, modulated_signal.data(), modulated_signal.size());
|
||||||
|
//sf_close(sndfile);
|
||||||
|
//std::cout << "Modulated signal written to " << file_name << '\n';
|
||||||
|
//
|
||||||
|
//// Success message
|
||||||
|
//std::cout << "Modem test completed successfully.\n";
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -26,14 +26,38 @@ TEST_F(PSKModulatorTest, ModulationOutputLength) {
|
|||||||
|
|
||||||
TEST_F(PSKModulatorTest, DemodulationOutput) {
|
TEST_F(PSKModulatorTest, DemodulationOutput) {
|
||||||
auto passband_signal = modulator.modulate(symbols);
|
auto passband_signal = modulator.modulate(symbols);
|
||||||
|
|
||||||
|
// Debug: Print modulated passband signal
|
||||||
|
std::cout << "Modulated Passband Signal: ";
|
||||||
|
for (const auto& sample : passband_signal) {
|
||||||
|
std::cout << sample << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
auto decoded_symbols = modulator.demodulate(passband_signal);
|
auto decoded_symbols = modulator.demodulate(passband_signal);
|
||||||
|
|
||||||
|
// Debug: Print decoded symbols
|
||||||
|
std::cout << "Decoded Symbols: ";
|
||||||
|
for (const auto& symbol : decoded_symbols) {
|
||||||
|
std::cout << (int)symbol << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// Debug: Print expected symbols
|
||||||
|
std::cout << "Expected Symbols: ";
|
||||||
|
for (const auto& symbol : symbols) {
|
||||||
|
std::cout << (int)symbol << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
ASSERT_EQ(symbols.size(), decoded_symbols.size());
|
ASSERT_EQ(symbols.size(), decoded_symbols.size());
|
||||||
|
|
||||||
for (size_t i = 0; i < symbols.size(); i++) {
|
for (size_t i = 0; i < symbols.size(); i++) {
|
||||||
EXPECT_EQ(symbols[i], decoded_symbols[i]);
|
EXPECT_EQ(symbols[i], decoded_symbols[i]) << " at index " << i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_F(PSKModulatorTest, InvalidSymbolInput) {
|
TEST_F(PSKModulatorTest, InvalidSymbolInput) {
|
||||||
std::vector<uint8_t> invalid_symbols = {0, 8, 9};
|
std::vector<uint8_t> invalid_symbols = {0, 8, 9};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user