Skip to content

Commit 1269b56

Browse files
committed
first pass at 2020B with partial protection FEC
1 parent af3e4df commit 1269b56

File tree

8 files changed

+94
-36
lines changed

8 files changed

+94
-36
lines changed

CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -575,9 +575,9 @@ endif()
575575
# 2020B AWGN test
576576
add_test(NAME test_OFDM_modem_2020B_AWGN
577577
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
578-
./ofdm_mod --in /dev/zero --testframes 10 --mode 2020B |
579-
./ch - - --No -22 |
580-
./ofdm_demod --mode 2020B --testframes -v 2 > /dev/null")
578+
./ofdm_mod --in /dev/zero --testframes 10 --mode 2020B --ldpc |
579+
./ch - - --No -19 |
580+
./ofdm_demod --mode 2020B --testframes --ldpc -v 2 > /dev/null")
581581

582582
# -------------------------------------------------------------------------
583583
# OFDM Data modes

octave/ofdm_lib.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@
324324
Ts = 0.0205; Nc = 31;
325325
config.amp_scale = 167E3; config.clip_gain1 = 2.5; config.clip_gain2 = 0.8;
326326
elseif strcmp(mode,"2020B")
327-
Ts = 0.014; Tcp = 0.004; Nc = 22; Ns=5;
327+
Ts = 0.014; Tcp = 0.004; Nc = 29; Ns=5;
328328
config.Ntxtbits = 4; config.Nuwbits = 8*2; config.bad_uw_errors = 5;
329329
config.amp_scale = 167E3; config.clip_gain1 = 2.5; config.clip_gain2 = 0.8;
330330
config.edge_pilots = 0; config.state_machine = "voice2";

src/gp_interleaver.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,14 @@
4343
*/
4444

4545
static const int b_table[] = {
46-
56, 37, /* 700E: HRA_56_56 */
47-
112, 71, /* 700D: HRA_112_112 */
48-
128, 83, /* datac0: H_128_256_5 */
49-
210, 131, /* 2020: HRAb_396_504 with 312 data bits used */
50-
1024, 641, /* datac3: H_1024_2048_4f */
51-
1290, 797, /* datac2: H2064_516_sparse */
52-
4096, 2531 /* datac1: H_4096_8192_3d */
46+
56, 37, /* 700E: HRA_56_56 */
47+
106, 67, /* 2020B: (112,56) partial protection */
48+
112, 71, /* 700D: HRA_112_112 */
49+
128, 83, /* datac0: H_128_256_5 */
50+
210, 131, /* 2020: HRAb_396_504 with 312 data bits used */
51+
1024, 641, /* datac3: H_1024_2048_4f */
52+
1290, 797, /* datac2: H2064_516_sparse */
53+
4096, 2531 /* datac1: H_4096_8192_3d */
5354
};
5455

5556
int choose_interleaver_b(int Nbits)
@@ -141,4 +142,4 @@ void gp_deinterleave_bits(char frame[], char interleaved_frame[], int Nbits)
141142
frame[i*2] = temp[i] >> 1;
142143
frame[i*2 + 1] = temp[i] & 1;
143144
}
144-
}
145+
}

