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
|
/*---------------------------------------------------------------------------*\
FILE........: freedv_700d_comprx.c
AUTHOR......: David Rowe
DATE CREATED: July 2022
Complex valued rx to support ctests. Includes a few operations that will
only work if complex Tx and Rx signals are being handled correctly.
\*---------------------------------------------------------------------------*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "codec2_cohpsk.h"
#include "comp_prim.h"
#include "freedv_api.h"
#include "freedv_api_internal.h"
#include "ofdm_internal.h"
int main(int argc, char *argv[]) {
/* with no arguments then run with no test code */
int test_num = 0;
if (argc == 2) {
if (strcmp(argv[1], "tx") == 0) {
test_num = 1;
}
if (strcmp(argv[1], "rx") == 0) {
test_num = 2;
}
}
fprintf(stderr, "%d\n", test_num);
struct freedv *freedv;
freedv = freedv_open(FREEDV_MODE_700D);
assert(freedv != NULL);
/* note API functions to tell us how big our buffers need to be */
short speech_out[freedv_get_n_max_speech_samples(freedv)];
short demod_in[2 * freedv_get_n_max_modem_samples(freedv)];
COMP demod_in_comp[2 * freedv_get_n_max_modem_samples(freedv)];
/* set up small freq offset */
float foff_hz = 25;
COMP phase_ch;
phase_ch.real = 1.0;
phase_ch.imag = 0.0;
/* set complex sine wave interferer at -fc */
COMP interferer_phase = {1.0, 0.0};
COMP interferer_freq;
interferer_freq.real =
cos(2.0 * M_PI * freedv->ofdm->tx_centre / FREEDV_FS_8000);
interferer_freq.imag =
sin(2.0 * M_PI * freedv->ofdm->tx_centre / FREEDV_FS_8000);
interferer_freq = cconj(interferer_freq);
/* log a file of demod input samples for plotting in Octave */
FILE *fdemod = fopen("demod.f32", "wb");
assert(fdemod != NULL);
/* measure demod input power, interferer input power */
float power_d = 0.0;
float power_interferer = 0.0;
int frames = 0, sum_sync = 0, frames_snr = 0;
float sum_snr = 0.0;
size_t nin, nout;
nin = freedv_nin(freedv);
while (fread(demod_in, sizeof(short), 2 * nin, stdin) == 2 * nin) {
for (int i = 0; i < nin; i++) {
demod_in_comp[i].real = (float)demod_in[2 * i];
demod_in_comp[i].imag = (float)demod_in[2 * i + 1];
// demod_in_comp[i].imag = 0;
}
if (test_num == 1) {
/* So Tx is a complex OFDM signal centered at +fc. A small
shift fd followed by Re{} will only work if Tx is complex.
If Tx is real, neg freq components at -fc+fd will be
aliased on top of fc+fd wanted signal by Re{} operation.
This can be tested by setting demod_in_comp[i].imag = 0
above */
fdmdv_freq_shift_coh(demod_in_comp, demod_in_comp, foff_hz,
FREEDV_FS_8000, &phase_ch, nin);
for (int i = 0; i < nin; i++) demod_in_comp[i].imag = 0.0;
}
if (test_num == 2) {
/* a complex sinewave (carrier) at -fc will only be ignored if
Rx is treating signal as complex, otherwise if real a +fc
alias will appear in the middle of our wanted signal at
+fc, this can be tested by setting demod_in_comp[i].imag =
0 below */
for (int i = 0; i < nin; i++) {
COMP a = fcmult(2E4, interferer_phase);
interferer_phase = cmult(interferer_phase, interferer_freq);
power_interferer += a.real * a.real + a.imag * a.imag;
COMP d = demod_in_comp[i];
power_d += d.real * d.real + d.imag * d.imag;
demod_in_comp[i] = cadd(d, a);
// demod_in_comp[i].imag = 0;
}
}
/* useful to take a look at this with Octave */
fwrite(demod_in_comp, sizeof(COMP), nin, fdemod);
nout = freedv_comprx(freedv, speech_out, demod_in_comp);
nin = freedv_nin(freedv); /* call me on every loop! */
fwrite(speech_out, sizeof(short), nout, stdout);
int sync;
float snr_est;
freedv_get_modem_stats(freedv, &sync, &snr_est);
fprintf(stderr, "sync: %d snr_est: %f\n", sync, snr_est);
frames++;
sum_sync += sync;
if (sync) {
sum_snr += snr_est;
frames_snr++;
}
}
fclose(fdemod);
freedv_close(freedv);
if (test_num == 2)
fprintf(stderr, "Demod/Interferer power ratio: %3.2f dB\n",
10 * log10(power_d / power_interferer));
float snr_av = sum_snr / frames_snr;
fprintf(stderr, "frames: %d sum_sync: %d snr_av: %3.2f dB\n", frames,
sum_sync, snr_av);
if (snr_av > 8.0)
return 0;
else
return 1;
}
|