From 456eefede4ee9beaf34537ac1ad033cd5ce935f7 Mon Sep 17 00:00:00 2001 From: Karlis Goba Date: Mon, 16 Aug 2021 12:49:32 +0300 Subject: [PATCH] Minor cleanup in encoding, more documentation --- ft8/encode.h | 17 +++-------------- ft8/ldpc.c | 6 +++--- gen_ft8.c | 54 ++++++++++++++++++---------------------------------- 3 files changed, 25 insertions(+), 52 deletions(-) diff --git a/ft8/encode.h b/ft8/encode.h index 0c2c3f0..31316a2 100644 --- a/ft8/encode.h +++ b/ft8/encode.h @@ -3,20 +3,9 @@ #include -// Generate FT8 tone sequence from payload data -// [IN] payload - 9 byte array consisting of 72 bit payload -// [OUT] itone - array of NN (79) bytes to store the generated tones (encoded as 0..7) +/// Generate FT8 tone sequence from payload data +/// @param[in] payload - 10 byte array consisting of 77 bit payload +/// @param[out] itone - array of NN (79) bytes to store the generated tones (encoded as 0..7) void genft8(const uint8_t *payload, uint8_t *itone); -// Encode an 87-bit message and return a 174-bit codeword. -// The generator matrix has dimensions (87,87). -// The code is a (174,87) regular ldpc code with column weight 3. -// The code was generated using the PEG algorithm. -// After creating the codeword, the columns are re-ordered according to -// "colorder" to make the codeword compatible with the parity-check matrix -// Arguments: -// * message - array of 87 bits stored as 11 bytes (MSB first) -// * codeword - array of 174 bits stored as 22 bytes (MSB first) -void encode174(const uint8_t *message, uint8_t *codeword); - #endif // _INCLUDE_ENCODE_H_ diff --git a/ft8/ldpc.c b/ft8/ldpc.c index c3be1de..fa1c060 100644 --- a/ft8/ldpc.c +++ b/ft8/ldpc.c @@ -212,7 +212,7 @@ void bp_decode(float codeword[], int max_iters, uint8_t plain[], int *ok) Tnm += tov[n][m_idx]; } } - toc[m][n_idx] = fast_tanh(-Tnm / 2); // == (exp(-Tnm)-1) / (exp(-Tnm)+1) + toc[m][n_idx] = fast_tanh(-Tnm / 2); } } @@ -228,10 +228,10 @@ void bp_decode(float codeword[], int max_iters, uint8_t plain[], int *ok) { if ((kFT8_LDPC_Nm[m][n_idx] - 1) != n) { - Tmn *= toc[m][n_idx]; // tanh(q(n', m) / 2) + Tmn *= toc[m][n_idx]; } } - tov[n][m_idx] = 2 * fast_atanh(-Tmn); // == log( (1-Tmn) / (1+Tmn) ) + tov[n][m_idx] = -2 * fast_atanh(Tmn); } } } diff --git a/gen_ft8.c b/gen_ft8.c index f741ebd..5709a3c 100644 --- a/gen_ft8.c +++ b/gen_ft8.c @@ -12,9 +12,16 @@ #define LOG_LEVEL LOG_INFO +/// Computes a GFSK smoothing pulse. +/// The pulse is theoretically infinitely long, however, here it's truncated at 3 times the symbol length. +/// This means the pulse array has to have space for 3*n_spsym elements. +/// @param[in] n_spsym Number of samples per symbol +/// @param[in] b Shape parameter (values defined for FT8/FT4) +/// @param[out] pulse Output array of pulse samples +/// void gfsk_pulse(int n_spsym, float b, float *pulse) { - const float c = M_PI * sqrtf(2 / logf(2)); + float c = M_PI * sqrtf(2 / logf(2)); for (int i = 0; i < 3 * n_spsym; ++i) { @@ -23,11 +30,19 @@ void gfsk_pulse(int n_spsym, float b, float *pulse) } } -// Same as synth_fsk, but uses GFSK phase shaping +/// Synthesize waveform data using GFSK phase shaping. +/// The output waveform will contain n_sym+2 symbols (extra symbol at the beginning/end). +/// @param[in] symbols Array of symbols (tones) (0-7 for FT8) +/// @param[in] n_sym Number of symbols in the symbols array +/// @param[in] f0 Audio frequency in Hertz for the symbol 0 (base frequency) +/// @param[in] n_spsym Number of samples per symbol (only integer number of samples supported) +/// @param[in] signal_rate Sample rate of synthesized signal, Hertz +/// @param[out] signal Output array of signal waveform samples (should have space for n_spsym*(n_sym+2) samples) +/// void synth_gfsk(const uint8_t *symbols, int n_sym, float f0, int n_spsym, int signal_rate, float *signal) { LOG(LOG_DEBUG, "n_spsym = %d\n", n_spsym); - int n_wave = n_sym * n_spsym; + int n_wave = n_sym * n_spsym; // Number of output samples float hmod = 1.0f; // Compute the smoothed frequency waveform. @@ -78,34 +93,6 @@ void synth_gfsk(const uint8_t *symbols, int n_sym, float f0, int n_spsym, int si } } -// Convert a sequence of symbols (tones) into a sinewave of continuous phase (FSK). -// Symbol 0 gets encoded as a sine of frequency f0, the others are spaced in increasing -// fashion. -void synth_fsk(const uint8_t *symbols, int num_symbols, float f0, float spacing, - float symbol_rate, float signal_rate, float *signal) -{ - float phase = 0; - float dt = 1 / signal_rate; - float dt_sym = 1 / symbol_rate; - float t = 0; - int j = 0; - int i = 0; - while (j < num_symbols) - { - float f = f0 + symbols[j] * spacing; - phase = fmodf(phase + 2 * M_PI * f / signal_rate, 2 * M_PI); - signal[i] = sinf(phase); - t += dt; - if (t >= dt_sym) - { - // Move to the next symbol - t -= dt_sym; - ++j; - } - ++i; - } -} - void usage() { printf("Generate a 15-second WAV file encoding a given message.\n"); @@ -135,7 +122,6 @@ int main(int argc, char **argv) // First, pack the text data into binary message uint8_t packed[FT8_K_BYTES]; - //int rc = packmsg(message, packed); int rc = pack77(message, packed); if (rc < 0) { @@ -152,8 +138,7 @@ int main(int argc, char **argv) printf("\n"); // Second, encode the binary message as a sequence of FSK tones - uint8_t tones[FT8_NN]; // FT8_NN = 79, lack of better name at the moment - //genft8(packed, 0, tones); + uint8_t tones[FT8_NN]; // Array of 79 tones (symbols) genft8(packed, tones); printf("FSK tones: "); @@ -174,7 +159,6 @@ int main(int argc, char **argv) signal[i] = 0; } - // synth_fsk(tones, FT8_NN, frequency, symbol_rate, symbol_rate, sample_rate, signal + num_silence); synth_gfsk(tones, FT8_NN, frequency, sample_rate / symbol_rate, sample_rate, signal + num_silence); save_wav(signal, num_silence + num_samples + num_silence, sample_rate, wav_path);