RDS CRC Prüfbit Berechnung

#3607851
Lesenswert?

Geschätzes Forum,

ich habe mal RDS-Rohdaten mitgeschnitten und in der XLS-Datei etwas 
aufbereitet.

Meine Frage:

Wie kann man die Prüfbits bzw. CRC berechnen, mit der Norm EN50067 
(s.Anhang) werde ich nicht schlau.

Vielleicht könnt Ihr mir mal einfach erklären, wie die Berechnung 
erfolgt.


Die Prüfbittberechnung ist ein Teil von diesem Projekt:

Beitrag "RDS DECODER analog Schaltung ohne IC gesucht, für Rohdatengewinnung"

Danke


Bernhard
Angehängte Dateien:
#3609809
Lesenswert?

@alle

zu einer kleinen Erkenntnis kam ich.

Beim Gruppentyp "D" ist mir etwas aufgefallen,

wenn alle 16 Datenbits  NULL sind,

dann sind die Prüfbits (Checkword und Offset) gleich dem

Tabelleneintrag im Annex A im Page59 der EN50067.


@Detlef Kunz

ich danke Dir, hab mal geschaut, leider blieb der "Aha"-Efekt noch aus.

Bernhard
Angehängte Dateien:
#3610704
Lesenswert?

Q+D
Ich hoffe das hilft.
1
#include <stdio.h>
2
#include <stdint.h>
3
#include <stdlib.h>
4

5
#define OFFSET_WORD_A 0x0FC
6

7
unsigned int calc_rds_crc (uint16_t data)
8
{
9
  int i;
10
  uint16_t polynom=0x05B9;
11
  uint16_t BitMask=0x8000;
12
  uint16_t crc = 0;
13

14
  for (i=16; i>0; i--)   //das ganze 16 mal (einmal für jedes Datenbit)
15
  {
16
    crc = crc << 1;      //CRC um ein Bit nach links schieben, dabei wird Bit0 mit 0 aufgefüllt
17

18
    if (data & BitMask)  //Bitmaske testet in der Schleife nacheinander alle Datenbits beginnend bei D0
19
      crc = crc | 1;     //ist das Datenbit 1, dann wird Bit 0 von CRC gesetzt, ansonsten bleibt es 0 
20

21
    if (crc & 0x0400)       //Bit10 dec CRC testen
22
      crc = crc ^ polynom;  //wenn es gesetzt ist, dann CRC mit POLYNOM XOR-Verknüpfen
23

24
    BitMask >>= 1;  //Bitmaske nach recht schieben für das nächste Bit
25
        }
26

27
//und noch ne Schleife
28
  for (i=10;i>0;i--)   //einmal für jedes Polynombit (also 10 mal)
29
  {
30
    crc = crc << 1;      //CRC ein Bit nach links
31

32
    if (crc & (1<<10))      //ist das 10. Bit gesetzt?
33
      crc = crc ^ polynom;  //ja, dann CRC mit POLYNOM XOR-Verknüpfen
34
        }
35

36
        return crc  & 0x3ff;   //die 10 Bit des CRC als Ergebnis liefern
37
}
38

39

40

41
int main(int argc, char *argv[])
42
{
43

44

45
  printf("test: %x\n", calc_rds_crc(0xd4f1) ^ OFFSET_WORD_A); //Das CRC mit dem OFFSET_WORD XOR-Verknüpft ergibt dein Ergebnis
46

47
  return EXIT_SUCCESS;
48
}
#3613344
Lesenswert?

So, sieht netwas besser aus.
1
#include <stdio.h>
2
#include <stdint.h>
3
#include <stdlib.h>
4

5
#define OFFSET_WORD_A 0x0FC
6

