forked from ka9q/ka9q-radio
-
Notifications
You must be signed in to change notification settings - Fork 0
/
filter.h
141 lines (124 loc) · 5.68 KB
/
filter.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// filter using fast convolution (overlap-save) and the FFTW3 FFT package
// for the ka9q-radio 'radiod' program
// Generates transfer functions using Kaiser window
// Optional output decimation by integer factor
// Complex input and transfer functions, complex or real output
// Copyright 2017-2023, Phil Karn, KA9Q, [email protected]
#ifndef _FILTER_H
#define _FILTER_H 1
#include <pthread.h>
#include <complex.h>
#include <stdbool.h>
#include <fftw3.h>
#include "misc.h"
extern double Fftw_plan_timelimit;
extern char const *Wisdom_file;
extern int Nthreads;
extern int FFTW_planning_level;
extern double FFTW_plan_timelimit;
// Input can be REAL or COMPLEX
// Output can be REAL, COMPLEX, CROSS_CONJ, i.e., COMPLEX with special cross conjugation for ISB, or SPECTRUM (noncoherent power)
enum filtertype {
NONE,
COMPLEX,
CROSS_CONJ,
REAL,
SPECTRUM,
};
// Input and output arrays can be either complex or real
// Used to be a union, but was prone to errors
struct rc {
float *r;
complex float *c;
};
#define ND 4
struct filter_in {
enum filtertype in_type; // REAL or COMPLEX
int ilen; // Length of user portion of input buffer, aka 'L'
int bins; // Total number of frequency bins. Complex: L + M - 1; Real: (L + M - 1)/2 + 1
int impulse_length; // Length of filter impulse response, aka 'M'
int wcnt; // Samples written to unexecuted input buffer
void *input_buffer; // Beginning of mirrored ring buffer
size_t input_buffer_size; // size of input buffer in **bytes**
struct rc input_write_pointer; // For incoming samples
struct rc input_read_pointer; // For FFT input
fftwf_plan fwd_plan; // FFT (time -> frequency)
pthread_mutex_t filter_mutex; // Synchronization for sequence number
pthread_cond_t filter_cond;
complex float *fdomain[ND];
unsigned int next_jobnum;
unsigned int completed_jobs[ND];
};
struct filter_out {
struct filter_in * restrict master;
enum filtertype out_type; // REAL, COMPLEX or CROSS_CONJ
int olen; // Length of user portion of output buffer (decimated L)
int bins; // Number of frequency bins; == N for complex, == N/2 + 1 for real output
complex float * restrict fdomain; // Filtered signal in frequency domain
complex float * restrict response; // Filter response in frequency domain
pthread_mutex_t response_mutex;
struct rc output_buffer; // Actual time-domain output buffer, length N/decimate
struct rc output; // Beginning of user output area, length L/decimate
fftwf_plan rev_plan; // IFFT (frequency -> time)
unsigned int next_jobnum;
float noise_gain; // Filter gain on uniform noise (ratio < 1)
int block_drops; // Lost frequency domain blocks, e.g., from late scheduling of slave thread
int rcnt; // Samples read from output buffer
};
int window_filter(int L,int M,complex float * restrict response,float beta);
int window_rfilter(int L,int M,complex float * restrict response,float beta);
struct filter_in *create_filter_input(struct filter_in *,int const L,int const M, enum filtertype const in_type);
struct filter_out *create_filter_output(struct filter_out *slave,struct filter_in * restrict master,complex float * restrict response,int olen, enum filtertype out_type);
int execute_filter_input(struct filter_in * restrict);
int execute_filter_output(struct filter_out * restrict ,int);
int execute_filter_output_idle(struct filter_out * const slave);
int delete_filter_input(struct filter_in * restrict);
int delete_filter_output(struct filter_out * restrict);
int make_kaiser(float * restrict,int M,float);
int set_filter(struct filter_out * restrict,float,float,float);
float const noise_gain(struct filter_out const * restrict);
void *run_fft(void *);
int write_cfilter(struct filter_in *, complex float const *,int size);
int write_rfilter(struct filter_in *, float const *,int size);
// Write complex sample to input side of filter
static inline int put_cfilter(struct filter_in * restrict const f,complex float const s){ // Complex
assert((void *)(f->input_write_pointer.c) >= f->input_buffer);
assert((void *)(f->input_write_pointer.c) < f->input_buffer + f->input_buffer_size);
*f->input_write_pointer.c++ = s;
mirror_wrap((void *)&f->input_write_pointer.c, f->input_buffer,f->input_buffer_size);
if(++f->wcnt >= f->ilen){
f->wcnt -= f->ilen;
execute_filter_input(f);
return 1; // may now execute filter output without blocking
}
return 0;
}
static inline int put_rfilter(struct filter_in * restrict const f,float const s){
assert((void *)(f->input_write_pointer.r) >= f->input_buffer);
assert((void *)(f->input_write_pointer.r) < f->input_buffer + f->input_buffer_size);
*f->input_write_pointer.r++ = s;
mirror_wrap((void *)&f->input_write_pointer.r, f->input_buffer,f->input_buffer_size);
if(++f->wcnt >= f->ilen){
f->wcnt -= f->ilen;
execute_filter_input(f);
return 1; // may now execute filter output without blocking
}
return 0;
}
// Read real samples from output side of filter
static inline float read_rfilter(struct filter_out * restrict const f,int const rotate){
if(f->rcnt == 0){
execute_filter_output(f,rotate);
f->rcnt = f->olen;
}
return f->output.r[f->olen - f->rcnt--];
}
// Read complex samples from output side of filter
static inline complex float read_cfilter(struct filter_out * restrict const f,int const rotate){
if(f->rcnt == 0){
execute_filter_output(f,rotate);
f->rcnt = f->olen;
}
return f->output.c[f->olen - f->rcnt--];
}
#endif