Skip to content

Commit 05ab17a

Browse files
Merge pull request AlexandreRouma#1307 from AlexandreRouma/new_rds
New rds demod and decode
2 parents ff23d7e + 2ef8ee3 commit 05ab17a

File tree

13 files changed

+1214
-242
lines changed

13 files changed

+1214
-242
lines changed

core/src/dsp/demod/broadcast_fm.h

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,17 @@ namespace dsp::demod {
4949
audioFirTaps = taps::lowPass(15000.0, 4000.0, _samplerate);
5050
alFir.init(NULL, audioFirTaps);
5151
arFir.init(NULL, audioFirTaps);
52+
xlator.init(NULL, -57000.0, samplerate);
5253
rdsResamp.init(NULL, samplerate, 5000.0);
5354

5455
lmr = buffer::alloc<float>(STREAM_BUFFER_SIZE);
5556
l = buffer::alloc<float>(STREAM_BUFFER_SIZE);
5657
r = buffer::alloc<float>(STREAM_BUFFER_SIZE);
5758

5859
lprDelay.out.free();
59-
lmrDelay.out.free();
6060
arFir.out.free();
6161
alFir.out.free();
62+
xlator.out.free();
6263
rdsResamp.out.free();
6364

6465
base_type::init(in);
@@ -92,6 +93,7 @@ namespace dsp::demod {
9293
alFir.setTaps(audioFirTaps);
9394
arFir.setTaps(audioFirTaps);
9495

96+
xlator.setOffset(-57000.0, samplerate);
9597
rdsResamp.setInSamplerate(samplerate);
9698

9799
reset();
@@ -139,7 +141,7 @@ namespace dsp::demod {
139141
base_type::tempStart();
140142
}
141143

142-
inline int process(int count, complex_t* in, stereo_t* out, int& rdsOutCount, float* rdsout = NULL) {
144+
inline int process(int count, complex_t* in, stereo_t* out, int& rdsOutCount, complex_t* rdsout = NULL) {
143145
// Demodulate
144146
demod.process(count, in, demod.out.writeBuf);
145147
if (_stereo) {
@@ -152,24 +154,24 @@ namespace dsp::demod {
152154

153155
// Delay
154156
lprDelay.process(count, demod.out.writeBuf, demod.out.writeBuf);
155-
lmrDelay.process(count, rtoc.out.writeBuf, rtoc.out.writeBuf);
157+
lmrDelay.process(count, rtoc.out.writeBuf, lmrDelay.out.writeBuf);
156158

157159
// conjugate PLL output to down convert twice the L-R signal
158160
math::Conjugate::process(count, pilotPLL.out.writeBuf, pilotPLL.out.writeBuf);
159-
math::Multiply<dsp::complex_t>::process(count, rtoc.out.writeBuf, pilotPLL.out.writeBuf, rtoc.out.writeBuf);
160-
math::Multiply<dsp::complex_t>::process(count, rtoc.out.writeBuf, pilotPLL.out.writeBuf, rtoc.out.writeBuf);
161+
math::Multiply<dsp::complex_t>::process(count, lmrDelay.out.writeBuf, pilotPLL.out.writeBuf, lmrDelay.out.writeBuf);
162+
math::Multiply<dsp::complex_t>::process(count, lmrDelay.out.writeBuf, pilotPLL.out.writeBuf, lmrDelay.out.writeBuf);
161163

162164
// Do RDS demod
163165
if (_rdsOut) {
164-
// Since the PLL output is no longer needed after this, use it as the output
165-
math::Multiply<dsp::complex_t>::process(count, rtoc.out.writeBuf, pilotPLL.out.writeBuf, pilotPLL.out.writeBuf);
166-
convert::ComplexToReal::process(count, pilotPLL.out.writeBuf, rdsout);
167-
volk_32f_s32f_multiply_32f(rdsout, rdsout, 100.0, count);
168-
rdsOutCount = rdsResamp.process(count, rdsout, rdsout);
166+
// Translate to 0Hz
167+
xlator.process(count, rtoc.out.writeBuf, rtoc.out.writeBuf);
168+
169+
// Resample to the output samplerate
170+
rdsOutCount = rdsResamp.process(count, rtoc.out.writeBuf, rdsout);
169171
}
170172

171173
// Convert output back to real for further processing
172-
convert::ComplexToReal::process(count, rtoc.out.writeBuf, lmr);
174+
convert::ComplexToReal::process(count, lmrDelay.out.writeBuf, lmr);
173175

174176
// Amplify by 2x
175177
volk_32f_s32f_multiply_32f(lmr, lmr, 2.0f, count);
@@ -193,24 +195,11 @@ namespace dsp::demod {
193195
// Convert to complex
194196
rtoc.process(count, demod.out.writeBuf, rtoc.out.writeBuf);
195197

196-
// Filter out pilot and run through PLL
197-
pilotFir.process(count, rtoc.out.writeBuf, pilotFir.out.writeBuf);
198-
pilotPLL.process(count, pilotFir.out.writeBuf, pilotPLL.out.writeBuf);
199-
200-
// Delay
201-
lprDelay.process(count, demod.out.writeBuf, demod.out.writeBuf);
202-
lmrDelay.process(count, rtoc.out.writeBuf, rtoc.out.writeBuf);
203-
204-
// conjugate PLL output to down convert twice the L-R signal
205-
math::Conjugate::process(count, pilotPLL.out.writeBuf, pilotPLL.out.writeBuf);
206-
math::Multiply<dsp::complex_t>::process(count, rtoc.out.writeBuf, pilotPLL.out.writeBuf, rtoc.out.writeBuf);
207-
math::Multiply<dsp::complex_t>::process(count, rtoc.out.writeBuf, pilotPLL.out.writeBuf, rtoc.out.writeBuf);
208-
209-
// Since the PLL output is no longer needed after this, use it as the output
210-
math::Multiply<dsp::complex_t>::process(count, rtoc.out.writeBuf, pilotPLL.out.writeBuf, pilotPLL.out.writeBuf);
211-
convert::ComplexToReal::process(count, pilotPLL.out.writeBuf, rdsout);
212-
volk_32f_s32f_multiply_32f(rdsout, rdsout, 100.0, count);
213-
rdsOutCount = rdsResamp.process(count, rdsout, rdsout);
198+
// Translate to 0Hz
199+
xlator.process(count, rtoc.out.writeBuf, rtoc.out.writeBuf);
200+
201+
// Resample to the output samplerate
202+
rdsOutCount = rdsResamp.process(count, rtoc.out.writeBuf, rdsout);
214203
}
215204

216205
// Filter if needed
@@ -240,7 +229,7 @@ namespace dsp::demod {
240229
return count;
241230
}
242231

243-
stream<float> rdsOut;
232+
stream<complex_t> rdsOut;
244233

245234
protected:
246235
double _deviation;
@@ -253,13 +242,14 @@ namespace dsp::demod {
253242
tap<complex_t> pilotFirTaps;
254243
filter::FIR<complex_t, complex_t> pilotFir;
255244
convert::RealToComplex rtoc;
245+
channel::FrequencyXlator xlator;
256246
loop::PLL pilotPLL;
257247
math::Delay<float> lprDelay;
258248
math::Delay<complex_t> lmrDelay;
259249
tap<float> audioFirTaps;
260250
filter::FIR<float, float> arFir;
261251
filter::FIR<float, float> alFir;
262-
multirate::RationalResampler<float> rdsResamp;
252+
multirate::RationalResampler<dsp::complex_t> rdsResamp;
263253

264254
float* lmr;
265255
float* l;

core/src/dsp/loop/phase_control_loop.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ namespace dsp::loop {
6565
if constexpr(CLAMP_PHASE) { clampPhase(); }
6666
}
6767

68+
inline void advancePhase() {
69+
phase += freq;
70+
if constexpr(CLAMP_PHASE) { clampPhase(); }
71+
}
72+
6873
T freq;
6974
T phase;
7075

core/src/utils/riff.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ namespace riff {
77
const char* LIST_SIGNATURE = "LIST";
88
const size_t RIFF_LABEL_SIZE = 4;
99

10+
// Writer::Writer(const Writer&& b) {
11+
// //file = std::move(b.file);
12+
// }
13+
14+
Writer::~Writer() {
15+
close();
16+
}
17+
1018
bool Writer::open(std::string path, const char form[4]) {
1119
std::lock_guard<std::recursive_mutex> lck(mtx);
1220

core/src/utils/riff.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ namespace riff {
2020

2121
class Writer {
2222
public:
23+
Writer() {}
24+
// Writer(const Writer&& b);
25+
~Writer();
26+
2327
bool open(std::string path, const char form[4]);
2428
bool isOpen();
2529
void close();
@@ -40,4 +44,23 @@ namespace riff {
4044
std::ofstream file;
4145
std::stack<ChunkDesc> chunks;
4246
};
47+
48+
// class Reader {
49+
// public:
50+
// Reader();
51+
// Reader(const Reader&& b);
52+
// ~Reader();
53+
54+
// bool open(std::string path);
55+
// bool isOpen();
56+
// void close();
57+
58+
// const std::string& form();
59+
60+
// private:
61+
62+
// std::string _form;
63+
// std::recursive_mutex mtx;
64+
// std::ofstream file;
65+
// };
4366
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#pragma once
2+
#include <dsp/loop/pll.h>
3+
#include "chrominance_filter.h"
4+
5+
// TODO: Should be 60 but had to try something
6+
#define BURST_START (63+CHROMA_FIR_DELAY)
7+
#define BURST_END (BURST_START+28)
8+
9+
#define A_PHASE ((135.0/180.0)*FL_M_PI)
10+
#define B_PHASE ((-135.0/180.0)*FL_M_PI)
11+
12+
namespace dsp::loop {
13+
class ChromaPLL : public PLL {
14+
using base_type = PLL;
15+
public:
16+
ChromaPLL() {}
17+
18+
ChromaPLL(stream<complex_t>* in, double bandwidth, double initPhase = 0.0, double initFreq = 0.0, double minFreq = -FL_M_PI, double maxFreq = FL_M_PI) {
19+
base_type::init(in, bandwidth, initFreq, initPhase, minFreq, maxFreq);
20+
}
21+
22+
inline int process(int count, complex_t* in, complex_t* out, bool aphase = false) {
23+
// Process the pre-burst section
24+
for (int i = 0; i < BURST_START; i++) {
25+
out[i] = in[i] * math::phasor(-pcl.phase);
26+
pcl.advancePhase();
27+
}
28+
29+
// Process the burst itself
30+
if (aphase) {
31+
for (int i = BURST_START; i < BURST_END; i++) {
32+
complex_t outVal = in[i] * math::phasor(-pcl.phase);
33+
out[i] = outVal;
34+
pcl.advance(math::normalizePhase(outVal.phase() - A_PHASE));
35+
}
36+
}
37+
else {
38+
for (int i = BURST_START; i < BURST_END; i++) {
39+
complex_t outVal = in[i] * math::phasor(-pcl.phase);
40+
out[i] = outVal;
41+
pcl.advance(math::normalizePhase(outVal.phase() - B_PHASE));
42+
}
43+
}
44+
45+
46+
// Process the post-burst section
47+
for (int i = BURST_END; i < count; i++) {
48+
out[i] = in[i] * math::phasor(-pcl.phase);
49+
pcl.advancePhase();
50+
}
51+
52+
return count;
53+
}
54+
55+
inline int processBlank(int count, complex_t* in, complex_t* out) {
56+
for (int i = 0; i < count; i++) {
57+
out[i] = in[i] * math::phasor(-pcl.phase);
58+
pcl.advancePhase();
59+
}
60+
return count;
61+
}
62+
};
63+
}

0 commit comments

Comments
 (0)