7
unsigned int calc_rds_crc (uint16_t data)
8
{
9
  int i;
10
  uint16_t polynom=0x05B9;
11
  uint16_t BitMask=0x8000;
12
  uint16_t crc = 0;
13

14
//-erste Schleife--------------------------
15
  for (i=16; i>0; i--)   //das ganze 16 mal (einmal für jedes Datenbit)
16
  {
17
    crc = crc << 1;      //CRC um ein Bit nach links schieben, dabei wird Bit0 mit 0 aufgefüllt
18

19
    if (data & BitMask)  //Bitmaske testet in der Schleife nacheinander alle Datenbits beginnend bei D0
20
      crc = crc | 1;     //ist das Datenbit 1, dann wird Bit 0 von CRC gesetzt, ansonsten bleibt es 0 
21

22
    if (crc & 0x0400)       //Bit10 dec CRC testen
23
      crc = crc ^ polynom;  //wenn es gesetzt ist, dann CRC mit POLYNOM XOR-Verknüpfen
24

25
    BitMask >>= 1;  //Bitmaske nach recht schieben für das nächste Bit
26
  }
27

28
//-zweite Schleife--------------------------
29
  for (i=10;i>0;i--)   //einmal für jedes Polynombit (also 10 mal)
30
  {
31
    crc = crc << 1;      //CRC ein Bit nach links
32

33
    if (crc & (1<<10))      //ist das 10. Bit gesetzt?
34
      crc = crc ^ polynom;  //ja, dann CRC mit POLYNOM XOR-Verknüpfen
35
  }
36

37
  return crc  & 0x3ff;   //die 10 Bit des CRC als Ergebnis liefern
38
}
39

40

41

42
int main(int argc, char *argv[])
43
{
44

45

46
  printf("test: %x\n", calc_rds_crc(0xd4f1) ^ OFFSET_WORD_A); //Das CRC mit dem OFFSET_WORD XOR-Verknüpft ergibt dein Ergebnis
47

48
  return EXIT_SUCCESS;
49
}
#3613369
Lesenswert?

noch ein etwas optimiert
1
unsigned int calc_rds_crc (uint16_t data)
2
{
3
  int i;
4
  uint16_t polynom=0x05B9;
5
  uint16_t BitMask=0x8000;
6
  uint16_t crc = 0;
7

8
  uint16_t tmp = data;
9
  for (i=26; i>0; i--)                       //das ganze 16 mal (einmal für jedes Datenbit) PLUS 10 mal mit 0-Bits
10
  {
11
    crc = crc << 1 | ((tmp & 0x8000)>>15);   //CRC um ein Bit nach links schieben, dabei wird Bit0 mit einem Datenbit ausgefüllt
12

13
    if (crc & 0x0400)                        //Bit10 des CRC testen
14
      crc = crc ^ polynom;                   //wenn es gesetzt ist, dann CRC mit POLYNOM XOR-Verknüpfen
15

16
    tmp <<= 1;                               //nächstes Datenbit in Position bringen
17
  }
18

19
  return crc  & 0x3ff;                       //die 10 Bit des CRC als Ergebnis liefern
20
}
#3613394
Lesenswert?

Das müsste die erste Schleife sein, wenn ich es richtig gedeutet habe.

Ich hoffe es hat sich kein Fehler eingschlichen, denn bis jetzt habe ich 
keine Kontrollmöglichkeit.

Detlef, könntest Du mir mal die Zwischenergebnisse der Schleife 1 und 2 
zur Verfügung stellen, wenn Data x8000 also 0b1000000000000000 ist?


Die Daten und CRC stammen von einem RDS Mittschnitt, müsste fehlerfrei 
sein.


>Vergiß nicht die Xor-Verknüpfung des Ergebnis mit dem Offset_Word zum
>Schluß!

ok, ich denke dran ;-)

Bernhard
Angehängte Dateien:
#3613533
Lesenswert?

@alle

ein kleiner RDS CRC Prüfbit Rechner Calculator in Excel.

Die 16-Bit Daten können hexadzimal eingegeben werden z.B. D4F1.

Im Ergebnis der Berechnung werden die Prüfsummen für alle Gruppentypen / 
RDS Gruppen ausgegeben.

@Detlef

