SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
Classes | Public Member Functions | Public Attributes | Private Member Functions | Private Attributes | List of all members
leansdr::cstln_lut< SOFTSYMB, R > Struct Template Reference

#include <sdr.h>

+ Inheritance diagram for leansdr::cstln_lut< SOFTSYMB, R >:
+ Collaboration diagram for leansdr::cstln_lut< SOFTSYMB, R >:

Classes

struct  result
 

Public Member Functions

 cstln_lut (cstln_base::predef type, float mer=10, float gamma1=0, float gamma2=0, float gamma3=0)
 
resultlookup (float I, float Q)
 
resultlookup (int I, int Q)
 
void dump (FILE *f)
 
void harden ()
 

Public Attributes

int m_typeCode
 
int m_rateCode
 
bool m_setByModcod
 
- Public Attributes inherited from leansdr::cstln_base
float amp_max
 
complex< int8_t > * symbols
 
int nsymbols
 
int nrotations
 

Private Member Functions

complex< signed char > polar (float r, int n, float i)
 
void polar2 (int i, float r, float a0, float a1, float a2, float a3)
 
void make_qam (int n)
 
void make_lut_from_symbols (float mer)
 

Private Attributes

result lut [R][R]
 

Additional Inherited Members

- Public Types inherited from leansdr::cstln_base
enum  predef {
  BPSK, QPSK, PSK8, APSK16,
  APSK32, APSK64E, QAM16, QAM64,
  QAM256, COUNT
}
 
- Static Public Attributes inherited from leansdr::cstln_base
static const char * names []
 

Detailed Description

template<typename SOFTSYMB, int R>
struct leansdr::cstln_lut< SOFTSYMB, R >

Definition at line 485 of file sdr.h.

Constructor & Destructor Documentation

◆ cstln_lut()

template<typename SOFTSYMB, int R>
leansdr::cstln_lut< SOFTSYMB, R >::cstln_lut ( cstln_base::predef  type,
float  mer = 10,
float  gamma1 = 0,
float  gamma2 = 0,
float  gamma3 = 0 
)
inline

Definition at line 487 of file sdr.h.

