Looking at the Symbolic Modulation

How to encode the data set

The RDS data stream is generated as a series of bytes. This has to be converted to a stream of sysmbols, that in turn decide the information to be sent to the DAC.

Conversion of the data set to symbolic information

The differential encoding consists of taking bit pairs and generating a change or no change of state. The result is placed back into the same bit as the later of the bits pair

void EncodeDifferential(void) 
{
  //  Take the payload and differential encode into differential_encoded_payload.
  //  Works at bit level
  //  There is a maximum PAYLOAD_SIZE of bytes and payload.part.frame_count of active frames  
  //  Between bytes and last bit last byte wrap
  //  Prime the start
  word size = (payload.part.frame_count * 13);
  byte value = 0;
  byte shift = 0;
  int i = 0;
  byte b_next = 0x00;
  //  At the start the previous bit is unknown could have been 0 or 1. We try 0 first
  byte b_previous = 0;
  //  Empty the differental array
  for(i = 0; i < size; i++) differential_encoded_payload[i] = 0x00;
  for(i = 0; i < size; i++) 
  {
    //  Run along the bytes. The shift is offset by 1
    value = payload.frame_byte[i];
    for(shift = 8; shift > 0; shift--) 
    {
      //  Run along the bits
      b_next = (byte)((value >> (shift - 1)) & 0x01);
      //  Encode
      //  If the bit is set place the bit
      if(b_previous != b_next) 
      {
        switch (shift) 
        {
          case 8:
            differential_encoded_payload[i] |= 0x80;
            break;
          case 7:
            differential_encoded_payload[i] |= 0x40;
            break;
          case 6:
            differential_encoded_payload[i] |= 0x20;
            break;
          case 5:
            differential_encoded_payload[i] |= 0x10;
            break;
          case 4:
            differential_encoded_payload[i] |= 0x08;
            break;
          case 3:
            differential_encoded_payload[i] |= 0x04;
            break;
          case 2:
            differential_encoded_payload[i] |= 0x02;
            break;
          case 1:
            differential_encoded_payload[i] |= 0x01;
            break;   
        }
        b_previous = 1;
      } //  End of bit set
      else b_previous = 0;  //  Update previous to current output
    }
  }
}

The encoding must form a consistent circle, with the last bit (n = 0-1) unknown when the encoding starts.

There are 8 possible symbols (P0..P7) as per a window of three differentially encoded bits.


void EncodeModulationSymbols(byte set) 
{
  //  Takes the differential_encoded_payload and converts to symbols in modulation_data
  //  P0    u d u d u d == 1 1 1
  //  P1    d u d u d u == 0 0 0
  //  P2    d u u d d u == 0 1 0
  //  P3    u d d u u d == 1 0 1
  //  P4    u d u d d u == 1 1 0
  //  P5    d u d u u d == 0 0 1
  //  P6    d u u d u d == 0 1 1
  //  P7    u d d u d u == 1 0 0
  //  Three bits are required to decide on each symbol
  //  Initialise with last bit of sequence, first bit of sequence 
  word i = 0; //  The symbol
  byte j = 6; //  The bit position in the byte
  word k = 0; //  The payload byte
  word l = 0; //  modulation_data position
  word number_of_symbols = 0;
  word symbol = 0;
  //  bytes are assigned to the bit value
  byte bLast = (differential_encoded_payload[((payload.part.frame_count * 13) - 1)] & 0x01);
  byte bFirst = (differential_encoded_payload[0] & 0x80);
  byte bNext = 0;
  byte bActual = bFirst;
  byte bPrevious = bLast;
  byte symbol_place_mark = 0;
  //  The first symbol to next to last
  //  The number of symbols is calculated from payload.part.frame_count
  number_of_symbols = payload.part.frame_count * 13 * 8;
  for(i = 0; i < number_of_symbols; i++) 
  {
    symbol = 0x0000;
  //  Special case on last symbol, this overlaps into the first element
    if(i == (number_of_symbols - 1)) bNext = bFirst;  
    else 
    {
      if(j == 0) bNext = (differential_encoded_payload[k] & 0x01);
      else if (j == 1) bNext = (differential_encoded_payload[k] & 0x02);
      else if (j == 2) bNext = (differential_encoded_payload[k] & 0x04);
      else if (j == 3) bNext = (differential_encoded_payload[k] & 0x08);
      else if (j == 4) bNext = (differential_encoded_payload[k] & 0x10);
      else if (j == 5) bNext = (differential_encoded_payload[k] & 0x20);
      else if (j == 6) bNext = (differential_encoded_payload[k] & 0x40);
      else if (j == 7) bNext = (differential_encoded_payload[k] & 0x80);
      if(j == 0) 
      {
        k++;   // Go to next payload byte and msbit
        j = 7;
      }
      else j--;
    }
    if(bPrevious) symbol |= 0x0004;
    if(bActual) symbol |= 0x0002;
    if(bNext) symbol |= 0x0001;
    //  The symbol code has been obtained. There are 4 symbols per word
    if(set == 0) 
    {
      switch (symbol_place_mark) 
      {
        case 3:
          current_data_set[l] |= (word)((word)symbol & 0x000F);
          l++;  //  Increment for next data position
          break;
        case 2:
          current_data_set[l] |= (word)(((word)symbol << 4) & 0x00F0);
          break;
        case 1:
          current_data_set[l] |= (word)(((word)symbol << 8) & 0x0F00);
          break;
        case 0:
          current_data_set[l] = (word)(((word)symbol << 12) & 0xF000);
          break;
      }
    }
    //  Shift elements
    bPrevious = bActual;
    bActual = bNext;
    symbol_place_mark++;
    if(symbol_place_mark > 3) symbol_place_mark = 0;
  }
  //  Modulation_data is now encoded in symbol codes, 4 per modulation_data element
  //  1 x symbol = 1 x bit. 1 x word = 4 x bit, 1664 x words = 832 x bytes. 832 x bytes = 64 x frame. 1 x frame = 13 bytes.
}

First a window of three bits is defined. This bit sequence gives the symbol 000 ... 0111

Then the symbols are packed 4 per word (this is a word based CPU .

With this information the modulator determines the symbol to be transmitted.