DVB-S2 VCM support, suitable for ACM reception (not MIS).

work
pabr 2019-11-24 04:37:42 +01:00
rodzic 67b124f8e7
commit 94e30b55b7
4 zmienionych plików z 96 dodań i 55 usunięć

Wyświetl plik

@ -60,7 +60,9 @@ struct config {
cstln_base::predef constellation;
code_rate fec;
// DVB-S2
s2_pls pls;
static const int MAX_PLS_SEQ = 256;
s2_pls pls_seq[MAX_PLS_SEQ];
int n_pls_seq;
// Common
int buf_factor;
float amp; // Desired RMS constellation amplitude
@ -73,7 +75,7 @@ struct config {
bool fill;
bool verbose, debug;
config()
: standard(DVB_S), constellation(cstln_base::QPSK), fec(FEC12),
: standard(DVB_S),
buf_factor(2),
amp(1.0f), agc(false),
interp(2), decim(1), rolloff(0.35), rrc_rej(10),
@ -81,9 +83,14 @@ struct config {
fill(false),
verbose(false), debug(false)
{
pls.modcod = 13; // 8PSK 2/3
pls.sf = false;
pls.pilots = false;
// DVB-S defaults
constellation = cstln_base::QPSK;
fec = FEC12;
// DVB-S2 defaults
pls_seq[0].modcod = 13; // 8PSK 2/3
pls_seq[0].sf = false;
pls_seq[0].pilots = false;
n_pls_seq = 1; // CCM
}
};
@ -234,7 +241,8 @@ void run_dvbs2(config &cfg) {
pipebuf<bbframe> p_bbframes(&sch, "Scr BB frames", BUF_FRAMES);
s2_framer r_framer(&sch, p_tspackets, p_bbframes);
r_framer.pls = cfg.pls;
r_framer.pls_seq = cfg.pls_seq;
r_framer.n_pls_seq = cfg.n_pls_seq;
if ( cfg.rolloff > 0.40 ) r_framer.rolloff_code = 3;
else if ( cfg.rolloff > 0.30 ) r_framer.rolloff_code = 0; // 0.35
else if ( cfg.rolloff > 0.225 ) r_framer.rolloff_code = 1; // 0.25
@ -354,6 +362,7 @@ void usage(const char *name, FILE *f, int c, const char *info=NULL) {
" --modcod INT Set DVB-S2 modcod number\n"
" --shortframes Generate short frames\n"
" --pilots Generate pilots\n"
" --nextvcm Move to new frame spec in repeating VCM pattern\n"
" -f INTERP[/DECIM] Samples per symbols (default: 2)\n"
" --roll-off FLOAT RRC roll-off (default: 0.35)\n"
" --rrc-rej FLOAT RRC filter rejection (defaut: 10)\n"
@ -417,11 +426,16 @@ int main(int argc, char *argv[]) {
usage(argv[0], stderr, 1, argv[i]);
}
else if ( ! strcmp(argv[i], "--modcod") && i+1<argc )
cfg.pls.modcod = atoi(argv[++i]);
cfg.pls_seq[cfg.n_pls_seq-1].modcod = atoi(argv[++i]);
else if ( ! strcmp(argv[i], "--shortframes") )
cfg.pls.sf = true;
cfg.pls_seq[cfg.n_pls_seq-1].sf = true;
else if ( ! strcmp(argv[i], "--pilots") )
cfg.pls.pilots = true;
cfg.pls_seq[cfg.n_pls_seq-1].pilots = true;
else if ( ! strcmp(argv[i], "--nextvcm") ) {
if ( cfg.n_pls_seq == cfg.MAX_PLS_SEQ ) fail("VCM sequence too long");
cfg.pls_seq[cfg.n_pls_seq] = cfg.pls_seq[cfg.n_pls_seq-1];
++cfg.n_pls_seq;
}
else if ( ! strcmp(argv[i], "-f") && i+1<argc ) {
++i;
cfg.decim = 1;

Wyświetl plik

@ -267,6 +267,8 @@ namespace leansdr {
qsymbols[1].re = +amp; qsymbols[1].im = -amp;
qsymbols[2].re = -amp; qsymbols[2].im = +amp;
qsymbols[3].re = -amp; qsymbols[3].im = -amp;
// Clear the constellation cache.
for ( int i=0; i<32; ++i ) pcsymbols[i] = NULL;
}
void run() {
while ( in.readable() >= 1 ) {
@ -280,7 +282,6 @@ namespace leansdr {
int nsymbols = ( (1+nslots) * plslot<hard_ss>::LENGTH +
(pls->pilots ? ((nslots-1)/16)*pilot_length : 0) );
if ( out.writable() < nsymbols ) break;
update_cstln(mcinfo);
int nw = run_frame(pls, mcinfo, pin+1, nslots, out.wr());
if ( nw != nsymbols ) fail("Bug: s2_frame_transmitter overflow");
in.read(1+nslots);
@ -298,6 +299,7 @@ namespace leansdr {
int pls_index = (pls->modcod<<2) | (pls->sf<<1) | pls->pilots;
memcpy(pout, plscodes.symbols[pls_index], plscodes.LENGTH*sizeof(*pout));
pout += plscodes.LENGTH;
complex<T> *csymbols = get_csymbols(pls->modcod);
// Slots and pilots
int till_next_pilot = pls->pilots ? 16 : nslots;
uint8_t *scr = &scrambling.Rn[0];
@ -327,26 +329,23 @@ namespace leansdr {
private:
pipereader< plslot<hard_ss> > in;
pipewriter< complex<T> > out;
cstln_lut<hard_ss,256> *cstln; // NULL initially
complex<T> *csymbols; // Valid iff cstln is valid. RMS cstln_amp.
void update_cstln(const modcod_info *mcinfo) {
if ( !cstln || cstln->nsymbols!=mcinfo->nsymbols ) {
if ( cstln ) {
fprintf(stderr, "Warning: Variable MODCOD is inefficient\n");
delete cstln;
delete csymbols;
}
complex<T> *pcsymbols[32]; // Constellations in use, indexed by modcod
complex<T> *get_csymbols(int modcod) {
if ( ! pcsymbols[modcod] ) {
const modcod_info *mcinfo = check_modcod(modcod);
if ( sch->debug )
fprintf(stderr, "Building constellation %d\n", mcinfo->nsymbols);
fprintf(stderr, "Building constellation %s ratecode %d\n",
cstln_base::names[mcinfo->c], mcinfo->rate);
// TBD Different Es/N0 for short frames ?
cstln = new cstln_lut<hard_ss,256>(mcinfo->c, mcinfo->esn0_nf,
mcinfo->g1, mcinfo->g2, mcinfo->g3);
csymbols = new complex<T>[cstln->nsymbols];
for ( int s=0; s<cstln->nsymbols; ++s ) {
csymbols[s].re = cstln->symbols[s].re;
csymbols[s].im = cstln->symbols[s].im;
cstln_lut<hard_ss,256> cstln(mcinfo->c, mcinfo->esn0_nf,
mcinfo->g1, mcinfo->g2, mcinfo->g3);
pcsymbols[modcod] = new complex<T>[cstln.nsymbols];
for ( int s=0; s<cstln.nsymbols; ++s ) {
pcsymbols[modcod][s].re = cstln.symbols[s].re;
pcsymbols[modcod][s].im = cstln.symbols[s].im;
}
}
return pcsymbols[modcod];
}
complex<T> qsymbols[4]; // RMS cstln_amp
s2_sof<T> sof;
@ -404,6 +403,9 @@ namespace leansdr {
qpsk = new cstln_lut<SOFTSYMB,256>(cstln_base::QPSK);
add_syncs(qpsk);
// Clear the constellation cache.
for ( int i=0; i<32; ++i ) cstlns[i] = NULL;
init_coarse_freq();
#if TEST_DIVERSITY
@ -685,24 +687,8 @@ namespace leansdr {
S = pls.sf ? mcinfo->nslots_nf/4 : mcinfo->nslots_nf;
till_next_pls = pls.pilots ? 16 : S;
// Constellation for data slots.
// TBD Comparison of nsymbols is insufficient for DVB-S2X.
if ( !cstln || cstln->nsymbols!=mcinfo->nsymbols ) {
if ( cstln ) {
fprintf(stderr, "Warning: Variable MODCOD is inefficient\n");
delete cstln;
}
if ( sch->debug )
fprintf(stderr, "Creating LUT for %s ratecode %d\n",
cstln_base::names[mcinfo->c], mcinfo->rate);
cstln = new cstln_lut<SOFTSYMB,256>(mcinfo->c, mcinfo->esn0_nf,
mcinfo->g1,mcinfo->g2,mcinfo->g3);
#if 0
fprintf(stderr, "Dumping constellation LUT to stdout.\n");
cstln->dump(stdout);
exit(0);
#endif
}
dcstln = cstln;
dcstln = get_cstln(pls.modcod);
cstln = dcstln; // Still used by AGC (when strongpls) and GUI
// Output special slot with PLS information.
pout->is_pls = true;
pout->pls = pls;
@ -848,7 +834,7 @@ namespace leansdr {
// Match RMS amplitude
agc_gain = cstln_amp / in_amp;
} else {
// Match peak amplitude
// Match peak amplitude. Note: Assumes CCM.
agc_gain = cstln_amp / cstln->amp_max / in_amp;
}
}
@ -960,7 +946,24 @@ namespace leansdr {
} syncs[MAXSYNCS], *current_sync;
int nsyncs;
s2_plscodes<T> plscodes;
cstln_lut<SOFTSYMB,256> *cstln;
cstln_lut<SOFTSYMB,256> *cstlns[32]; // Constellations in use, by modcod
cstln_lut<SOFTSYMB,256> *get_cstln(int modcod) {
if ( ! cstlns[modcod] ) {
const modcod_info *mcinfo = &modcod_infos[modcod];
if ( sch->debug )
fprintf(stderr, "Creating LUT for %s ratecode %d\n",
cstln_base::names[mcinfo->c], mcinfo->rate);
cstlns[modcod] = new cstln_lut<SOFTSYMB,256>
(mcinfo->c, mcinfo->esn0_nf, mcinfo->g1,mcinfo->g2,mcinfo->g3);
#if 0
fprintf(stderr, "Dumping constellation LUT to stdout.\n");
cstlns[modcod]->dump(stdout);
exit(0);
#endif
}
return cstlns[modcod];
}
cstln_lut<SOFTSYMB,256> *cstln; // Last seen, or NULL (legacy)
// Initialize synchronizers for an arbitrary constellation.
void add_syncs(cstln_lut<SOFTSYMB,256> *c) {
int random_decision = 0;
@ -2031,32 +2034,44 @@ namespace leansdr {
struct s2_framer : runnable {
uint8_t rolloff_code; // 0=0.35, 1=0.25, 2=0.20, 3=reserved
s2_pls pls;
// User must provide pls_seq[n_pls_seq].
// For ACM, user can change pls_seq[0] at runtime.
// For VCM with a repeating pattern, use n_pls_seq>=2.
s2_pls *pls_seq;
int n_pls_seq;
s2_framer(scheduler *sch, pipebuf<tspacket> &_in, pipebuf<bbframe> &_out)
: runnable(sch, "S2 framer"),
n_pls_seq(0),
pls_index(0),
in(_in), out(_out)
{
pls.modcod = 4;
pls.sf = false;
pls.pilots = true;
nremain = 0;
remcrc = 0; // CRC for nonexistent previous packet
}
void run() {
while ( out.writable() >= 1 ) {
const modcod_info *mcinfo = check_modcod(pls.modcod);
const fec_info *fi = &fec_infos[pls.sf][mcinfo->rate];
if ( ! n_pls_seq ) fail("PLS not specified");
s2_pls *pls = &pls_seq[pls_index];
const modcod_info *mcinfo = check_modcod(pls->modcod);
const fec_info *fi = &fec_infos[pls->sf][mcinfo->rate];
int framebytes = fi->Kbch / 8;
if ( ! framebytes ) fail("MODCOD/framesize combination not allowed");
if ( 10+nremain+188*in.readable() < framebytes )
break; // Not enough data to fill a frame
bbframe *pout = out.wr();
pout->pls = pls;
pout->pls = *pls;
uint8_t *buf = pout->bytes;
uint8_t *end = buf + framebytes;
// EN 302 307-1 section 5.1.6 Base-Band Header insertion
uint8_t *bbheader = buf;
*buf++ = 0xf0 | rolloff_code; // MATYPE-1: TS, SIS, CCM
uint8_t matype1 = 0;
matype1 |= 0xc0; // TS
matype1 |= 0x20; // SIS
matype1 |= (n_pls_seq==1) ? 0x10 : 0x00; // CCM/ACM
// TBD ISSY/NPD required for ACM ?
matype1 |= rolloff_code;
*buf++ = matype1; // MATYPE-1
*buf++ = 0; // MATYPE-2
uint16_t upl = 188 * 8;
*buf++ = upl >> 8; // UPL MSB
@ -2089,9 +2104,12 @@ namespace leansdr {
}
if ( buf != end ) fail("Bug: s2_framer");
out.written(1);
++pls_index;
if ( pls_index == n_pls_seq ) pls_index = 0;
}
}
private:
int pls_index; // Next slot to use in pls_seq
pipereader<tspacket> in;
pipewriter<bbframe> out;
crc8_engine crc8;

Wyświetl plik

@ -1,11 +1,14 @@
leandvb-ft:
make -C ../src/apps leantsgen leandvbtx leanchansim leandvb
@echo Testing lock on 6 DVB-S code rates...
@echo Testing lock on 5 DVB-S code rates...
./leandvb_bench.sh S_FT
grep '^[^#]..' leandvb_bench_results.txt | wc -l | grep -q 5
@echo Testing lock on 52 DVB-S2 modcod/framesize combinations...
./leandvb_bench.sh S2_FT
grep '^[^#]..' leandvb_bench_results.txt | wc -l | grep -q 52
@echo Testing DVB-S2 VCM...
./leandvb_bench.sh S2VCM_FT
grep '^[^#]..' leandvb_bench_results.txt | wc -l | grep -q 3
@echo Success
leandvb-snr:

Wyświetl plik

@ -194,6 +194,12 @@ s2_ft 26 "32APSK_5/6" 14.28
s2_ft 27 "32APSK_8/9" 15.69
s2_ft 28 "32APSK_9/10" 16.05
# S2 VCM
test_series "S2VCM_FT_NF_QPSK12_8PSK23" 4 25 "$S2TX --modcod 4 --nextvcm --modcod 13" "$S2RX"
test_series "S2VCM_FT_NF_QPSK12_16APSK34" 4 30 "$S2TX --modcod 4 --nextvcm --modcod 19" "$S2RX"
# S2 VCM, FEC-dependent radii
test_series "S2VCM_FT_NF_16APSK23_16APSK910" 4 30 "$S2TX --modcod 18 --nextvcm --modcod 23" "$S2RX"
# DVB-S error performance
test_series "1.2sps-hs" 6/5 "20 19 18 17 16 15 14 13 12 11 10" "" "--u8 --hs"