492  {
493  switch (type)
494  {
495  case BPSK:
496  amp_max = 1;
497  nrotations = 2;
498  nsymbols = 2;
499  symbols = new complex<signed char>[nsymbols];
500 #if 0 // BPSK at 0°
501  symbols[0] = polar(1, 2, 0);
502  symbols[1] = polar(1, 2, 1);
503  printf("cstln_lut::cstln_lut: BPSK at 0 degrees\n");
504 #else // BPSK at 45°
505  symbols[0] = polar(1, 8, 1);
506  symbols[1] = polar(1, 8, 5);
507  printf("cstln_lut::cstln_lut: BPSK at 45 degrees\n");
508 #endif
510  break;
511  case QPSK:
512  amp_max = 1;
513  // EN 300 421, section 4.5 Baseband shaping and modulation
514  // EN 302 307, section 5.4.1
515  nrotations = 4;
516  nsymbols = 4;
517  symbols = new complex<signed char>[nsymbols];
518  symbols[0] = polar(1, 4, 0.5);
519  symbols[1] = polar(1, 4, 3.5);
520  symbols[2] = polar(1, 4, 1.5);
521  symbols[3] = polar(1, 4, 2.5);
523  printf("cstln_lut::cstln_lut: QPSK\n");
524  break;
525  case PSK8:
526  amp_max = 1;
527  // EN 302 307, section 5.4.2
528  nrotations = 8;
529  nsymbols = 8;
530  symbols = new complex<signed char>[nsymbols];
531  symbols[0] = polar(1, 8, 1);
532  symbols[1] = polar(1, 8, 0);
533  symbols[2] = polar(1, 8, 4);
534  symbols[3] = polar(1, 8, 5);
535  symbols[4] = polar(1, 8, 2);
536  symbols[5] = polar(1, 8, 7);
537  symbols[6] = polar(1, 8, 3);
538  symbols[7] = polar(1, 8, 6);
540  printf("cstln_lut::cstln_lut: PSK8\n");
541  break;
542  case APSK16:
543  {
544  // Default gamma for non-DVB-S2 applications.
545  if (gamma1 == 0)
546  gamma1 = 2.57;
547  // EN 302 307, section 5.4.3
548  float r1 = sqrtf(4.0f / (1.0f + 3.0f * gamma1 * gamma1));
549  float r2 = gamma1 * r1;
550  amp_max = r2;
551  nrotations = 4;
552  nsymbols = 16;
553  symbols = new complex<signed char>[nsymbols];
554  symbols[0] = polar(r2, 12, 1.5);
555  symbols[1] = polar(r2, 12, 10.5);
556  symbols[2] = polar(r2, 12, 4.5);
557  symbols[3] = polar(r2, 12, 7.5);
558  symbols[4] = polar(r2, 12, 0.5);
559  symbols[5] = polar(r2, 12, 11.5);
560  symbols[6] = polar(r2, 12, 5.5);
561  symbols[7] = polar(r2, 12, 6.5);
562  symbols[8] = polar(r2, 12, 2.5);
563  symbols[9] = polar(r2, 12, 9.5);
564  symbols[10] = polar(r2, 12, 3.5);
565  symbols[11] = polar(r2, 12, 8.5);
566  symbols[12] = polar(r1, 4, 0.5);
567  symbols[13] = polar(r1, 4, 3.5);
568  symbols[14] = polar(r1, 4, 1.5);
569  symbols[15] = polar(r1, 4, 2.5);
571  printf("cstln_lut::cstln_lut: APSK16: gamma1=%f r1=%f r2=%f\n", gamma1, r1, r2);
572  break;
573  }
574  case APSK32:
575  {
576  // Default gammas for non-DVB-S2 applications.
577  if (gamma1 == 0)
578  gamma1 = 2.53;
579  if (gamma2 == 0)
580  gamma2 = 4.30;
581  // EN 302 307, section 5.4.3
582  float r1 = sqrtf(
583  8.0f / (1.0f + 3.0f * gamma1 * gamma1 + 4 * gamma2 * gamma2));
584  float r2 = gamma1 * r1;
585  float r3 = gamma2 * r1;
586  amp_max = r3;
587  nrotations = 4;
588  nsymbols = 32;
589  symbols = new complex<signed char>[nsymbols];
590  symbols[0] = polar(r2, 12, 1.5);
591  symbols[1] = polar(r2, 12, 2.5);
592  symbols[2] = polar(r2, 12, 10.5);
593  symbols[3] = polar(r2, 12, 9.5);
594  symbols[4] = polar(r2, 12, 4.5);
595  symbols[5] = polar(r2, 12, 3.5);
596  symbols[6] = polar(r2, 12, 7.5);
597  symbols[7] = polar(r2, 12, 8.5);
598  symbols[8] = polar(r3, 16, 1);
599  symbols[9] = polar(r3, 16, 3);
600  symbols[10] = polar(r3, 16, 14);
601  symbols[11] = polar(r3, 16, 12);
602  symbols[12] = polar(r3, 16, 6);
603  symbols[13] = polar(r3, 16, 4);
604  symbols[14] = polar(r3, 16, 9);
605  symbols[15] = polar(r3, 16, 11);
606  symbols[16] = polar(r2, 12, 0.5);
607  symbols[17] = polar(r1, 4, 0.5);
608  symbols[18] = polar(r2, 12, 11.5);
609  symbols[19] = polar(r1, 4, 3.5);
610  symbols[20] = polar(r2, 12, 5.5);
611  symbols[21] = polar(r1, 4, 1.5);
612  symbols[22] = polar(r2, 12, 6.5);
613  symbols[23] = polar(r1, 4, 2.5);
614  symbols[24] = polar(r3, 16, 0);
615  symbols[25] = polar(r3, 16, 2);
616  symbols[26] = polar(r3, 16, 15);
617  symbols[27] = polar(r3, 16, 13);
618  symbols[28] = polar(r3, 16, 7);
619  symbols[29] = polar(r3, 16, 5);
620  symbols[30] = polar(r3, 16, 8);
621  symbols[31] = polar(r3, 16, 10);
623  printf("cstln_lut::cstln_lut: APSK32: gamma1=%f gamma2=%f, r1=%f r2=%f r3=%f\n", gamma1, gamma2, r1, r2, r3);
624  break;
625  }
626  case APSK64E:
627  {
628  // Default gammas for non-DVB-S2 applications.
629  if (gamma1 == 0)
630  gamma1 = 2.4;
631  if (gamma2 == 0)
632  gamma2 = 4.3;
633  if (gamma3 == 0)
634  gamma3 = 7.0;
635  // EN 302 307-2, section 5.4.5, Table 13e
636  float r1 = sqrtf(
637  64.0f / (4.0f + 12.0f * gamma1 * gamma1 + 20.0f * gamma2 * gamma2 + 28.0f * gamma3 * gamma3));
638  float r2 = gamma1 * r1;
639  float r3 = gamma2 * r1;
640  float r4 = gamma3 * r1;
641  amp_max = r4;
642  nrotations = 4;
643  nsymbols = 64;
644  symbols = new complex<signed char>[nsymbols];
645  polar2(0, r4, 1.0 / 4, 7.0 / 4, 3.0 / 4, 5.0 / 4);
646  polar2(4, r4, 13.0 / 28, 43.0 / 28, 15.0 / 28, 41.0 / 28);
647  polar2(8, r4, 1.0 / 28, 55.0 / 28, 27.0 / 28, 29.0 / 28);
648  polar2(12, r1, 1.0 / 4, 7.0 / 4, 3.0 / 4, 5.0 / 4);
649  polar2(16, r4, 9.0 / 28, 47.0 / 28, 19.0 / 28, 37.0 / 28);
650  polar2(20, r4, 11.0 / 28, 45.0 / 28, 17.0 / 28, 39.0 / 28);
651  polar2(24, r3, 1.0 / 20, 39.0 / 20, 19.0 / 20, 21.0 / 20);
652  polar2(28, r2, 1.0 / 12, 23.0 / 12, 11.0 / 12, 13.0 / 12);
653  polar2(32, r4, 5.0 / 28, 51.0 / 28, 23.0 / 28, 33.0 / 28);
654  polar2(36, r3, 9.0 / 20, 31.0 / 20, 11.0 / 20, 29.0 / 20);
655  polar2(40, r4, 3.0 / 28, 53.0 / 28, 25.0 / 28, 31.0 / 28);
656  polar2(44, r2, 5.0 / 12, 19.0 / 12, 7.0 / 12, 17.0 / 12);
657  polar2(48, r3, 1.0 / 4, 7.0 / 4, 3.0 / 4, 5.0 / 4);
658  polar2(52, r3, 7.0 / 20, 33.0 / 20, 13.0 / 20, 27.0 / 20);
659  polar2(56, r3, 3.0 / 20, 37.0 / 20, 17.0 / 20, 23.0 / 20);
660  polar2(60, r2, 1.0 / 4, 7.0 / 4, 3.0 / 4, 5.0 / 4);
662  printf("cstln_lut::cstln_lut: APSK64E: gamma1=%f gamma2=%f, gamm3=%f r1=%f r2=%f r3=%f r4=%f\n", gamma1, gamma2, gamma3, r1, r2, r3, r4);
663  break;
664  }
665  case QAM16:
666  amp_max = 0;
667  make_qam(16);
668  break;
669  case QAM64:
670  amp_max = 1;
671  make_qam(64);
672  break;
673  case QAM256:
674  amp_max = 1;
675  make_qam(256);
676  break;
677  default:
678  fail("Constellation not implemented");
679  }
680  }
complex< signed char > polar(float r, int n, float i)
Definition: sdr.h:716
void make_qam(int n)
Definition: sdr.h:736
float amp_max
Definition: sdr.h:477
void make_lut_from_symbols(float mer)
Definition: sdr.h:770
void fail(const char *s)
Definition: framework.cpp:11
void polar2(int i, float r, float a0, float a1, float a2, float a3)
Definition: sdr.h:724
complex< int8_t > * symbols
Definition: sdr.h:478

