From ff13d3d307ce8f6c652e493dd9584832bb7967e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20DEL=20NERO?= Date: Tue, 22 Nov 2022 00:32:34 +0100 Subject: [PATCH] wip : RDS support. --- src/broadcast_fm/broadcast_fm.c | 37 ++++++++-- src/broadcast_fm/rds.c | 119 ++++++++++++++++++++++++++++++++ src/broadcast_fm/rds.h | 46 ++++++++++++ 3 files changed, 195 insertions(+), 7 deletions(-) create mode 100644 src/broadcast_fm/rds.c create mode 100644 src/broadcast_fm/rds.h diff --git a/src/broadcast_fm/broadcast_fm.c b/src/broadcast_fm/broadcast_fm.c index e7520be..5c4a397 100644 --- a/src/broadcast_fm/broadcast_fm.c +++ b/src/broadcast_fm/broadcast_fm.c @@ -128,6 +128,8 @@ #include "modulator.h" +#include "rds.h" + #include "utils.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_r_car; double pilot_sample; + double rds_sample,rds_mod_sample; double balance_sample; double fm_mod; @@ -259,6 +262,9 @@ int main(int argc, char* argv[]) wave_gen audiow_stereo38KHz_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)]; 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) audio_l_gen.phase = 0; 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_r_gen.phase = 0; 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; // 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.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 iqgen.phase = 0; iqgen.Frequency = IF_FREQ; @@ -456,14 +470,22 @@ int main(int argc, char* argv[]) FIR_Audio_Filter_Filter_put(&leftminusright_audio_filter, leftminusright_audio); 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; + 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 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. - // 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); } else @@ -471,11 +493,12 @@ int main(int argc, char* argv[]) // Mono : No pilot nor 38KHz modulation... audio_sample_r_car = 0; pilot_sample = 0; + rds_sample = 0; } // Mix all signals sources : - // 45% 45% 10% - audio_sample_final = ((leftplusright_audio) + audio_sample_r_car + pilot_sample); + // 42.5% 42.5% 10% 5% + audio_sample_final = ((leftplusright_audio) + audio_sample_r_car + pilot_sample + rds_sample); // Main carrier frequency modulation : +/- 75KHz 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_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; } diff --git a/src/broadcast_fm/rds.c b/src/broadcast_fm/rds.c new file mode 100644 index 0000000..a3a95ec --- /dev/null +++ b/src/broadcast_fm/rds.c @@ -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 +#include +#include +#include + +#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; +} diff --git a/src/broadcast_fm/rds.h b/src/broadcast_fm/rds.h new file mode 100644 index 0000000..5338265 --- /dev/null +++ b/src/broadcast_fm/rds.h @@ -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);