src/interldpc.c

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ void set_data_bits_per_frame(struct LDPC *ldpc, int new_data_bits_per_frame) {
6868
FEC protection scheme */
6969
void ldpc_encode_frame(struct LDPC *ldpc, int codeword[], unsigned char tx_bits_char[]) {
7070
unsigned char pbits[ldpc->NumberParityBits];
71+
int codec_frame;
7172
int i, j;
7273

7374
unsigned char tx_bits_char_padded[ldpc->ldpc_data_bits_per_frame];
@@ -95,27 +96,41 @@ void ldpc_encode_frame(struct LDPC *ldpc, int codeword[], unsigned char tx_bits_
9596
unmodified.
9697
*/
9798
memcpy(tx_bits_char_padded, tx_bits_char, ldpc->data_bits_per_frame);
98-
int codec_frame;
9999
for(codec_frame=0; codec_frame<6; codec_frame++)
100100
for(i=11; i<52; i++)
101101
tx_bits_char_padded[codec_frame*52+i] = 1;
102102
assert(codec_frame*52 == ldpc->data_bits_per_frame);
103103
for (i = ldpc->data_bits_per_frame; i < ldpc->ldpc_data_bits_per_frame; i++)
104104
tx_bits_char_padded[i] = 1;
105105
encode(ldpc, tx_bits_char_padded, pbits);
106+
107+
break;
108+
109+
case LDPC_PROT_2020B:
110+
/* We only want to protect the stage 1 VQ data bits, 0..10 in
111+
each 52 bit codec frame. There are 3 codec frames 3x52=156
112+
bits, and 56 parity bits. We only use 11*3 = 33 bits of
113+
the LDPC codeword data bits, the rest are set to known
114+
values.
115+
*/
116+
for(j=0,codec_frame=0; codec_frame<3; codec_frame++)
117+
for(i=0; i<11; i++,j++)
118+
tx_bits_char_padded[j] = tx_bits_char[codec_frame*52+i];
119+
assert(j == 33);
120+
for (i = 33; i < ldpc->ldpc_data_bits_per_frame; i++)
121+
tx_bits_char_padded[i] = 1;
122+
encode(ldpc, tx_bits_char_padded, pbits);
123+
106124
break;
125+
107126
default:
108127
assert(0);
109128
}
110129

111130
/* output codeword is concatenation of (used) data bits and parity
112131
bits, we don't bother sending unused (known) data bits */
113-
for (i = 0; i < ldpc->data_bits_per_frame; i++) {
114-
codeword[i] = tx_bits_char[i];
115-
}
116-
for (j = 0; j < ldpc->NumberParityBits; i++, j++) {
117-
codeword[i] = pbits[j];
118-
}
132+
for (i = 0; i < ldpc->data_bits_per_frame; i++) codeword[i] = tx_bits_char[i];
133+
for (j = 0; j < ldpc->NumberParityBits; i++, j++) codeword[i] = pbits[j];
119134
}
120135

121136
void qpsk_modulate_frame(COMP tx_symbols[], int codeword[], int n) {
@@ -137,7 +152,8 @@ void ldpc_decode_frame(struct LDPC *ldpc, int *parityCheckCount, int *iter, uint
137152
float llr_full_codeword[ldpc->ldpc_coded_bits_per_frame];
138153
int unused_data_bits = ldpc->ldpc_data_bits_per_frame - ldpc->data_bits_per_frame;
139154
uint8_t out_char_ldpc[ldpc->coded_bits_per_frame];
140-
int i;
155+
int i,j;
156+
int codec_frame;
141157

142158
switch (ldpc->protection_mode) {
143159
case LDPC_PROT_EQUAL:
@@ -175,7 +191,6 @@ void ldpc_decode_frame(struct LDPC *ldpc, int *parityCheckCount, int *iter, uint
175191
}
176192

177193
// set up known bits
178-
int codec_frame;
179194
for(codec_frame=0; codec_frame<6; codec_frame++)
180195
for(i=11; i<52; i++)
181196
llr_full_codeword[codec_frame*52+i] = -100.0f;
@@ -194,6 +209,33 @@ void ldpc_decode_frame(struct LDPC *ldpc, int *parityCheckCount, int *iter, uint
194209
for(i=0; i<11; i++)
195210
out_char[codec_frame*52+i] = out_char_ldpc[codec_frame*52+i];
196211
break;
212+
case LDPC_PROT_2020B:
213+
/* 2020B waveform, with unequal error protection. As per
214+
2020A, only the stage1 VQ index of each LPCNet vocoder
215+
frames is protected. In this case the FEC codeword is much
216+
smaller than the payload data. */
217+
218+
// set up LDPC codeword
219+
for(j=0,codec_frame=0; codec_frame<3; codec_frame++)
220+
for(i=0; i<11; i++,j++)
221+
llr_full_codeword[j] = llr[codec_frame*52+i];
222+
// set known LDPC codeword data bits
223+
for (i = 33; i < ldpc->ldpc_data_bits_per_frame; i++)
224+
llr_full_codeword[i] = -100;
225+
// parity bits at end
226+
for (i=0; i<ldpc->NumberParityBits; i++)
227+
llr_full_codeword[ldpc->ldpc_data_bits_per_frame+i] = llr[ldpc->data_bits_per_frame+i];
228+
*iter = run_ldpc_decoder(ldpc, out_char_ldpc, llr_full_codeword, parityCheckCount);
229+
230+
// pass through received data bits, replacing only decoded bits
231+
for (i = 0; i < ldpc->data_bits_per_frame; i++) {
232+
out_char[i] = llr[i] < 0;
233+
}
234+
for(j=0,codec_frame=0; codec_frame<3; codec_frame++)
235+
for(i=0; i<11; i++,j++)
236+
out_char[codec_frame*52+i] = out_char_ldpc[j];
237+
238+
break;
197239
default:
198240
assert(0);
199241
}
@@ -279,7 +321,19 @@ void count_errors_protection_mode(int protection_mode, int *pNerrs, int *pNcoded
279321
*/
280322
for(int codec_frame=0; codec_frame<6; codec_frame++) {
281323
for(i=0; i<11; i++) {
282-
if (tx_bits[i] != rx_bits[i]) Nerrs++;
324+
if (tx_bits[codec_frame*52+i] != rx_bits[codec_frame*52+i]) Nerrs++;
325+
Ncoded++;
326+
}
327+
}
328+
break;
329+
case LDPC_PROT_2020B:
330+
/* We only protect bits 0..10 in each 52 bit LPCNet codec
331+
frame. There are 3 codec frames 3x52=156 data bits, of
332+
which only 11*3 = 33 bits are protected.
333+
*/
334+
for(int codec_frame=0; codec_frame<3; codec_frame++) {
335+
for(i=0; i<11; i++) {
336+
if (tx_bits[codec_frame*52+i] != rx_bits[codec_frame*52+i]) Nerrs++;
283337
Ncoded++;
284338
}
285339
}

src/interldpc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#define LDPC_PROT_EQUAL 0 /* all bits in LDPC codeword used, e.g. 700D/700E */
3939
#define LDPC_PROT_2020 1 /* (504,396) but some data bits unused */
4040
#define LDPC_PROT_2020A 2 /* (504,396) but we only protect stage1 VQ in each LPCNet frame */
41+
#define LDPC_PROT_2020B 3 /* (112,56) but we only protect stage1 VQ in each LPCNet frame */
4142

4243
void set_up_ldpc_constants(struct LDPC *ldpc, int code_length, int parity_bits);
4344
void set_data_bits_per_frame(struct LDPC *ldpc, int new_data_bits_per_frame);

src/ofdm_demod.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ void opt_help() {
6767
fprintf(stderr, " --in filename Name of InputModemRawFile\n");
6868
fprintf(stderr, " --out filename Name of OutputOneCharPerBitFile\n");
6969
fprintf(stderr, " --log filename Octave log file for testing\n");
70-
fprintf(stderr, " --mode modeName Predefined mode 700D|2020|datac1\n");
70+
fprintf(stderr, " --mode modeName Predefined mode e.g. 700D|2020|datac1\n");
7171
fprintf(stderr, " --nc [17..62] Number of Carriers (17 default, 62 max)\n");
7272
fprintf(stderr, " --np Number of packets\n");
7373
fprintf(stderr, " --ns Nframes One pilot every ns symbols (8 default)\n");
@@ -343,15 +343,16 @@ int main(int argc, char *argv[]) {
343343
if (ldpc_en) {
344344
ldpc_codes_setup(&ldpc, ofdm->codename);
345345
if (verbose > 1) { fprintf(stderr, "using: %s\n", ofdm->codename); }
346-
if (!strcmp(mode,"2020") || !strcmp(mode,"2020A")) {
347-
set_data_bits_per_frame(&ldpc, 312);
348-
}
346+
347+
/* mode specific set up */
348+
if (!strcmp(mode,"2020") || !strcmp(mode,"2020A")) set_data_bits_per_frame(&ldpc, 312);
349349
if (!strcmp(mode,"2020A")) ldpc.protection_mode = LDPC_PROT_2020A;
350+
if (!strcmp(mode,"2020B")) {
351+
set_data_bits_per_frame(&ldpc, 156);
352+
ldpc.protection_mode = LDPC_PROT_2020B;
353+
}
350354
Ndatabitsperpacket = ldpc.data_bits_per_frame;
351355

352-
assert(Ndatabitsperpacket <= ldpc.ldpc_data_bits_per_frame);
353-
assert(Npayloadbitsperpacket <= ldpc.ldpc_coded_bits_per_frame);
354-
355356
if (verbose > 1) {
356357
fprintf(stderr, "LDPC codeword data bits = %d\n", ldpc.ldpc_data_bits_per_frame);
357358
fprintf(stderr, "LDPC codeword total bits = %d\n", ldpc.ldpc_coded_bits_per_frame);

src/ofdm_mod.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -257,15 +257,16 @@ int main(int argc, char *argv[]) {
257257
if (ldpc_en) {
258258
ldpc_codes_setup(&ldpc, ofdm->codename);
259259
if (verbose > 1) { fprintf(stderr, "using: %s\n", ofdm->codename); }
260-
if (!strcmp(mode,"2020") || !strcmp(mode,"2020A")) {
261-
set_data_bits_per_frame(&ldpc, 312);
262-
}
260+
261+
/* mode specific set up */
262+
if (!strcmp(mode,"2020") || !strcmp(mode,"2020A")) set_data_bits_per_frame(&ldpc, 312);
263263
if (!strcmp(mode,"2020A")) ldpc.protection_mode = LDPC_PROT_2020A;
264+
if (!strcmp(mode,"2020B")) {
265+
set_data_bits_per_frame(&ldpc, 156);
266+
ldpc.protection_mode = LDPC_PROT_2020B;
267+
}
264268
Ndatabitsperpacket = ldpc.data_bits_per_frame;
265269

266-
assert(Ndatabitsperpacket <= ldpc.ldpc_data_bits_per_frame);
267-
assert(Npayloadbitsperpacket <= ldpc.ldpc_coded_bits_per_frame);
268-
269270
if (verbose > 1) {
270271
fprintf(stderr, "LDPC codeword data bits = %d\n", ldpc.ldpc_data_bits_per_frame);
271272
fprintf(stderr, "LDPC codeword total bits = %d\n", ldpc.ldpc_coded_bits_per_frame);

src/ofdm_mode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config) {
6262
config->ts = 0.0205; config->nc = 31; config->codename = "HRAb_396_504";
6363
config->tx_bpf_en = false; config->amp_scale = 167E3; config->clip_gain1 = 2.5; config->clip_gain2 = 0.8;
6464
} else if (strcmp(mode,"2020B") == 0) {
65-
config->ts = 0.014; config->tcp = 0.004; config->nc = 22; config->ns=5; config->codename = NULL;
65+
config->ts = 0.014; config->tcp = 0.004; config->nc = 29; config->ns=5; config->codename = "HRA_56_56";
6666
config->txtbits = 4; config->nuwbits = 8*2; config->bad_uw_errors = 5;
6767
config->tx_bpf_en = false; config->amp_scale = 167E3; config->clip_gain1 = 2.5; config->clip_gain2 = 0.8;
6868
config->edge_pilots = 0; config->state_machine = "voice2";

0 commit comments

Comments
 (0)