Member Function Documentation

◆ dump()

template<typename SOFTSYMB, int R>
void leansdr::cstln_lut< SOFTSYMB, R >::dump ( FILE *  f)
inline

Definition at line 839 of file sdr.h.

840  {
841  int bps = log2(nsymbols);
842  fprintf(f, "P5\n%d %d\n255\n", R, R * (bps + 1));
843 
844  for (int bit = 0; bit < bps + 1; ++bit)
845  {
846  for (int Q = R / 2 - 1; Q >= -R / 2; --Q)
847  {
848  for (int I = -R / 2; I < R / 2; ++I)
849  {
850  result *pr = &lut[I & (R - 1)][Q & (R - 1)];
851  uint8_t v;
852  if (bit < bps)
853  v = softsymb_to_dump(pr->ss, bit);
854  else
855  v = 128 + pr->phase_error / 64;
856  // Highlight the constellation symbols.
857  for (int s = 0; s < nsymbols; ++s)
858  {
859  if (symbols[s].re == I && symbols[s].im == Q)
860  v ^= 128;
861  }
862 
863  fputc(v, f);
864  }
865  }
866  }
867  }
unsigned char uint8_t
Definition: rtptypes_win.h:42
uint8_t softsymb_to_dump(const llr_ss &ss, int bit)
Definition: sdr.cpp:38
complex< int8_t > * symbols
Definition: sdr.h:478
result lut[R][R]
Definition: sdr.h:768

