TinyModem
Header-only software audio modem library
Loading...
Searching...
No Matches
OFDMEncoder.h
Go to the documentation of this file.
1#pragma once
2
3#include <math.h>
4
5#include "AudioTools.h"
6#include "ModemBase.h"
7#include "OFDM.h"
8
9namespace tinymodem {
10
22class OFDMEncoder : public ModemEncoder {
23 public:
24 OFDMEncoder() = default;
25 OFDMEncoder(Print& out) { setOutput(out); }
26
29 OFDMConfig result;
30 result.setMode("ofdm32");
31 return result;
32 }
33
34 void setOutput(Print& out) override {
35 samples.setOutput(out);
36 ModemEncoder::setOutput(out); // writeSilence(), writeTone()
37 }
38
40 void setAudioInfo(audio_tools::AudioInfo info) override {
41 cfg.sample_rate = info.sample_rate;
42 cfg.channels = info.channels;
43 cfg.bits_per_sample = info.bits_per_sample;
44 if (is_active) begin();
45 }
46
47 audio_tools::AudioInfo audioInfo() override { return cfg; }
48
49 using audio_tools::AudioEncoder::begin;
50
53 cfg = config;
54 return begin();
55 }
56
57 bool begin() override {
58 is_active = false;
59 if (!cfg.isValid()) return false;
60 if (cfg.bits_per_sample != 16) {
61 LOGE("OFDMEncoder: bits_per_sample must be 16, not %d",
62 (int)cfg.bits_per_sample);
63 return false;
64 }
65 if (cfg.channels < 1) {
66 LOGE("OFDMEncoder: invalid number of channels: %d", (int)cfg.channels);
67 return false;
68 }
69 samples.begin(cfg.channels, cfg.volume);
70 if (!tones.begin(cfg, cfg.volume)) return false;
71 fft_size = cfg.fftSize();
72 prefix_size = cfg.prefixSize();
73 first_bin = cfg.firstBin();
74 table.begin(fft_size);
75 phases.resize(cfg.carriers);
76 frame.resize(cfg.max_frame);
77 frame_len = 0;
78 // the rms of the sum of all carriers is about 0.25 * volume
79 amplitude = 0.25f * sqrtf(2.0f / cfg.carriers);
80 is_active = true;
81 return true;
82 }
83
84 void end() override {
86 is_active = false;
87 }
88
90 size_t write(const uint8_t* data, size_t len) override {
91 if (!is_active) return 0;
92 for (size_t j = 0; j < len; j++) {
93 frame[frame_len++] = data[j];
94 if (frame_len == cfg.max_frame) sendFrame();
95 }
96 return len;
97 }
98
101 bool endTransmission(size_t silence_samples = 0) override {
102 if (!is_active || frame_len == 0) return false;
103 sendFrame();
104 // silence of one symbol marks the end
105 size_t n = fft_size + prefix_size + silence_samples;
106 for (size_t j = 0; j < n; j++) samples.write(0.0f);
107 samples.flush();
108 return true;
109 }
110
112 bool isTransmitting() override { return frame_len > 0; }
113
115 float symbolRate() override { return cfg.symbolRate(); }
116
118 OFDMConfig& config() { return cfg; }
119
120 operator bool() override { return is_active; }
121
122 protected:
126 bool is_active = false;
127 int fft_size = 0;
128 int prefix_size = 0;
129 int first_bin = 0;
130 float amplitude = 0.1f;
131 audio_tools::Vector<uint8_t> phases; // current phase of each carrier
132 audio_tools::Vector<uint8_t> frame;
133 int frame_len = 0;
134
135 void sendFrame() {
136 int n = cfg.carriers;
137 // sync symbol: even carriers with known phases
138 for (int i = 0; i < n; i++) phases[i] = OFDMConfig::knownPhase(0, i);
139 sendSymbol(true);
140 // reference symbol: all carriers with known phases
141 for (int i = 0; i < n; i++) phases[i] = OFDMConfig::knownPhase(1, i);
142 sendSymbol(false);
143 // header: length and inverted length (16 bit each)
144 sendHeader((uint32_t)frame_len << 16 | (uint16_t)~frame_len);
145 // data
146 int bit_count = 0;
147 sendBits(frame.data(), frame_len, bit_count);
148 if (bit_count > 0) sendSymbol(false);
149 samples.flush();
150 frame_len = 0;
151 }
152
157 void sendBits(const uint8_t* data, int len, int& bit_count) {
158 int n = cfg.carriers;
159 for (int j = 0; j < len; j++) {
160 for (int b = 6; b >= 0; b -= 2) {
161 int dibit = (data[j] >> b) & 3;
162 int carrier = bit_count / 2;
163 phases[carrier] = (phases[carrier] + grayToPhase(dibit)) & 3;
164 bit_count += 2;
165 if (bit_count == 2 * n) {
166 sendSymbol(false);
167 bit_count = 0;
168 }
169 }
170 }
171 }
172
175 void sendHeader(uint32_t header) {
176 int symbols = OFDMConfig::headerSymbols(cfg.carriers);
177 for (int s = 0; s < symbols; s++) {
178 for (int i = 0; i < cfg.carriers; i++) {
179 int bit = (header >> (31 - (s * cfg.carriers + i) % 32)) & 1;
180 if (bit) phases[i] = (phases[i] + 2) & 3;
181 }
182 sendSymbol(false);
183 }
184 }
185
187 static int grayToPhase(int dibit) {
188 static const int phase[4] = {0, 1, 3, 2};
189 return phase[dibit];
190 }
191
193 void sendSymbol(bool sync) {
194 int n = cfg.carriers;
195 float a = sync ? amplitude * 1.41421356f : amplitude;
196 for (int t = -prefix_size; t < fft_size; t++) {
197 int time = t < 0 ? t + fft_size : t;
198 float value = 0;
199 for (int i = 0; i < n; i++) {
200 int bin = first_bin + i;
201 if (sync && (bin & 1)) continue; // only even carriers
202 int idx = (int)(((int64_t)bin * time) % fft_size);
203 // cos(angle + phase * 90 degrees)
204 switch (phases[i]) {
205 case 0:
206 value += table.cosine(idx);
207 break;
208 case 1:
209 value -= table.sine(idx);
210 break;
211 case 2:
212 value -= table.cosine(idx);
213 break;
214 default:
215 value += table.sine(idx);
216 break;
217 }
218 }
219 samples.write(a * value);
220 }
221 }
222};
223
224} // namespace tinymodem
Common API of the modulators (FSKEncoder, MFSKEncoder): the written data is converted to 16 bit PCM a...
Definition ModemBase.h:286
void setOutput(Print &out) override
Definition ModemBase.h:288
ToneOutput tones
Definition ModemBase.h:334
bool begin() override
Definition OFDMEncoder.h:57
audio_tools::AudioInfo audioInfo() override
Definition OFDMEncoder.h:47
int frame_len
Definition OFDMEncoder.h:133
bool is_active
Definition OFDMEncoder.h:126
SampleOutput samples
Definition OFDMEncoder.h:124
float amplitude
Definition OFDMEncoder.h:130
void sendHeader(uint32_t header)
Definition OFDMEncoder.h:175
void sendBits(const uint8_t *data, int len, int &bit_count)
Definition OFDMEncoder.h:157
void setAudioInfo(audio_tools::AudioInfo info) override
Defines the sample rate and number of channels of the generated audio.
Definition OFDMEncoder.h:40
bool endTransmission(size_t silence_samples=0) override
Definition OFDMEncoder.h:101
OFDMEncoder(Print &out)
Definition OFDMEncoder.h:25
void end() override
Definition OFDMEncoder.h:84
float symbolRate() override
OFDM symbols per second.
Definition OFDMEncoder.h:115
audio_tools::Vector< uint8_t > phases
Definition OFDMEncoder.h:131
int first_bin
Definition OFDMEncoder.h:129
size_t write(const uint8_t *data, size_t len) override
Collects the bytes and sends full frames.
Definition OFDMEncoder.h:90
bool begin(OFDMConfig config)
Starts the processing with the indicated configuration.
Definition OFDMEncoder.h:52
void sendSymbol(bool sync)
Writes the cyclic prefix and the symbol.
Definition OFDMEncoder.h:193
void sendFrame()
Definition OFDMEncoder.h:135
audio_tools::Vector< uint8_t > frame
Definition OFDMEncoder.h:132
bool isTransmitting() override
true if there is data which was not sent yet
Definition OFDMEncoder.h:112
int fft_size
Definition OFDMEncoder.h:127
OFDMConfig cfg
Definition OFDMEncoder.h:123
static int grayToPhase(int dibit)
00 -> 0, 01 -> 90, 11 -> 180, 10 -> 270 degrees
Definition OFDMEncoder.h:187
OFDMConfig & config()
The configuration which was provided in begin().
Definition OFDMEncoder.h:118
OFDMConfig defaultConfig()
Provides a default configuration: ofdm32.
Definition OFDMEncoder.h:28
void setOutput(Print &out) override
Definition OFDMEncoder.h:34
int prefix_size
Definition OFDMEncoder.h:128
OFDMTable table
Definition OFDMEncoder.h:125
Sine and cosine of 2 * PI * i / size.
Definition OFDM.h:140
Writes float samples (-1.0 to 1.0) as 16 bit PCM with the requested number of channels and volume to ...
Definition ModemBase.h:118
TinyModem: software audio modems and packets with error correction.
Definition AX25.h:11
Configuration of the OFDM modem (OFDMEncoder, OFDMDecoder): the data is transmitted in parallel on ca...
Definition OFDM.h:23
static int knownPhase(int symbol, int carrier)
Definition OFDM.h:120
static int headerSymbols(int carriers)
Number of symbols of the header (32 bits, one bit per carrier).
Definition OFDM.h:116
bool setMode(const char *mode)
Selects "ofdm16", "ofdm32" or "ofdm64": returns false if invalid.
Definition OFDM.h:52