wip : RDS support.

This commit is contained in:
Jean-François DEL NERO 2022-11-22 00:32:34 +01:00
parent 94f026bfaf
commit ff13d3d307
3 changed files with 195 additions and 7 deletions

View File

@ -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
View 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
View 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);