◆ harden()

template<typename SOFTSYMB, int R>
void leansdr::cstln_lut< SOFTSYMB, R >::harden ( )
inline

Definition at line 870 of file sdr.h.

871  {
872  for (int i = 0; i < R; ++i)
873  {
874  for (int q = 0; q < R; ++q)
875  softsymb_harden(&lut[i][q].ss);
876  }
877  }
void softsymb_harden(llr_ss *ss)
Definition: sdr.cpp:20
int32_t i
Definition: decimators.h:244
result lut[R][R]
Definition: sdr.h:768

◆ lookup() [1/2]

template<typename SOFTSYMB, int R>
result* leansdr::cstln_lut< SOFTSYMB, R >::lookup ( float  I,
float  Q 
)
inline

Definition at line 689 of file sdr.h.

Referenced by leansdr::viterbi_sync::init_map(), leansdr::cstln_receiver< leansdr::f32, leansdr::eucl_ss >::run(), and leansdr::s2_frame_receiver< T, SOFTSYMB >::track_symbol().

690  {
691  // Handling of overflows beyond the lookup table:
692  // - For BPSK/QPSK/8PSK we only care about the phase,
693  // so the following is harmless and improves locking at low SNR.
694  // - For amplitude modulations this is not appropriate.
695  // However, if there is enough noise to cause overflow,
696  // demodulation would probably fail anyway.
697  //
698  // Comment-out for better throughput at high SNR.
699 #if 1
700  while (I < -128 || I > 127 || Q < -128 || Q > 127)
701  {
702  I *= 0.5;
703  Q *= 0.5;
704  }
705 #endif
706  return &lut[(u8)(s8)I][(u8)(s8)Q];
707  }
unsigned char u8
Definition: framework.h:453
signed char s8
Definition: framework.h:456
result lut[R][R]
Definition: sdr.h:768
+ Here is the caller graph for this function:

