diff --git a/lib/constants.h b/lib/constants.h index 59127bd..21bf5bc 100644 --- a/lib/constants.h +++ b/lib/constants.h @@ -4,4 +4,8 @@ #endif #ifndef M_2PI #define M_2PI (M_PI * 2.0) -#endif \ No newline at end of file +#endif + +inline float sincf(float x) { + return (x == 0.0f) ? 1.0f : sinf(M_PI * x) / (M_PI * x); +} \ No newline at end of file diff --git a/lib/filters.c b/lib/filters.c index efac0d5..8fee831 100644 --- a/lib/filters.c +++ b/lib/filters.c @@ -14,36 +14,43 @@ float hard_clip(float sample, float threshold) { return fmaxf(-threshold, fminf(threshold, sample)); } -void init_pll(PLL *pll, float freq, float loop_filter_bandwidth, float damping, int sample_rate) { - pll->phase = 0.0f; - pll->freq = freq; - pll->loop_filter_state = 0.0f; - pll->kp = M_2PI * loop_filter_bandwidth; - pll->ki = (4.0f*damping*damping) * pll->kp * pll->kp; - pll->sample_rate = sample_rate; +void init_bpf(FIRFilter *bpf, float start, float end) { + int m = FILTER_LEN - 1; + float sum = 0.0f; + + for(int n = 0; n < FILTER_LEN; n++) { + float x = n-m/2.0f; + float h1 = sincf(2.0f*start*x) * (0.54 - 0.46 * cosf(M_2PI * n / m)); + float h2 = sincf(2.0f*end*x) * (0.54 - 0.46 * cosf(M_2PI * n / m)); + bpf->filter[n] = h1-h2; + sum += bpf->filter[n]; + } + + for(int n = 0; n < FILTER_LEN; n++) { + bpf->filter[n] /= sum; + } +} +void init_lpf(FIRFilter *lpf, float freq) { + int m = FILTER_LEN - 1; + float sum = 0.0f; + + for(int n = 0; n < FILTER_LEN; n++) { + float x = n-m/2.0f; + lpf->filter[n] = sincf(2.0f*freq*x) * (0.54 - 0.46 * cosf(M_2PI * n / m)); + sum += lpf->filter[n]; + } + + for(int n = 0; n < FILTER_LEN; n++) { + lpf->filter[n] /= sum; + } } -float apply_pll(PLL *pll, float ref_sample) { - float phase_error; - - float vco_output = sinf(pll->phase); - - phase_error = atan2f(ref_sample, vco_output);; - - pll->loop_filter_state += pll->ki * phase_error / pll->sample_rate; - float loop_output = pll->loop_filter_state + pll->kp * phase_error; - - float freq_adjustment = loop_output / M_2PI; - float instantaneous_freq = pll->freq + freq_adjustment; - - pll->phase += M_2PI * instantaneous_freq / pll->sample_rate; - - while (pll->phase >= M_2PI) { - pll->phase -= M_2PI; - } - while (pll->phase < 0.0f) { - pll->phase += M_2PI; - } - - return vco_output; +float fir_filter(FIRFilter *fir, float sample) { + float out = 0.0f; + for(int i = 0; i < FILTER_LEN; i++) { + out += fir->filter[i] * sample; + } + fir->filter_idx++; + if(fir->filter_idx == FILTER_LEN) fir->filter_idx = 0; + return out; } \ No newline at end of file diff --git a/lib/filters.h b/lib/filters.h index 17f95d3..fbbd9b9 100644 --- a/lib/filters.h +++ b/lib/filters.h @@ -5,6 +5,8 @@ #include "constants.h" #include "oscillator.h" +#define FILTER_LEN 51 + typedef struct { float alpha; @@ -16,13 +18,11 @@ float apply_preemphasis(ResistorCapacitor *filter, float sample); float hard_clip(float sample, float threshold); -typedef struct { - float phase; - float freq; - float loop_filter_state; - float kp; - float ki; - int sample_rate; -} PLL; -void init_pll(PLL *pll, float freq, float loop_filter_bandwidth, float damping, int sample_rate); -float apply_pll(PLL *pll, float ref_sample); \ No newline at end of file +typedef struct filters +{ + float filter[FILTER_LEN]; + int filter_idx; +} FIRFilter; +void init_bpf(FIRFilter *bpf, float start, float end); +void init_lpf(FIRFilter *lpf, float freq); +float fir_filter(FIRFilter *fir, float sample); \ No newline at end of file diff --git a/src/fm95.c b/src/fm95.c index 673284d..9aca14d 100644 --- a/src/fm95.c +++ b/src/fm95.c @@ -415,8 +415,10 @@ int main(int argc, char **argv) { init_preemphasis(&preemp_l, preemphasis_tau, sample_rate); init_preemphasis(&preemp_r, preemphasis_tau, sample_rate); - PLL rds2_pll; - init_pll(&rds2_pll, 66500, 5, 0.5f, sample_rate); + FIRFilter rds2_bpf, lpf_l, lpf_r; + init_bpf(&rds2_bpf, 66000, 67000); + init_lpf(&lpf_l, 15000); + init_lpf(&lpf_r, 15000); // #endregion signal(SIGINT, stop); @@ -474,6 +476,8 @@ int main(int argc, char **argv) { float ready_l = apply_preemphasis(&preemp_l, l_in)*2; float ready_r = apply_preemphasis(&preemp_r, r_in)*2; + ready_l = fir_filter(&lpf_l, ready_l); + ready_r = fir_filter(&lpf_l, ready_r); ready_l = hard_clip(ready_l*audio_volume, clipper_threshold); ready_r = hard_clip(ready_r*audio_volume, clipper_threshold); @@ -495,7 +499,7 @@ int main(int argc, char **argv) { float rds_carrier = get_oscillator_sin_multiplier_ni(&osc, 3); output[i] += (current_rds_in*rds_carrier)*RDS_VOLUME; if(!sca_on) { - float rds2_carrier_66 = apply_pll(&rds2_pll, rds_carrier); + float rds2_carrier_66 = fir_filter(&rds2_bpf, get_oscillator_sin_multiplier_ni(&osc, 3.5f)); output[i] += (current_rds2_in*rds2_carrier_66)*RDS2_VOLUME; } }