mirror of
https://github.com/jfdelnero/rf-tools.git
synced 2024-11-22 03:36:38 -05:00
wip : RDS support.
This commit is contained in:
parent
94f026bfaf
commit
ff13d3d307
@ -128,6 +128,8 @@
|
|||||||
|
|
||||||
#include "modulator.h"
|
#include "modulator.h"
|
||||||
|
|
||||||
|
#include "rds.h"
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#include "fir_filters/FIR_Audio_Filter_Filter.h"
|
#include "fir_filters/FIR_Audio_Filter_Filter.h"
|
||||||
@ -238,6 +240,7 @@ int main(int argc, char* argv[])
|
|||||||
double audio_sample_final;
|
double audio_sample_final;
|
||||||
double audio_sample_r_car;
|
double audio_sample_r_car;
|
||||||
double pilot_sample;
|
double pilot_sample;
|
||||||
|
double rds_sample,rds_mod_sample;
|
||||||
double balance_sample;
|
double balance_sample;
|
||||||
double fm_mod;
|
double fm_mod;
|
||||||
|
|
||||||
@ -259,6 +262,9 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
wave_gen audiow_stereo38KHz_gen;
|
wave_gen audiow_stereo38KHz_gen;
|
||||||
wave_gen stereo_pilot_gen;
|
wave_gen stereo_pilot_gen;
|
||||||
|
wave_gen rds_carrier_57KHz_gen;
|
||||||
|
|
||||||
|
rds_stat rdsstat;
|
||||||
|
|
||||||
uint16_t iq_wave_buf[ BUFFER_SAMPLES_SIZE * (IQ_SAMPLE_RATE/SUBCARRIERS_SAMPLE_RATE)];
|
uint16_t iq_wave_buf[ BUFFER_SAMPLES_SIZE * (IQ_SAMPLE_RATE/SUBCARRIERS_SAMPLE_RATE)];
|
||||||
int16_t mod_wave_buf[(BUFFER_SAMPLES_SIZE*2)/4];
|
int16_t mod_wave_buf[(BUFFER_SAMPLES_SIZE*2)/4];
|
||||||
@ -347,12 +353,12 @@ int main(int argc, char* argv[])
|
|||||||
// Left and Right audio freq (used if no .mod music file)
|
// Left and Right audio freq (used if no .mod music file)
|
||||||
audio_l_gen.phase = 0;
|
audio_l_gen.phase = 0;
|
||||||
audio_l_gen.Frequency = 700;
|
audio_l_gen.Frequency = 700;
|
||||||
audio_l_gen.Amplitude = 22.5;
|
audio_l_gen.Amplitude = 21.25;
|
||||||
audio_l_gen.sample_rate = SUBCARRIERS_SAMPLE_RATE;
|
audio_l_gen.sample_rate = SUBCARRIERS_SAMPLE_RATE;
|
||||||
|
|
||||||
audio_r_gen.phase = 0;
|
audio_r_gen.phase = 0;
|
||||||
audio_r_gen.Frequency = 1000;
|
audio_r_gen.Frequency = 1000;
|
||||||
audio_r_gen.Amplitude = 22.5;
|
audio_r_gen.Amplitude = 21.25;
|
||||||
audio_r_gen.sample_rate = SUBCARRIERS_SAMPLE_RATE;
|
audio_r_gen.sample_rate = SUBCARRIERS_SAMPLE_RATE;
|
||||||
|
|
||||||
// Left <> Right balance LFO (used if no .mod music file)
|
// Left <> Right balance LFO (used if no .mod music file)
|
||||||
@ -373,6 +379,14 @@ int main(int argc, char* argv[])
|
|||||||
audiow_stereo38KHz_gen.Amplitude = 1;
|
audiow_stereo38KHz_gen.Amplitude = 1;
|
||||||
audiow_stereo38KHz_gen.sample_rate = SUBCARRIERS_SAMPLE_RATE;
|
audiow_stereo38KHz_gen.sample_rate = SUBCARRIERS_SAMPLE_RATE;
|
||||||
|
|
||||||
|
// 57KHz RDS carrier
|
||||||
|
rds_carrier_57KHz_gen.phase = 0;
|
||||||
|
rds_carrier_57KHz_gen.Frequency = 57000;
|
||||||
|
rds_carrier_57KHz_gen.Amplitude = 1;
|
||||||
|
rds_carrier_57KHz_gen.sample_rate = SUBCARRIERS_SAMPLE_RATE;
|
||||||
|
|
||||||
|
init_rds_encoder(&rdsstat,SUBCARRIERS_SAMPLE_RATE);
|
||||||
|
|
||||||
// IQ Modulator
|
// IQ Modulator
|
||||||
iqgen.phase = 0;
|
iqgen.phase = 0;
|
||||||
iqgen.Frequency = IF_FREQ;
|
iqgen.Frequency = IF_FREQ;
|
||||||
@ -456,14 +470,22 @@ int main(int argc, char* argv[])
|
|||||||
FIR_Audio_Filter_Filter_put(&leftminusright_audio_filter, leftminusright_audio);
|
FIR_Audio_Filter_Filter_put(&leftminusright_audio_filter, leftminusright_audio);
|
||||||
leftminusright_audio = FIR_Audio_Filter_Filter_get(&leftminusright_audio_filter);
|
leftminusright_audio = FIR_Audio_Filter_Filter_get(&leftminusright_audio_filter);
|
||||||
|
|
||||||
// Keep the 18KHz pilot and the 38KHz clock in phase :
|
// Keep the 19KHz pilot and the 38KHz clock in phase :
|
||||||
audiow_stereo38KHz_gen.phase = (stereo_pilot_gen.phase * 2) + PI/2;
|
audiow_stereo38KHz_gen.phase = (stereo_pilot_gen.phase * 2) + PI/2;
|
||||||
|
|
||||||
|
rds_carrier_57KHz_gen.phase = (stereo_pilot_gen.phase * 3) + PI/2;
|
||||||
|
|
||||||
|
rds_mod_sample = get_rds_bit_state(&rdsstat,stereo_pilot_gen.phase);
|
||||||
|
|
||||||
// 38KHz DSB-SC (Double-sideband suppressed-carrier) modulation
|
// 38KHz DSB-SC (Double-sideband suppressed-carrier) modulation
|
||||||
audio_sample_r_car = f_get_next_sample(&audiow_stereo38KHz_gen); // Get the 38KHz carrier
|
audio_sample_r_car = f_get_next_sample(&audiow_stereo38KHz_gen); // Get the 38KHz carrier
|
||||||
audio_sample_r_car = (audio_sample_r_car * leftminusright_audio ); // And multiply it with the left - right sample.
|
audio_sample_r_car = (audio_sample_r_car * leftminusright_audio ); // And multiply it with the left - right sample.
|
||||||
|
|
||||||
// 18KHz pilot
|
// 57KHz DSB-SC (Double-sideband suppressed-carrier) modulation
|
||||||
|
rds_sample = f_get_next_sample(&rds_carrier_57KHz_gen); // Get the 57KHz carrier
|
||||||
|
rds_sample = ( rds_sample * rds_mod_sample ); // And multiply it with the rds sample.
|
||||||
|
|
||||||
|
// 19KHz pilot
|
||||||
pilot_sample = f_get_next_sample(&stereo_pilot_gen);
|
pilot_sample = f_get_next_sample(&stereo_pilot_gen);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -471,11 +493,12 @@ int main(int argc, char* argv[])
|
|||||||
// Mono : No pilot nor 38KHz modulation...
|
// Mono : No pilot nor 38KHz modulation...
|
||||||
audio_sample_r_car = 0;
|
audio_sample_r_car = 0;
|
||||||
pilot_sample = 0;
|
pilot_sample = 0;
|
||||||
|
rds_sample = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mix all signals sources :
|
// Mix all signals sources :
|
||||||
// 45% 45% 10%
|
// 42.5% 42.5% 10% 5%
|
||||||
audio_sample_final = ((leftplusright_audio) + audio_sample_r_car + pilot_sample);
|
audio_sample_final = ((leftplusright_audio) + audio_sample_r_car + pilot_sample + rds_sample);
|
||||||
|
|
||||||
// Main carrier frequency modulation : +/- 75KHz
|
// Main carrier frequency modulation : +/- 75KHz
|
||||||
fm_mod = ((audio_sample_final / (double)(100.0)) * (double)(75000));
|
fm_mod = ((audio_sample_final / (double)(100.0)) * (double)(75000));
|
||||||
@ -485,7 +508,7 @@ int main(int argc, char* argv[])
|
|||||||
//FM_Baseband_Filter_put(&fmband_filter, fm_mod );
|
//FM_Baseband_Filter_put(&fmband_filter, fm_mod );
|
||||||
//fm_mod = FM_Baseband_Filter_get(&fmband_filter);
|
//fm_mod = FM_Baseband_Filter_get(&fmband_filter);
|
||||||
|
|
||||||
subcarriers_dbg_wave_buf[j] = fm_mod;
|
subcarriers_dbg_wave_buf[j] = fm_mod/4;
|
||||||
subcarriers_float_wave_buf[j] = fm_mod;
|
subcarriers_float_wave_buf[j] = fm_mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
119
src/broadcast_fm/rds.c
Normal file
119
src/broadcast_fm/rds.c
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//-------------------------------------------------------------------------------//
|
||||||
|
//-------------------------------------------------------------------------------//
|
||||||
|
//-----------H----H--X----X-----CCCCC----22222----0000-----0000------11----------//
|
||||||
|
//----------H----H----X-X-----C--------------2---0----0---0----0--1--1-----------//
|
||||||
|
//---------HHHHHH-----X------C----------22222---0----0---0----0-----1------------//
|
||||||
|
//--------H----H----X--X----C----------2-------0----0---0----0-----1-------------//
|
||||||
|
//-------H----H---X-----X---CCCCC-----222222----0000-----0000----1111------------//
|
||||||
|
//-------------------------------------------------------------------------------//
|
||||||
|
//----------------------------------------------------- http://hxc2001.free.fr --//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// File : rds.c
|
||||||
|
// Contains: rds engine
|
||||||
|
//
|
||||||
|
// This file is part of rf-tools.
|
||||||
|
//
|
||||||
|
// Written by: Jean-François DEL NERO
|
||||||
|
//
|
||||||
|
// Copyright (C) 2022 Jean-François DEL NERO
|
||||||
|
//
|
||||||
|
// You are free to do what you want with this code.
|
||||||
|
// A credit is always appreciated if you use it into your product :)
|
||||||
|
//
|
||||||
|
// Change History (most recent first):
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "modulator.h"
|
||||||
|
#include "rds.h"
|
||||||
|
|
||||||
|
void init_rds_encoder(rds_stat * stat,int sample_rate)
|
||||||
|
{
|
||||||
|
memset(stat,0,sizeof(rds_stat));
|
||||||
|
stat->bit_rate = RDS_BIT_RATE;
|
||||||
|
stat->old_pilot_phase = 0;
|
||||||
|
stat->sample_rate = sample_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rds_differential_encoder(rds_stat * stat)
|
||||||
|
{
|
||||||
|
stat->current_diff_dat_state = ((stat->ser_data_in & 1) ^ stat->current_diff_dat_state);
|
||||||
|
|
||||||
|
return stat->current_diff_dat_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
double get_rds_bit_state(rds_stat * stat, double pilot_phase)
|
||||||
|
{
|
||||||
|
double sample;
|
||||||
|
double phase_diff;
|
||||||
|
|
||||||
|
if(pilot_phase < stat->old_pilot_phase)
|
||||||
|
phase_diff = (2*PI + pilot_phase) - stat->old_pilot_phase;
|
||||||
|
else
|
||||||
|
phase_diff = pilot_phase - stat->old_pilot_phase;
|
||||||
|
|
||||||
|
if( phase_diff >= ((2*PI) / 3) )
|
||||||
|
{
|
||||||
|
// New 57KHz tick clock
|
||||||
|
stat->old_pilot_phase = pilot_phase;//+= ((2*PI) / 3);
|
||||||
|
|
||||||
|
if(stat->old_pilot_phase >= (2*PI))
|
||||||
|
stat->old_pilot_phase = 0;
|
||||||
|
|
||||||
|
stat->cycles_count++;
|
||||||
|
if(stat->cycles_count >= 16*2)
|
||||||
|
{
|
||||||
|
stat->test++;
|
||||||
|
|
||||||
|
stat->ser_data_in = rand()&1;
|
||||||
|
|
||||||
|
rds_differential_encoder(stat);
|
||||||
|
|
||||||
|
stat->current_data_state = (stat->current_diff_dat_state & 0x1);
|
||||||
|
|
||||||
|
stat->cycles_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delayed signal
|
||||||
|
if(stat->cycles_count == 8*2)
|
||||||
|
{
|
||||||
|
stat->current_data_state = stat->current_diff_dat_state ^ 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FREQ_FILTER (1187.5*1.0)
|
||||||
|
|
||||||
|
if(stat->current_data_state)
|
||||||
|
{
|
||||||
|
// Must go to 0.
|
||||||
|
if( !((stat->phase >= ((2*PI) - ((2.0 * PI * (FREQ_FILTER*2))/ (double)stat->sample_rate) ) ) || // >=// 2PI - step
|
||||||
|
(stat->phase < (((2.0 * PI * (FREQ_FILTER*2))/ (double)stat->sample_rate) ) ) ) // < // step
|
||||||
|
)
|
||||||
|
{
|
||||||
|
stat->phase += ( (2.0 * PI * (FREQ_FILTER*2) ) / (double)stat->sample_rate );
|
||||||
|
if(stat->phase >= 2.0 * PI)
|
||||||
|
stat->phase -= (2.0 * PI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Must go to PI.
|
||||||
|
if( !((stat->phase >= ((PI) - ((2.0 * PI * (FREQ_FILTER*2))/ (double)stat->sample_rate) ) ) && // > PI - step
|
||||||
|
(stat->phase < ((PI) + ((2.0 * PI * (FREQ_FILTER*2))/ (double)stat->sample_rate) ) )) // < PI + step
|
||||||
|
)
|
||||||
|
{
|
||||||
|
stat->phase += ( (2.0 * PI * (FREQ_FILTER*2) ) / (double)stat->sample_rate );
|
||||||
|
if(stat->phase >= 2.0 * PI)
|
||||||
|
stat->phase -= (2.0 * PI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sample = ( cos( stat->phase ) * 3.0 );
|
||||||
|
|
||||||
|
return sample;
|
||||||
|
}
|
46
src/broadcast_fm/rds.h
Normal file
46
src/broadcast_fm/rds.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//-------------------------------------------------------------------------------//
|
||||||
|
//-------------------------------------------------------------------------------//
|
||||||
|
//-----------H----H--X----X-----CCCCC----22222----0000-----0000------11----------//
|
||||||
|
//----------H----H----X-X-----C--------------2---0----0---0----0--1--1-----------//
|
||||||
|
//---------HHHHHH-----X------C----------22222---0----0---0----0-----1------------//
|
||||||
|
//--------H----H----X--X----C----------2-------0----0---0----0-----1-------------//
|
||||||
|
//-------H----H---X-----X---CCCCC-----222222----0000-----0000----1111------------//
|
||||||
|
//-------------------------------------------------------------------------------//
|
||||||
|
//----------------------------------------------------- http://hxc2001.free.fr --//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// File : rds.h
|
||||||
|
// Contains: rds engine
|
||||||
|
//
|
||||||
|
// This file is part of rf-tools.
|
||||||
|
//
|
||||||
|
// Written by: Jean-François DEL NERO
|
||||||
|
//
|
||||||
|
// Copyright (C) 2022 Jean-François DEL NERO
|
||||||
|
//
|
||||||
|
// You are free to do what you want with this code.
|
||||||
|
// A credit is always appreciated if you use it into your product :)
|
||||||
|
//
|
||||||
|
// Change History (most recent first):
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define RDS_BIT_RATE 1187.5
|
||||||
|
|
||||||
|
typedef struct _rds_stat
|
||||||
|
{
|
||||||
|
int sample_rate;
|
||||||
|
float bit_rate;
|
||||||
|
|
||||||
|
double old_pilot_phase;
|
||||||
|
double phase;
|
||||||
|
|
||||||
|
int current_data_state;
|
||||||
|
int current_diff_dat_state;
|
||||||
|
int ser_data_in;
|
||||||
|
|
||||||
|
int test;
|
||||||
|
int cycles_count;
|
||||||
|
}rds_stat;
|
||||||
|
|
||||||
|
void init_rds_encoder(rds_stat * stat,int sample_rate);
|
||||||
|
double get_rds_bit_state(rds_stat * stat, double pilot_phase);
|
Loading…
Reference in New Issue
Block a user