◆ lookup() [2/2]

template<typename SOFTSYMB, int R>
result* leansdr::cstln_lut< SOFTSYMB, R >::lookup ( int  I,
int  Q 
)
inline

Definition at line 709 of file sdr.h.

710  {
711  // Ignore wrapping modulo 256
712  return &lut[(u8)I][(u8)Q];
713  }
unsigned char u8
Definition: framework.h:453
result lut[R][R]
Definition: sdr.h:768

◆ make_lut_from_symbols()

template<typename SOFTSYMB, int R>
void leansdr::cstln_lut< SOFTSYMB, R >::make_lut_from_symbols ( float  mer)
inlineprivate

Definition at line 770 of file sdr.h.

771  {
772  // Note: Excessively low values of MER will break 16APSK and 32APSK.
773  float sigma = cstln_amp * pow(10.0, (-mer / 20));
774 
775  // Precomputed values.
776  // Shared scope so that we don't have to reset dists2[nsymbols..] to -1.
777  struct full_ss fss;
778 
779  for (int s = 0; s < 256; ++s)
780  fss.dists2[s] = -1;
781 
782  for (int I = -R / 2; I < R / 2; ++I)
783  {
784  for (int Q = -R / 2; Q < R / 2; ++Q)
785  {
786  // Nearest symbol
787  fss.nearest = 0;
788  fss.dists2[0] = 65535;
789  // Conditional probabilities:
790  // Sum likelyhoods from all candidate symbols.
791  //
792  // P(TX[b]==B | RX==IQ) =
793  // sum(S=0..nsymbols-1, P(TX[b]==B | RX==IQ && TXs==S))
794  //
795  // P(TX[b] == B | RX==IQ && TX==S) =
796  // P(TX[b]==B && RX==IQ && TX==S) / P(RX==IQ && TX==S)
797  float probs[8][2];
798  memset(probs, 0, sizeof(probs));
799 
800  for (int s = 0; s < nsymbols; ++s)
801  {
802  float d2 = ((I - symbols[s].re) * (I - symbols[s].re) + (Q - symbols[s].im) * (Q - symbols[s].im));
803 
804  if (d2 < fss.dists2[fss.nearest])
805  fss.nearest = s;
806 
807  fss.dists2[s] = d2;
808  float p = expf(-d2 / (2 * sigma * sigma)) / (sqrtf(2 * M_PI) * sigma);
809 
810  for (int bit = 0; bit < 8; ++bit)
811  {
812  probs[bit][(s >> bit) & 1] += p;
813  }
814  }
815 
816  // Normalize
817  for (int b = 0; b < 8; ++b)
818  {
819  float p = probs[b][1] / (probs[b][0] + probs[b][1]);
820  // Avoid trouble when sigma is unrealistically low.
821  if (!isnormal(p))
822  p = 0;
823  fss.p[b] = p;
824  }
825 
826  result *pr = &lut[I & (R - 1)][Q & (R - 1)];
827  to_softsymb(&fss, &pr->ss);
828  // Always record nearest symbol and phase error for C&T.
829  pr->symbol = fss.nearest;
830  float ph_symbol = atan2f(symbols[pr->symbol].im,
831  symbols[pr->symbol].re);
832  float ph_err = atan2f(Q, I) - ph_symbol;
833  pr->phase_error = (int32_t)(ph_err * 65536 / (2 * M_PI)); // Mod 65536
834  }
835  }
836  }
void to_softsymb(const full_ss *fss, hard_ss *ss)
Definition: sdr.cpp:55
#define M_PI
Definition: rdsdemod.cpp:27
int int32_t
Definition: rtptypes_win.h:45
complex< int8_t > * symbols
Definition: sdr.h:478
const float cstln_amp
Definition: sdr.h:404
result lut[R][R]
Definition: sdr.h:768

