The RDS specifies the filtering used for 57 kHz sub carrier, only in a notation that is alien to me. See section 1.7 of the RBDS or EN 50067 standard.
Here are the blighters:
Formula (4) defines the data period, 842 Ás. This is 1/48 of the sub-carrier frequency. That's not too painful.
The first two are fairly straight forward. The threw me. Three D.S.P. text books later, I saw things more clearly.
A (t) is known as the Dirac delta function, or impulse function.
To paraphrase (1): a Logic 1 at source gives a positive impulse, and half a data period later, a negative impulse.
To paraphrase (2): a Logic 0 at source gives a negative impulse, and half a data period later, a positive impulse.
These agree with the following diagram taken from the spec:
This is how we get from waveform 2, the differentially encoded data, to the bi-phase data in waveform 4.
That leaves us with formula (3) that gets us waveform 5.
A positive impulse would look like this:
This is the sinc or sin(x pi)/x pi function.
In formula (3) we are only interested in f between 0 and twice the data rate:
This is like a glitch with pre-ringing.
Assembling theses impulses into the data stream used in the specification example:
(We're getting close!) Applying the above waveform through a cosine filter that's "resonant" at 1/4 of the data rate frequency, we reduce the double peak:
This is the waveform we apply to the balanced modulator.
The PIC has limited memory. I store the following highlighted part of the above waveform as a lookup table:
This is a modest table of a mere 40 bytes, enough to reproduce the waveform sampling at 38 kHz. By judicious coding either the double peak, or its inverse, or a sine wave can be generated.
Here's a screen shot of the PIC DTA output:
And how were the images on this page created?
I created a MFC VC++ dialog app that used techniques taken from DSP text books.
The app performs a series of operations on a pair of buffers. A function reads an input buffer, "does something with it" and updates the output buffer.
The app goes through the following stages, simulating a real RDS transmitter. (Well for a 13ms period - long enough to simulate the above waveforms.)
All functions have the same signature. Here's one of the more tricky ones:
|void sinc (const double in, double out)
for (int i1 = 0; i1 < N; i1++)
for (int i2 = -8; i2 < 16; i2++)
int index = i1 + i2;
double d1 = ((index < N) && (index >= 0)) ? in[index]: 0.0;
if (i2 != 0)
out[i1] += d1 * (sin((TWOPI * i2) / 16.0) / ((TWOPI * i2 )/ 16.0)) ;
out[i1] += d1;
out[i1] /= 1;
The buffer size used was 500 (N). 16 samples per data period - that gives me a chance to display 31 or so data periods.
The output buffer gets painted on the WM_PAINT, as you do. The PIC table enjoyed a more circuitous route from output buffer, via TRACE statements, Excel for encoding as 7 bit data, and finally to the PIC source.
To the RDS generator page
back to the RDS page
This page was last updated on the 30th July 2002