könntest Du mir mal bitte diesen Rechner für x01 bis x20 testen. Habe 
jetzt tagelang RDS-Daten mitgeschnitten, aber solche Datenbits wurden 
nicht gesendet.

Bernhard
Angehängte Dateien:
#3613553
Lesenswert?

Sowas?
1
Data: 0x0001     crc: 0x1b9      A: 0x145        C: 0x021        B: 0x0d1        D: 0x00d
2
Data: 0x0002     crc: 0x372      A: 0x38e        C: 0x2ea        B: 0x21a        D: 0x2c6
3
Data: 0x0003     crc: 0x2cb      A: 0x237        C: 0x353        B: 0x3a3        D: 0x37f
4
Data: 0x0004     crc: 0x35d      A: 0x3a1        C: 0x2c5        B: 0x235        D: 0x2e9
5
Data: 0x0005     crc: 0x2e4      A: 0x218        C: 0x37c        B: 0x38c        D: 0x350
6
Data: 0x0006     crc: 0x02f      A: 0x0d3        C: 0x1b7        B: 0x147        D: 0x19b
7
Data: 0x0007     crc: 0x196      A: 0x16a        C: 0x00e        B: 0x0fe        D: 0x022
8
Data: 0x0008     crc: 0x303      A: 0x3ff        C: 0x29b        B: 0x26b        D: 0x2b7
9
Data: 0x0009     crc: 0x2ba      A: 0x246        C: 0x322        B: 0x3d2        D: 0x30e
10
Data: 0x000a     crc: 0x071      A: 0x08d        C: 0x1e9        B: 0x119        D: 0x1c5
11
Data: 0x000b     crc: 0x1c8      A: 0x134        C: 0x050        B: 0x0a0        D: 0x07c
12
Data: 0x000c     crc: 0x05e      A: 0x0a2        C: 0x1c6        B: 0x136        D: 0x1ea
13
Data: 0x000d     crc: 0x1e7      A: 0x11b        C: 0x07f        B: 0x08f        D: 0x053
14
Data: 0x000e     crc: 0x32c      A: 0x3d0        C: 0x2b4        B: 0x244        D: 0x298
15
Data: 0x000f     crc: 0x295      A: 0x269        C: 0x30d        B: 0x3fd        D: 0x321
16
Data: 0x0010     crc: 0x3bf      A: 0x343        C: 0x227        B: 0x2d7        D: 0x20b
17
Data: 0x0011     crc: 0x206      A: 0x2fa        C: 0x39e        B: 0x36e        D: 0x3b2
18
Data: 0x0012     crc: 0x0cd      A: 0x031        C: 0x155        B: 0x1a5        D: 0x179
19
Data: 0x0013     crc: 0x174      A: 0x188        C: 0x0ec        B: 0x01c        D: 0x0c0
20
Data: 0x0014     crc: 0x0e2      A: 0x01e        C: 0x17a        B: 0x18a        D: 0x156
21
Data: 0x0015     crc: 0x15b      A: 0x1a7        C: 0x0c3        B: 0x033        D: 0x0ef
22
Data: 0x0016     crc: 0x390      A: 0x36c        C: 0x208        B: 0x2f8        D: 0x224
23
Data: 0x0017     crc: 0x229      A: 0x2d5        C: 0x3b1        B: 0x341        D: 0x39d
24
Data: 0x0018     crc: 0x0bc      A: 0x040        C: 0x124        B: 0x1d4        D: 0x108
25
Data: 0x0019     crc: 0x105      A: 0x1f9        C: 0x09d        B: 0x06d        D: 0x0b1
26
Data: 0x001a     crc: 0x3ce      A: 0x332        C: 0x256        B: 0x2a6        D: 0x27a
27
Data: 0x001b     crc: 0x277      A: 0x28b        C: 0x3ef        B: 0x31f        D: 0x3c3
28
Data: 0x001c     crc: 0x3e1      A: 0x31d        C: 0x279        B: 0x289        D: 0x255
29
Data: 0x001d     crc: 0x258      A: 0x2a4        C: 0x3c0        B: 0x330        D: 0x3ec
30
Data: 0x001e     crc: 0x093      A: 0x06f        C: 0x10b        B: 0x1fb        D: 0x127
31
Data: 0x001f     crc: 0x12a      A: 0x1d6        C: 0x0b2        B: 0x042        D: 0x09e
32
Data: 0x0020     crc: 0x2c7      A: 0x23b        C: 0x35f        B: 0x3af        D: 0x373
#3613911
Lesenswert?

@alle

Eine VBA Visual Basic Variante.

Ein Datenstring von 26 Bites wird an die Funktion übergeben als Antwort 
erhält man eine 0 für Error (z.B. CRC Error), 1 für Gruppe-A, 2 für 
Gruppe-B, 3 für Gruppe-C, 4 für die Gruppe-D.



Public Function BERECHNUNG_CRC(INP As String) As Byte
' INPUT: STRING 26 BYTES
' z.B.  ("10000000000000000111000011")
'       ("11010100111100011010001111")
' OUT:
'   0= Error
'   1=Gruppe A
'   2=Gruppe B
'   3=Gruppe C
'   4=Gruppe D
Dim i As Integer
Dim ZWISCHENERGEBNIS1
Dim ZWISCHENERGEBNIS2
Dim DATA As Double
Dim CRC_OLD As Double
Dim CRC As Double
Dim CRC_GRUPPE_A
Dim CRC_GRUPPE_B
Dim CRC_GRUPPE_C
Dim CRC_GRUPPE_D
'----------------------------------------------------------------------- 
------------------
' Länge-Check
If Len(INP) <> 26 Then Exit Function
' DATA UMWANDELN
For i = 0 To 15
    DATA = DATA + Mid(INP, 16 - i, 1) * 2 ^ i
Next i
' CRC-OLD UMWANDELN
For i = 0 To 9
    CRC_OLD = CRC_OLD + Mid(INP, 26 - i, 1) * 2 ^ i
Next i
'----------------------------------------------------------------------- 
------------------
' 1. Schleife 16xDatenbits behandeln
For i = 0 To 15
    DATA = DATA * 2             ' DATA 1 x links
        If DATA > &HFFFF& Then  ' mehr als 16 Bits ?
            CRC = CRC * 2 + 1   '  1 x links und 1 reinschieben
        Else
            CRC = CRC * 2       '  1 x links und 0 reinschieben
        End If
    If CRC > &H3FF& Then
        CRC = CRC Xor &H5B9&    ' XOR Polynom 0x5B9
    End If
    DATA = DATA And &HFFFF&     ' größer 16 BIT abschneiden
Next i
    ZWISCHENERGEBNIS1 = Hex(CRC)
'----------------------------------------------------------------------- 
------------------
' 2. Schleife 10xCRC-Bits behandeln
For i = 0 To 9
    CRC = CRC * 2               ' CRC 1 x links
    If CRC > &H3FF& Then        ' mehr als 10 Bits ?
        CRC = CRC Xor &H5B9&    ' XOR Polynom 0x5B9
    End If
    CRC = CRC And &H3FF&        ' größer 10 BIT abschneiden
Next i
    ZWISCHENERGEBNIS2 = Hex(CRC)
'----------------------------------------------------------------------- 
------------------
' MASTER-WORD
CRC_GRUPPE_A = CRC Xor &HFC&
CRC_GRUPPE_B = CRC Xor &H198&
CRC_GRUPPE_C = CRC Xor &H168&
CRC_GRUPPE_D = CRC Xor &H1B4&
'----------------------------------------------------------------------- 
------------------
' CRC vergleich CRC mit CRC_OLD
BERECHNUNG_CRC = 0
If CRC_GRUPPE_A = CRC_OLD Then BERECHNUNG_CRC = 1
If CRC_GRUPPE_B = CRC_OLD Then BERECHNUNG_CRC = 2
If CRC_GRUPPE_C = CRC_OLD Then BERECHNUNG_CRC = 3
If CRC_GRUPPE_D = CRC_OLD Then BERECHNUNG_CRC = 4
End Function
#3614370
Lesenswert?