◆ make_qam()

template<typename SOFTSYMB, int R>
void leansdr::cstln_lut< SOFTSYMB, R >::make_qam ( int  n)
inlineprivate

Definition at line 736 of file sdr.h.

737  {
738  nrotations = 4;
739  nsymbols = n;
740  symbols = new complex<signed char>[nsymbols];
741  int m = sqrtl(n);
742  float scale;
743 
744  { // Average power in first quadrant with unit grid
745  int q = m / 2;
746  float avgpower = 2 * (q * 0.25 + (q - 1) * q / 2.0 + (q - 1) * q * (2 * q - 1) / 6.0) / q;
747  scale = 1.0 / sqrtf(avgpower);
748  }
749  // Arbitrary mapping
750 
751  int s = 0;
752 
753  for (int x = 0; x < m; ++x)
754  {
755  for (int y = 0; y < m; ++y)
756  {
757  float I = x - (float)(m - 1) / 2;
758  float Q = y - (float)(m - 1) / 2;
759  symbols[s].re = I * scale * cstln_amp;
760  symbols[s].im = Q * scale * cstln_amp;
761  ++s;
762  }
763  }
764 
765  make_lut_from_symbols(20); // TBD
766  }
void make_lut_from_symbols(float mer)
Definition: sdr.h:770
complex< int8_t > * symbols
Definition: sdr.h:478
const float cstln_amp
Definition: sdr.h:404

◆ polar()

template<typename SOFTSYMB, int R>
complex<signed char> leansdr::cstln_lut< SOFTSYMB, R >::polar ( float  r,
int  n,
float  i 
)
inlineprivate

Definition at line 716 of file sdr.h.

717  {
718  float a = i * 2 * M_PI / n;
719  return complex<signed char>(r * cosf(a) * cstln_amp,
720  r * sinf(a) * cstln_amp);
721  }
#define M_PI
Definition: rdsdemod.cpp:27
int32_t i
Definition: decimators.h:244
const float cstln_amp
Definition: sdr.h:404

◆ polar2()

template<typename SOFTSYMB, int R>
void leansdr::cstln_lut< SOFTSYMB, R >::polar2 ( int  i,
float  r,
float  a0,
float  a1,
float  a2,
float  a3 
)
inlineprivate

Definition at line 724 of file sdr.h.

725  {
726  float a[] = {a0, a1, a2, a3};
727 
728  for (int j = 0; j < 4; ++j)
729  {
730  float phi = a[j] * M_PI;
731  symbols[i + j] = complex<signed char>(r * cosf(phi) * cstln_amp,
732  r * sinf(phi) * cstln_amp);
733  }
734  }
#define M_PI
Definition: rdsdemod.cpp:27
int32_t i
Definition: decimators.h:244
complex< int8_t > * symbols
Definition: sdr.h:478
const float cstln_amp
Definition: sdr.h:404

Member Data Documentation

◆ lut

template<typename SOFTSYMB, int R>
result leansdr::cstln_lut< SOFTSYMB, R >::lut[R][R]
private

Definition at line 768 of file sdr.h.

◆ m_rateCode

template<typename SOFTSYMB, int R>
int leansdr::cstln_lut< SOFTSYMB, R >::m_rateCode

Definition at line 880 of file sdr.h.

Referenced by leansdr::s2_frame_receiver< T, SOFTSYMB >::run_frame_locked().

◆ m_setByModcod

template<typename SOFTSYMB, int R>
bool leansdr::cstln_lut< SOFTSYMB, R >::m_setByModcod

Definition at line 881 of file sdr.h.

◆ m_typeCode

template<typename SOFTSYMB, int R>
int leansdr::cstln_lut< SOFTSYMB, R >::m_typeCode

Definition at line 879 of file sdr.h.


The documentation for this struct was generated from the following file: