#pragma once // Requires: nlohmann/json (header-only), libcurl #include #include #include #include #include #include #include namespace sigtera { enum class DataType { iq, spectrogram }; inline std::string to_string(DataType v) { switch (v) { case DataType::iq: return "iq"; case DataType::spectrogram: return "spectrogram"; } return ""; } enum class Format { raw_float32, raw_float64, wav }; inline std::string to_string(Format v) { switch (v) { case Format::raw_float32: return "raw_float32"; case Format::raw_float64: return "raw_float64"; case Format::wav: return "wav"; } return ""; } enum class SelfInterferenceCancelation { True, False }; inline std::string to_string(SelfInterferenceCancelation v) { switch (v) { case SelfInterferenceCancelation::True: return "True"; case SelfInterferenceCancelation::False: return "False"; } return ""; } enum class Signal { tone, psk, iridium, ook, ask, fsk, dpsk, qam, ofdm }; inline std::string to_string(Signal v) { switch (v) { case Signal::tone: return "tone"; case Signal::psk: return "psk"; case Signal::iridium: return "iridium"; case Signal::ook: return "ook"; case Signal::ask: return "ask"; case Signal::fsk: return "fsk"; case Signal::dpsk: return "dpsk"; case Signal::qam: return "qam"; case Signal::ofdm: return "ofdm"; } return ""; } enum class DataGenerator { random, specify_bits, file }; inline std::string to_string(DataGenerator v) { switch (v) { case DataGenerator::random: return "random"; case DataGenerator::specify_bits: return "specify_bits"; case DataGenerator::file: return "file"; } return ""; } struct _ReceiverBase { virtual nlohmann::json to_json() const = 0; virtual ~_ReceiverBase() = default; }; struct NbTone { double pre_padding = 0; double post_padding = 0; double power = -2; double center_frequency = 0; double duration = 0.1; double phase = 0; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "tone"; j["pre-padding"] = pre_padding; j["post-padding"] = post_padding; j["power"] = power; j["center_frequency"] = center_frequency; j["duration"] = duration; j["phase"] = phase; return j; } }; struct NbPsk { double pre_padding = 0; double post_padding = 0; double power = -2; double center_frequency = 0; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; int modulation_order = 4; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "psk"; j["pre-padding"] = pre_padding; j["post-padding"] = post_padding; j["power"] = power; j["center_frequency"] = center_frequency; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["modulation_order"] = modulation_order; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct NbIridium { double pre_padding = 0; double post_padding = 0; double power = -2; double center_frequency = 0; int slot_index = 0; double sample_rate = 100000; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; double duration = 0.1; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "iridium"; j["pre-padding"] = pre_padding; j["post-padding"] = post_padding; j["power"] = power; j["center_frequency"] = center_frequency; j["slot_index"] = slot_index; j["sample_rate"] = sample_rate; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["duration"] = duration; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct NbOok { double pre_padding = 0; double post_padding = 0; double power = -2; double center_frequency = 0; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "ook"; j["pre-padding"] = pre_padding; j["post-padding"] = post_padding; j["power"] = power; j["center_frequency"] = center_frequency; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct NbAsk { double pre_padding = 0; double post_padding = 0; double power = -2; double center_frequency = 0; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; int modulation_order = 2; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "ask"; j["pre-padding"] = pre_padding; j["post-padding"] = post_padding; j["power"] = power; j["center_frequency"] = center_frequency; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["modulation_order"] = modulation_order; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct NbFsk { double pre_padding = 0; double post_padding = 0; double power = -2; double center_frequency = 0; int modulation_order = 4; double baud = 4800; int samples_per_symbol = 8; double freq_sep = 1000; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "fsk"; j["pre-padding"] = pre_padding; j["post-padding"] = post_padding; j["power"] = power; j["center_frequency"] = center_frequency; j["modulation_order"] = modulation_order; j["baud"] = baud; j["samples_per_symbol"] = samples_per_symbol; j["freq_sep"] = freq_sep; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct NbDpsk { double pre_padding = 0; double post_padding = 0; double power = -2; double center_frequency = 0; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "dpsk"; j["pre-padding"] = pre_padding; j["post-padding"] = post_padding; j["power"] = power; j["center_frequency"] = center_frequency; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct NbQam { double pre_padding = 0; double post_padding = 0; double power = -2; double center_frequency = 0; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; int modulation_order = 16; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "qam"; j["pre-padding"] = pre_padding; j["post-padding"] = post_padding; j["power"] = power; j["center_frequency"] = center_frequency; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["modulation_order"] = modulation_order; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct NbOfdm { double pre_padding = 0; double post_padding = 0; double power = -2; double center_frequency = 0; int num_subcarriers = 64; int fft_size = 64; int cyclic_prefix_length = 16; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "ofdm"; j["pre-padding"] = pre_padding; j["post-padding"] = post_padding; j["power"] = power; j["center_frequency"] = center_frequency; j["num_subcarriers"] = num_subcarriers; j["fft_size"] = fft_size; j["cyclic_prefix_length"] = cyclic_prefix_length; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct WbTone { double power = -2; double center_frequency = 0; double signal_start_time = 0; double duration = 0.1; double phase = 0; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "tone"; j["power"] = power; j["center_frequency"] = center_frequency; j["signal_start_time"] = signal_start_time; j["duration"] = duration; j["phase"] = phase; return j; } }; struct WbPsk { double power = -2; double center_frequency = 0; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; double signal_start_time = 0; int modulation_order = 4; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "psk"; j["power"] = power; j["center_frequency"] = center_frequency; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["signal_start_time"] = signal_start_time; j["modulation_order"] = modulation_order; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct WbIridium { double power = -2; double center_frequency = 0; int slot_index = 0; double sample_rate = 100000; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; double signal_start_time = 0; double duration = 0.1; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "iridium"; j["power"] = power; j["center_frequency"] = center_frequency; j["slot_index"] = slot_index; j["sample_rate"] = sample_rate; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["signal_start_time"] = signal_start_time; j["duration"] = duration; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct WbOok { double power = -2; double center_frequency = 0; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; double signal_start_time = 0; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "ook"; j["power"] = power; j["center_frequency"] = center_frequency; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["signal_start_time"] = signal_start_time; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct WbAsk { double power = -2; double center_frequency = 0; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; double signal_start_time = 0; int modulation_order = 2; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "ask"; j["power"] = power; j["center_frequency"] = center_frequency; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["signal_start_time"] = signal_start_time; j["modulation_order"] = modulation_order; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct WbFsk { double power = -2; double center_frequency = 0; double signal_start_time = 0; int modulation_order = 4; double baud = 4800; int samples_per_symbol = 8; double freq_sep = 1000; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "fsk"; j["power"] = power; j["center_frequency"] = center_frequency; j["signal_start_time"] = signal_start_time; j["modulation_order"] = modulation_order; j["baud"] = baud; j["samples_per_symbol"] = samples_per_symbol; j["freq_sep"] = freq_sep; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct WbDpsk { double power = -2; double center_frequency = 0; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; double signal_start_time = 0; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "dpsk"; j["power"] = power; j["center_frequency"] = center_frequency; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["signal_start_time"] = signal_start_time; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct WbQam { double power = -2; double center_frequency = 0; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; double signal_start_time = 0; int modulation_order = 16; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "qam"; j["power"] = power; j["center_frequency"] = center_frequency; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["signal_start_time"] = signal_start_time; j["modulation_order"] = modulation_order; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct WbOfdm { double power = -2; double center_frequency = 0; double signal_start_time = 0; int num_subcarriers = 64; int fft_size = 64; int cyclic_prefix_length = 16; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "ofdm"; j["power"] = power; j["center_frequency"] = center_frequency; j["signal_start_time"] = signal_start_time; j["num_subcarriers"] = num_subcarriers; j["fft_size"] = fft_size; j["cyclic_prefix_length"] = cyclic_prefix_length; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; class _Narrowband : public _ReceiverBase { public: DataType data_type = DataType::iq; Format format = Format::raw_float32; int noise = -10; double sample_rate = 100000; _Narrowband& Tone(NbTone p = {}) { signals_.push_back(p.to_json()); return *this; } _Narrowband& Psk(NbPsk p = {}) { signals_.push_back(p.to_json()); return *this; } _Narrowband& Iridium(NbIridium p = {}) { signals_.push_back(p.to_json()); return *this; } _Narrowband& Ook(NbOok p = {}) { signals_.push_back(p.to_json()); return *this; } _Narrowband& Ask(NbAsk p = {}) { signals_.push_back(p.to_json()); return *this; } _Narrowband& Fsk(NbFsk p = {}) { signals_.push_back(p.to_json()); return *this; } _Narrowband& Dpsk(NbDpsk p = {}) { signals_.push_back(p.to_json()); return *this; } _Narrowband& Qam(NbQam p = {}) { signals_.push_back(p.to_json()); return *this; } _Narrowband& Ofdm(NbOfdm p = {}) { signals_.push_back(p.to_json()); return *this; } nlohmann::json to_json() const override { nlohmann::json j, sigs = nlohmann::json::array(); j["mode"] = "dataset_generation"; j["segmentation"] = "narrowband"; j["data_type"] = to_string(data_type); j["format"] = to_string(format); j["noise"] = noise; j["sample_rate"] = sample_rate; for (auto& s : signals_) sigs.push_back(s); j["signal"] = sigs; return j; } private: std::vector signals_; }; class _Wideband : public _ReceiverBase { public: DataType data_type = DataType::iq; Format format = Format::raw_float32; int noise = -10; double length = 10; double sample_rate = 100000; _Wideband& Tone(WbTone p = {}) { signals_.push_back(p.to_json()); return *this; } _Wideband& Psk(WbPsk p = {}) { signals_.push_back(p.to_json()); return *this; } _Wideband& Iridium(WbIridium p = {}) { signals_.push_back(p.to_json()); return *this; } _Wideband& Ook(WbOok p = {}) { signals_.push_back(p.to_json()); return *this; } _Wideband& Ask(WbAsk p = {}) { signals_.push_back(p.to_json()); return *this; } _Wideband& Fsk(WbFsk p = {}) { signals_.push_back(p.to_json()); return *this; } _Wideband& Dpsk(WbDpsk p = {}) { signals_.push_back(p.to_json()); return *this; } _Wideband& Qam(WbQam p = {}) { signals_.push_back(p.to_json()); return *this; } _Wideband& Ofdm(WbOfdm p = {}) { signals_.push_back(p.to_json()); return *this; } nlohmann::json to_json() const override { nlohmann::json j, sigs = nlohmann::json::array(); j["mode"] = "dataset_generation"; j["segmentation"] = "wideband"; j["data_type"] = to_string(data_type); j["format"] = to_string(format); j["noise"] = noise; j["length"] = length; j["sample_rate"] = sample_rate; for (auto& s : signals_) sigs.push_back(s); j["signal"] = sigs; return j; } private: std::vector signals_; }; struct EnvTxTone { double power = -2; double center_frequency = 0; double transmitter_start_time = 0; double duration = 0.1; double phase = 0; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "tone"; j["power"] = power; j["center_frequency"] = center_frequency; j["transmitter_start_time"] = transmitter_start_time; j["duration"] = duration; j["phase"] = phase; return j; } }; struct EnvTxPsk { double power = -2; double center_frequency = 0; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; double transmitter_start_time = 0; int modulation_order = 4; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "psk"; j["power"] = power; j["center_frequency"] = center_frequency; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["transmitter_start_time"] = transmitter_start_time; j["modulation_order"] = modulation_order; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct EnvTxIridium { double power = -2; double center_frequency = 0; int slot_index = 0; double sample_rate = 100000; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; double transmitter_start_time = 0; double duration = 0.1; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "iridium"; j["power"] = power; j["center_frequency"] = center_frequency; j["slot_index"] = slot_index; j["sample_rate"] = sample_rate; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["transmitter_start_time"] = transmitter_start_time; j["duration"] = duration; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct EnvTxOok { double power = -2; double center_frequency = 0; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; double transmitter_start_time = 0; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "ook"; j["power"] = power; j["center_frequency"] = center_frequency; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["transmitter_start_time"] = transmitter_start_time; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct EnvTxAsk { double power = -2; double center_frequency = 0; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; double transmitter_start_time = 0; int modulation_order = 2; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "ask"; j["power"] = power; j["center_frequency"] = center_frequency; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["transmitter_start_time"] = transmitter_start_time; j["modulation_order"] = modulation_order; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct EnvTxFsk { double power = -2; double center_frequency = 0; double transmitter_start_time = 0; int modulation_order = 4; double baud = 4800; int samples_per_symbol = 8; double freq_sep = 1000; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "fsk"; j["power"] = power; j["center_frequency"] = center_frequency; j["transmitter_start_time"] = transmitter_start_time; j["modulation_order"] = modulation_order; j["baud"] = baud; j["samples_per_symbol"] = samples_per_symbol; j["freq_sep"] = freq_sep; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct EnvTxDpsk { double power = -2; double center_frequency = 0; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; double transmitter_start_time = 0; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "dpsk"; j["power"] = power; j["center_frequency"] = center_frequency; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["transmitter_start_time"] = transmitter_start_time; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct EnvTxQam { double power = -2; double center_frequency = 0; int samples_per_symbol = 8; std::string pulse_shape = "rectangle"; int pulse_shape_span = 6; double pulse_shape_rolloff = 0.35; double transmitter_start_time = 0; int modulation_order = 16; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "qam"; j["power"] = power; j["center_frequency"] = center_frequency; j["samples_per_symbol"] = samples_per_symbol; j["pulse_shape"] = pulse_shape; j["pulse_shape_span"] = pulse_shape_span; j["pulse_shape_rolloff"] = pulse_shape_rolloff; j["transmitter_start_time"] = transmitter_start_time; j["modulation_order"] = modulation_order; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct EnvTxOfdm { double power = -2; double center_frequency = 0; double transmitter_start_time = 0; int num_subcarriers = 64; int fft_size = 64; int cyclic_prefix_length = 16; double baud = 4800; DataGenerator data_generator = DataGenerator::random; int n_bits = 8192; std::string bits = "1010101"; std::string input_file = ""; nlohmann::json to_json() const { nlohmann::json j; j["signal"] = "ofdm"; j["power"] = power; j["center_frequency"] = center_frequency; j["transmitter_start_time"] = transmitter_start_time; j["num_subcarriers"] = num_subcarriers; j["fft_size"] = fft_size; j["cyclic_prefix_length"] = cyclic_prefix_length; j["baud"] = baud; j["data_generator"] = to_string(data_generator); j["n_bits"] = n_bits; j["bits"] = bits; j["input_file"] = input_file; return j; } }; struct _EnvReceiver { DataType data_type = DataType::iq; Format format = Format::raw_float32; int noise = -10; double sample_rate = 100000; nlohmann::json to_json() const { nlohmann::json j; j["element"] = "receiver"; j["data_type"] = to_string(data_type); j["format"] = to_string(format); j["noise"] = noise; j["sample_rate"] = sample_rate; return j; } }; class _EnvTransmitter { public: _EnvTransmitter& Tone(EnvTxTone p = {}) { sig_ = p.to_json(); return *this; } _EnvTransmitter& Psk(EnvTxPsk p = {}) { sig_ = p.to_json(); return *this; } _EnvTransmitter& Iridium(EnvTxIridium p = {}) { sig_ = p.to_json(); return *this; } _EnvTransmitter& Ook(EnvTxOok p = {}) { sig_ = p.to_json(); return *this; } _EnvTransmitter& Ask(EnvTxAsk p = {}) { sig_ = p.to_json(); return *this; } _EnvTransmitter& Fsk(EnvTxFsk p = {}) { sig_ = p.to_json(); return *this; } _EnvTransmitter& Dpsk(EnvTxDpsk p = {}) { sig_ = p.to_json(); return *this; } _EnvTransmitter& Qam(EnvTxQam p = {}) { sig_ = p.to_json(); return *this; } _EnvTransmitter& Ofdm(EnvTxOfdm p = {}) { sig_ = p.to_json(); return *this; } nlohmann::json to_json() const { nlohmann::json j; j["element"] = "transmitter"; if (!sig_.is_null()) { for (auto& [k, v] : sig_.items()) j[k] = v; } return j; } private: nlohmann::json sig_; }; class _EnvPlatform { public: double position_x = 0; double position_y = 0; double position_z = 0; SelfInterferenceCancelation self_interference_cancelation = SelfInterferenceCancelation::True; _EnvPlatform& Receiver(_EnvReceiver p = {}) { elements_.push_back(p.to_json()); return *this; } _EnvPlatform& Transmitter(_EnvTransmitter p = {}) { elements_.push_back(p.to_json()); return *this; } nlohmann::json to_json() const { nlohmann::json j, elems = nlohmann::json::array(); j["platform"] = "platform"; j["position_x"] = position_x; j["position_y"] = position_y; j["position_z"] = position_z; j["self_interference_cancelation"] = to_string(self_interference_cancelation); for (auto& e : elements_) elems.push_back(e); j["element"] = elems; return j; } private: std::vector elements_; }; class _Environment : public _ReceiverBase { public: double length = 10; double speed_of_propagation = 300000000.0; double path_loss_exponent = 2; _Environment& Platform(_EnvPlatform p = {}) { platforms_.push_back(p.to_json()); return *this; } nlohmann::json to_json() const override { nlohmann::json j, plats = nlohmann::json::array(); j["mode"] = "environment_simulation"; j["length"] = length; j["speed_of_propagation"] = speed_of_propagation; j["path_loss_exponent"] = path_loss_exponent; for (auto& p : platforms_) plats.push_back(p); j["platform"] = plats; return j; } private: std::vector platforms_; }; struct Frame { nlohmann::json params; std::vector data; }; class Client { public: explicit Client(std::string url = "https://api.sigtera.com") : url_(std::move(url)) {} _Narrowband& narrowband() { auto p = std::make_unique<_Narrowband>(); auto& ref = *p; requests_.push_back(std::move(p)); return ref; } _Wideband& wideband() { auto p = std::make_unique<_Wideband>(); auto& ref = *p; requests_.push_back(std::move(p)); return ref; } _Environment& environment() { auto p = std::make_unique<_Environment>(); auto& ref = *p; requests_.push_back(std::move(p)); return ref; } std::vector simulate() { std::vector out; for (auto& req : requests_) { auto frames = _send(req->to_json()); out.insert(out.end(), frames.begin(), frames.end()); } return out; } private: std::string url_; std::vector> requests_; static size_t _write_cb(char* ptr, size_t size, size_t n, void* ud) { auto* buf = static_cast*>(ud); buf->insert(buf->end(), ptr, ptr + size * n); return size * n; } std::vector _send(const nlohmann::json& body) { std::string payload = body.dump(); std::vector raw; CURL* curl = curl_easy_init(); if (!curl) throw std::runtime_error("curl_easy_init failed"); std::string endpoint = url_ + "/api"; struct curl_slist* hdrs = curl_slist_append(nullptr, "Content-Type: application/json"); curl_easy_setopt(curl, CURLOPT_URL, endpoint.c_str()); curl_easy_setopt(curl, CURLOPT_POST, 1L); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.c_str()); curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)payload.size()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hdrs); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _write_cb); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &raw); CURLcode res = curl_easy_perform(curl); curl_slist_free_all(hdrs); curl_easy_cleanup(curl); if (res != CURLE_OK) throw std::runtime_error(curl_easy_strerror(res)); return _parse(raw); } std::vector _parse(const std::vector& raw) { std::vector frames; size_t pos = 0; auto read_u32 = [&]() -> uint32_t { if (pos + 4 > raw.size()) return 0; uint32_t n = (uint32_t(raw[pos]) << 24) | (uint32_t(raw[pos+1]) << 16) | (uint32_t(raw[pos+2]) << 8) | uint32_t(raw[pos+3]); pos += 4; return n; }; while (pos < raw.size()) { uint32_t jlen = read_u32(); if (pos + jlen > raw.size()) break; auto params = nlohmann::json::parse(raw.begin() + pos, raw.begin() + pos + jlen); pos += jlen; std::vector data; for (;;) { uint32_t blen = read_u32(); if (blen == 0) break; if (pos + blen > raw.size()) break; data.insert(data.end(), raw.begin() + pos, raw.begin() + pos + blen); pos += blen; } frames.push_back({std::move(params), std::move(data)}); } return frames; } }; } // namespace sigtera