1
// Q+D
2
// nur mal schnell als Beispiel zum testen
3

4

5
.include "m8def.inc"
6

7
.equ  POLYNOM    = 0x5B9
8
.equ  OFFSET_WORD_A  = 0x0FC
9
.equ  OFFSET_WORD_B  = 0x198
10
.equ  OFFSET_WORD_C  = 0x168
11
.equ  OFFSET_WORD_D  = 0x1B4
12

13

14

15
  .cseg
16
  .org 0
17
  rjmp  _Reset
18

19
_Reset:
20
  ldi  r16,low(RAMEND)
21
  out  spl,r16
22
  ldi  r16,high(RAMEND)
23
  out  sph,r16
24

25

26
  ldi  r16,low(0xd4f1)
27
  sts  data,r16
28
  ldi  r16,high(0xd4f1)
29
  sts  data+1,r16
30

31
Main:
32
  rcall  rds_crc
33
  rjmp  Main
34

35

36

37
rds_crc:
38
  push  r3
39
  push  r4
40
  push  r16
41
  push  r17
42
  push  r18
43

44

45
//temporäres CRC (r3,r4) auf 0 setzen    
46
  clr  r3
47
  clr  r4
48

49
// erste Teilaufgabe
50
  ldi  r18,8
51
  lds  r16,data+1  //die ersten 8 Datenbit
52
  rcall  crc_loop
53

54
// zweite Teilaufgabe
55
  ldi  r18,8
56
  lds  r16,data  //die restlichen 8 Datenbit verarbeiten
57
  rcall  crc_loop
58

59
//dritte Teilaufgabe
60
  ldi  r18,10    //10 0-Bits verarbeiten
61
  clr  r16    //dummy
62
  rcall  crc_loop
63

64

65
// mit OFFSET_WORD_A verknüpfen
66
  ldi  r17,low(OFFSET_WORD_A)
67
  eor  r3,r17
68
  ldi  r17,high(OFFSET_WORD_A)
69
  eor  r4,r17
70

71
// CRC abspeichern
72
  sts  crc,r3
73
  sts  crc+1,r4
74

75

76
  pop  r18
77
  pop  r17
78
  pop  r16
79
  pop  r4
80
  pop  r3
81
  ret
82

83

84
crc_loop:
85
_loop:
86
  lsl  r16
87
  rol  r3
88
  rol  r4
89
  sbrs  r4,2
90
  rjmp  _kein_xor
91
  ldi  r17,low(POLYNOM)
92
  eor  r3,r17
93
  ldi  r17,high(POLYNOM)
94
  eor  r4,r17
95
_kein_xor:
96
  dec  r18
97
  brne  _loop
98
  ret
99

100
  .dseg
101
data:  .BYTE  2
102
crc:  .BYTE  2
#3620290
Lesenswert?

>Das Problem: Die Sache der Decodierung ist viel komplexer.

Die einzelnen Gruppen und Blöcke kann ich in Assembler und VBA schon 
ganz brauchbar zusammenfügen. Bei vernünftigem RDS-Empfang wird der 
Datenstrom nach spätestens 107 Byte synchronisiert

Hab mich mal mit der Fehlerkorrektur beschäftigt und folgendes Programm 
geschrieben:

Wenn die CRC-Bits einer Gruppe nicht zu den beiden DATEN-Bits passen, 
dann wird nacheinander jedes einzelne Daten und CRC-Bit (26Bit) 
invertiert und der CRC-Check durchgeführt.

Die Gruppen-Errors nahmen sofort ab, aber es entstanden plötzlich auch 
falsche Grubben und sogar falsche Blöcke.

Bin noch am überlegen, ob sich die Fehlerkorrektur wirklich lohnt, keine 
Daten können besser sein als falsche.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren