aboutsummaryrefslogtreecommitdiff
path: root/src/ch.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ch.c')
-rw-r--r--src/ch.c836
1 files changed, 444 insertions, 392 deletions
diff --git a/src/ch.c b/src/ch.c
index 57411bd..9d8d895 100644
--- a/src/ch.c
+++ b/src/ch.c
@@ -26,454 +26,506 @@
*/
#include <assert.h>
+#include <errno.h>
+#include <getopt.h>
+#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <math.h>
-#include <errno.h>
-#include <getopt.h>
-#include "freedv_api.h"
#include "codec2_cohpsk.h"
#include "comp_prim.h"
+#include "debug_alloc.h"
+#include "freedv_api.h"
#include "ht_coeff.h"
#include "ssbfilt_coeff.h"
-#include "debug_alloc.h"
-
-#define BUF_N 160
-#define MPG_DELAY_MS 0.5
-#define MPP_DELAY_MS 2.0
-#define MPD_DELAY_MS 4.0
+#define BUF_N 160
+#define MPG_DELAY_MS 0.5
+#define MPP_DELAY_MS 2.0
+#define MPD_DELAY_MS 4.0
/* see instructions below for how to generate these files */
-#define DEFAULT_FADING_DIR "unittest"
-#define MPG_FADING_FILE_NAME "slow_fading_samples.float"
-#define MPP_FADING_FILE_NAME "fast_fading_samples.float"
-#define MPD_FADING_FILE_NAME "faster_fading_samples.float"
+#define DEFAULT_FADING_DIR "unittest"
+#define MPG_FADING_FILE_NAME "slow_fading_samples.float"
+#define MPP_FADING_FILE_NAME "fast_fading_samples.float"
+#define MPD_FADING_FILE_NAME "faster_fading_samples.float"
// Gaussian from uniform:
float gaussian(void) {
- double x = (double)rand() / RAND_MAX;
- double y = (double)rand() / RAND_MAX;
- double z = sqrt(-2 * log(x)) * cos(2 * M_PI * y);
- return sqrt(1./2.) * z;
+ double x = (double)rand() / RAND_MAX;
+ double y = (double)rand() / RAND_MAX;
+ double z = sqrt(-2 * log(x)) * cos(2 * M_PI * y);
+ return sqrt(1. / 2.) * z;
}
// complex noise sample
COMP noise(void) {
- COMP n = {gaussian(),gaussian()};
- return n;
+ COMP n = {gaussian(), gaussian()};
+ return n;
}
-int main(int argc, char *argv[])
-{
- FILE *fin, *ffading, *fout;
- char *fading_dir;
- float NodB, foff_hz;
- int fading_en, nhfdelay;
-
- short buf[BUF_N];
- float htbuf[HT_N+BUF_N];
- COMP ch_in[BUF_N];
- COMP ch_fdm[BUF_N];
- COMP ssbfiltbuf[SSBFILT_N+BUF_N];
- COMP ssbfiltout[BUF_N];
-
- COMP phase_ch;
- float No, variance;
- COMP scaled_noise;
- float hf_gain;
- COMP *ch_fdm_delay = NULL, aspread, aspread_2ms, delayed, direct;
- float tx_pwr, tx_pwr_fade, noise_pwr, user_multipath_delay;
- int frames, i, j, k, Fs, ret, nclipped, noutclipped, ssbfilt_en, complex_out, ctest;
- float sam, peak, clip, papr, CNo, snr3k, gain;
-
- if (argc < 3) {
- helpmsg:
- fprintf(stderr, "Command line channel simulation tool.\n"
- "\n"
- "usage: %s InputRealModemRawFile OutputRealModemRawFile [Options]\n"
- "\n"
- " real int16 input -> Gain -> Hilbert Transform -> clipper -> freq shift ->\n"
- " Multipath -> AWGN noise -> SSB filter -> real int16 output\n"
- "\n"
- "[--clip int16] Hilbert clipper (clip complex signal magnitude, default 32767)\n"
- "[--complexout] Optional int16 IQ complex output (default real int16)\n"
- "[--ctest] Check PAPR is around 0dB, used to support ctests\n"
- "[--freq FoffHz] Frequency offset (default 0Hz)\n"
- "[--fading_dir Path] path to multipath fading files (default 'unittest')\n"
- "[--Fs SampleRateHz] Sample rate of simulation (default 8000 Hz)\n"
- "[--gain G] Linear gain (default 1.0)\n"
- "[--mpg] Multipath good 0.1Hz Doppler, 0.5ms delay\n"
- "[--mpp] Multipath poor 1.0Hz Doppler, 2.0ms delay\n"
- "[--mpd] Multipath disturbed 2.0Hz Doppler, 4.0ms delay\n"
- "[--ssbfilt 0|1] SSB bandwidth filter (default 1 on)\n"
- "[--mulipath_delay ms] Optionally adjust multipath delay\n"
- "[--No dBHz] AWGN Noise density dB/Hz (default -100)"
- "\n"
- , argv[0]);
- exit(1);
+int main(int argc, char *argv[]) {
+ FILE *fin, *ffading, *fout;
+ char *fading_dir;
+ float NodB, foff_hz;
+ int fading_en, nhfdelay;
+
+ short buf[BUF_N];
+ float htbuf[HT_N + BUF_N];
+ COMP ch_in[BUF_N];
+ COMP ch_fdm[BUF_N];
+ COMP ssbfiltbuf[SSBFILT_N + BUF_N];
+ COMP ssbfiltout[BUF_N];
+
+ COMP phase_ch;
+ float No, variance;
+ COMP scaled_noise;
+ float hf_gain;
+ COMP *ch_fdm_delay = NULL, aspread, aspread_2ms, delayed, direct;
+ float tx_pwr, tx_pwr_fade, noise_pwr, user_multipath_delay;
+ int frames, i, j, k, Fs, ret, nclipped, noutclipped, ssbfilt_en, complex_out,
+ ctest;
+ float sam, peak, clip, papr, CNo, snr3k, gain;
+
+ if (argc < 3) {
+ helpmsg:
+ fprintf(
+ stderr,
+ "Command line channel simulation tool.\n"
+ "\n"
+ "usage: %s InputRealModemRawFile OutputRealModemRawFile [Options]\n"
+ "\n"
+ " real int16 input -> Gain -> Hilbert Transform -> clipper -> freq "
+ "shift ->\n"
+ " Multipath -> AWGN noise -> SSB filter -> real int16 output\n"
+ "\n"
+ "[--clip int16] Hilbert clipper (clip complex signal "
+ "magnitude, default 32767)\n"
+ "[--complexout] Optional int16 IQ complex output (default real "
+ "int16)\n"
+ "[--ctest] Check PAPR is around 0dB, used to support "
+ "ctests\n"
+ "[--freq FoffHz] Frequency offset (default 0Hz)\n"
+ "[--fading_dir Path] path to multipath fading files (default "
+ "'unittest')\n"
+ "[--Fs SampleRateHz] Sample rate of simulation (default 8000 Hz)\n"
+ "[--gain G] Linear gain (default 1.0)\n"
+ "[--mpg] Multipath good 0.1Hz Doppler, 0.5ms delay\n"
+ "[--mpp] Multipath poor 1.0Hz Doppler, 2.0ms delay\n"
+ "[--mpd] Multipath disturbed 2.0Hz Doppler, 4.0ms "
+ "delay\n"
+ "[--ssbfilt 0|1] SSB bandwidth filter (default 1 on)\n"
+ "[--mulipath_delay ms] Optionally adjust multipath delay\n"
+ "[--No dBHz] AWGN Noise density dB/Hz (default -100)"
+ "\n",
+ argv[0]);
+ exit(1);
+ }
+
+ if (strcmp(argv[1], "-") == 0)
+ fin = stdin;
+ else if ((fin = fopen(argv[1], "rb")) == NULL) {
+ fprintf(stderr, "ch: Error opening input modem raw file: %s: %s.\n",
+ argv[1], strerror(errno));
+ exit(1);
+ }
+
+ if (strcmp(argv[2], "-") == 0)
+ fout = stdout;
+ else if ((fout = fopen(argv[2], "wb")) == NULL) {
+ fprintf(stderr, "ch: Error opening output modem raw file: %s: %s.\n",
+ argv[2], strerror(errno));
+ exit(1);
+ }
+
+ NodB = -100;
+ Fs = 8000;
+ foff_hz = 0.0;
+ fading_en = 0;
+ ctest = 0;
+ clip = 32767;
+ gain = 1.0;
+ ssbfilt_en = 1;
+ complex_out = 0;
+ fading_dir = strdup(DEFAULT_FADING_DIR);
+ user_multipath_delay = -1.0;
+
+ int o = 0;
+ int opt_idx = 0;
+ while (o != -1) {
+ static struct option long_opts[] = {
+ {"complexout", no_argument, 0, 'o'},
+ {"ctest", no_argument, 0, 't'},
+ {"clip", required_argument, 0, 'c'},
+ {"fading_dir", required_argument, 0, 'u'},
+ {"freq", required_argument, 0, 'f'},
+ {"Fs", required_argument, 0, 'r'},
+ {"gain", required_argument, 0, 'g'},
+ {"ssbfilt", required_argument, 0, 's'},
+ {"help", no_argument, 0, 'h'},
+ {"mpg", no_argument, 0, 'i'},
+ {"mpp", no_argument, 0, 'p'},
+ {"mpd", no_argument, 0, 'd'},
+ {"multipath_delay", required_argument, 0, 'm'},
+ {"No", required_argument, 0, 'n'},
+ {0, 0, 0, 0}};
+
+ o = getopt_long(argc, argv, "c:df:g:im:n:opr:s:tu:h", long_opts, &opt_idx);
+
+ switch (o) {
+ case 'c':
+ clip = atof(optarg);
+ break;
+ case 'd':
+ fading_en = 3;
+ break;
+ case 'f':
+ foff_hz = atof(optarg);
+ break;
+ case 'g':
+ gain = atof(optarg);
+ break;
+ case 'i':
+ fading_en = 1;
+ break;
+ case 'm':
+ user_multipath_delay = atof(optarg);
+ break;
+ case 'n':
+ NodB = atof(optarg);
+ break;
+ case 'o':
+ complex_out = 1;
+ break;
+ case 'p':
+ fading_en = 2;
+ break;
+ case 'r':
+ Fs = atoi(optarg);
+ break;
+ case 's':
+ ssbfilt_en = atoi(optarg);
+ break;
+ case 't':
+ ctest = 1;
+ break;
+ case 'u':
+ fading_dir = strdup(optarg);
+ break;
+ case 'h':
+ case '?':
+ goto helpmsg;
+ break;
}
-
- if (strcmp(argv[1], "-") == 0) fin = stdin;
- else if ( (fin = fopen(argv[1],"rb")) == NULL ) {
- fprintf(stderr, "ch: Error opening input modem raw file: %s: %s.\n",
- argv[1], strerror(errno));
+ }
+
+ phase_ch.real = 1.0;
+ phase_ch.imag = 0.0;
+
+ /* N = var = NoFs */
+
+ // arbitrary noise scaling, to maintain backwards compatibility with many
+ // tests. TODO make the No units more sensible, and fix all the tests that
+ // depend on this scaling
+ No = pow(10.0, NodB / 10.0) * 1000 * 1000;
+ variance = Fs * No;
+
+ tx_pwr = tx_pwr_fade = noise_pwr = 0.0;
+ noutclipped = 0;
+ nclipped = 0;
+ peak = 0.0;
+
+ /* init HF fading model */
+
+ ffading = NULL;
+ nhfdelay = 0;
+ if (fading_en) {
+ char fname[256];
+
+ if (fading_en == 1) {
+ sprintf(fname, "%s/%s", fading_dir, MPG_FADING_FILE_NAME);
+ ffading = fopen(fname, "rb");
+ if (ffading == NULL) {
+ cant_load_fading_file:
+ fprintf(stderr,
+ "-----------------------------------------------------\n");
+ fprintf(stderr, "ch ERROR: Can't find fading file: %s\n", fname);
+ fprintf(
+ stderr,
+ "\nAdjust path --fading_dir or use GNU Octave to generate:\n\n");
+ gen_fading_file:
+ fprintf(stderr, "$ octave --no-gui\n");
+ fprintf(stderr, "octave:24> pkg load signal\n");
+ fprintf(stderr, "octave:24> time_secs=60\n");
+ fprintf(stderr,
+ "octave:25> ch_fading(\"faster_fading_samples.float\", 8000, "
+ "2.0, 8000*time_secs)\n");
+ fprintf(stderr,
+ "octave:26> ch_fading(\"fast_fading_samples.float\", 8000, "
+ "1.0, 8000*time_secs)\n");
+ fprintf(stderr,
+ "octave:27> ch_fading(\"slow_fading_samples.float\", 8000, "
+ "0.1, 8000*time_secs)\n");
+ fprintf(stderr,
+ "-----------------------------------------------------\n");
exit(1);
+ }
+ nhfdelay = floor(MPG_DELAY_MS * Fs / 1000);
}
- if (strcmp(argv[2], "-") == 0) fout = stdout;
- else if ( (fout = fopen(argv[2],"wb")) == NULL ) {
- fprintf(stderr, "ch: Error opening output modem raw file: %s: %s.\n",
- argv[2], strerror(errno));
- exit(1);
+ if (fading_en == 2) {
+ sprintf(fname, "%s/%s", fading_dir, MPP_FADING_FILE_NAME);
+ ffading = fopen(fname, "rb");
+ if (ffading == NULL) goto cant_load_fading_file;
+ nhfdelay = floor(MPP_DELAY_MS * Fs / 1000);
}
- NodB = -100;
- Fs = 8000; foff_hz = 0.0; fading_en = 0; ctest = 0;
- clip =32767; gain = 1.0;
- ssbfilt_en = 1; complex_out = 0;
- fading_dir = strdup(DEFAULT_FADING_DIR); user_multipath_delay = -1.0;
-
- int o = 0;
- int opt_idx = 0;
- while( o != -1 ){
- static struct option long_opts[] = {
- {"complexout", no_argument, 0, 'o'},
- {"ctest", no_argument, 0, 't'},
- {"clip", required_argument, 0, 'c'},
- {"fading_dir", required_argument, 0, 'u'},
- {"freq", required_argument, 0, 'f'},
- {"Fs", required_argument, 0, 'r'},
- {"gain", required_argument, 0, 'g'},
- {"ssbfilt", required_argument, 0, 's'},
- {"help", no_argument, 0, 'h'},
- {"mpg", no_argument, 0, 'i'},
- {"mpp", no_argument, 0, 'p'},
- {"mpd", no_argument, 0, 'd'},
- {"multipath_delay", required_argument, 0, 'm'},
- {"No", required_argument, 0, 'n'},
- {0, 0, 0, 0}
- };
-
- o = getopt_long(argc,argv,"c:df:g:im:n:opr:s:tu:h",long_opts,&opt_idx);
-
- switch(o) {
- case 'c':
- clip = atof(optarg);
- break;
- case 'd':
- fading_en = 3;
- break;
- case 'f':
- foff_hz = atof(optarg);
- break;
- case 'g':
- gain = atof(optarg);
- break;
- case 'i':
- fading_en = 1;
- break;
- case 'm':
- user_multipath_delay = atof(optarg);
- break;
- case 'n':
- NodB = atof(optarg);
- break;
- case 'o':
- complex_out = 1;
- break;
- case 'p':
- fading_en = 2;
- break;
- case 'r':
- Fs = atoi(optarg);
- break;
- case 's':
- ssbfilt_en = atoi(optarg);
- break;
- case 't':
- ctest = 1;
- break;
- case 'u':
- fading_dir = strdup(optarg);
- break;
- case 'h':
- case '?':
- goto helpmsg;
- break;
- }
+ if (fading_en == 3) {
+ sprintf(fname, "%s/%s", fading_dir, MPD_FADING_FILE_NAME);
+ ffading = fopen(fname, "rb");
+ if (ffading == NULL) goto cant_load_fading_file;
+ nhfdelay = floor(MPD_DELAY_MS * Fs / 1000);
}
- phase_ch.real = 1.0; phase_ch.imag = 0.0;
-
- /* N = var = NoFs */
-
- // arbitrary noise scaling, to maintain backwards compatibility with many tests. TODO make the No
- // units more sensible, and fix all the tests that depend on this scaling
- No = pow(10.0, NodB/10.0)*1000*1000;
- variance = Fs*No;
-
- tx_pwr = tx_pwr_fade = noise_pwr = 0.0;
- noutclipped = 0; nclipped = 0;
- peak = 0.0;
-
- /* init HF fading model */
+ ch_fdm_delay = (COMP *)MALLOC((nhfdelay + COHPSK_NOM_SAMPLES_PER_FRAME) *
+ sizeof(COMP));
+ assert(ch_fdm_delay != NULL);
+ for (i = 0; i < nhfdelay + COHPSK_NOM_SAMPLES_PER_FRAME; i++) {
+ ch_fdm_delay[i].real = 0.0;
+ ch_fdm_delay[i].imag = 0.0;
+ }
- ffading = NULL;
- nhfdelay = 0;
- if (fading_en) {
- char fname[256];
-
- if (fading_en == 1) {
- sprintf(fname, "%s/%s", fading_dir, MPG_FADING_FILE_NAME);
- ffading = fopen(fname, "rb");
- if (ffading == NULL) {
- cant_load_fading_file:
- fprintf(stderr, "-----------------------------------------------------\n");
- fprintf(stderr, "ch ERROR: Can't find fading file: %s\n", fname);
- fprintf(stderr, "\nAdjust path --fading_dir or use GNU Octave to generate:\n\n");
- gen_fading_file:
- fprintf(stderr, "$ octave --no-gui\n");
- fprintf(stderr, "octave:24> pkg load signal\n");
- fprintf(stderr, "octave:24> time_secs=60\n");
- fprintf(stderr, "octave:25> ch_fading(\"faster_fading_samples.float\", 8000, 2.0, 8000*time_secs)\n");
- fprintf(stderr, "octave:26> ch_fading(\"fast_fading_samples.float\", 8000, 1.0, 8000*time_secs)\n");
- fprintf(stderr, "octave:27> ch_fading(\"slow_fading_samples.float\", 8000, 0.1, 8000*time_secs)\n");
- fprintf(stderr, "-----------------------------------------------------\n");
- exit(1);
- }
- nhfdelay = floor(MPG_DELAY_MS*Fs/1000);
- }
+ /* optionally override delay from command line */
+ if (user_multipath_delay >= 0.0)
+ nhfdelay = floor(user_multipath_delay * Fs / 1000);
+
+ /* first values in file are HF gains */
+
+ for (i = 0; i < 4; i++) ret = fread(&hf_gain, sizeof(float), 1, ffading);
+ // fprintf(stderr, "hf_gain: %f\n", hf_gain);
+ }
+
+ assert(HT_N == sizeof(ht_coeff) / sizeof(COMP));
+ for (i = 0; i < HT_N; i++) {
+ htbuf[i] = 0.0;
+ }
+ for (i = 0; i < SSBFILT_N; i++) {
+ ssbfiltbuf[i].real = 0.0;
+ ssbfiltbuf[i].imag = 0.0;
+ }
+ COMP lo_phase = {1.0, 0.0};
+ COMP lo_freq;
+ lo_freq.real = cos(2.0 * M_PI * SSBFILT_CENTRE / Fs);
+ lo_freq.imag = sin(2.0 * M_PI * SSBFILT_CENTRE / Fs);
+
+ fprintf(stderr,
+ "ch: Fs: %d NodB: %4.2f foff: %4.2f Hz fading: %d nhfdelay: %d clip: "
+ "%4.2f ssbfilt: %d complexout: %d\n",
+ Fs, NodB, foff_hz, fading_en, nhfdelay, clip, ssbfilt_en,
+ complex_out);
+
+ /* --------------------------------------------------------*\
+ Main Loop
+ \*---------------------------------------------------------*/
+
+ frames = 0;
+ while (fread(buf, sizeof(short), BUF_N, fin) == BUF_N) {
+ frames++;
+
+ /* Hilbert Transform to produce complex signal so we can do
+ single sided freq shifts, HF channel models, and analog
+ compression. Allows us to use real signal I/O.
+
+ As the real and imag filters both have unity gain, ch_in[]
+ has twice the power of the real input signal buf[].
+ */
+
+ for (i = 0, j = HT_N; i < BUF_N; i++, j++) {
+ htbuf[j] = (float)buf[i] * gain;
+
+ /* FIR filter with HT to get imag, just delay to get real */
+
+ ch_in[i].real = 0.0;
+ ch_in[i].imag = 0.0;
+ for (k = 0; k < HT_N; k++) {
+ ch_in[i].real += htbuf[j - k] * ht_coeff[k].real;
+ ch_in[i].imag += htbuf[j - k] * ht_coeff[k].imag;
+ }
+ // printf("%d %f %f\n", i, ch_in[i].real, ch_in[i].imag);
+ }
+ assert(j <= (BUF_N + HT_N));
- if (fading_en == 2) {
- sprintf(fname, "%s/%s", fading_dir, MPP_FADING_FILE_NAME);
- ffading = fopen(fname, "rb");
- if (ffading == NULL) goto cant_load_fading_file;
- nhfdelay = floor(MPP_DELAY_MS*Fs/1000);
- }
+ /* update HT memory */
+ for (i = 0; i < HT_N; i++) htbuf[i] = htbuf[i + BUF_N];
- if (fading_en == 3) {
- sprintf(fname, "%s/%s", fading_dir, MPD_FADING_FILE_NAME);
- ffading = fopen(fname, "rb");
- if (ffading == NULL) goto cant_load_fading_file;
- nhfdelay = floor(MPD_DELAY_MS*Fs/1000);
- }
+ /* --------------------------------------------------------*\
+ Clipping mag of complex signal
+ \*---------------------------------------------------------*/
- ch_fdm_delay = (COMP*)MALLOC((nhfdelay+COHPSK_NOM_SAMPLES_PER_FRAME)*sizeof(COMP));
- assert(ch_fdm_delay != NULL);
- for(i=0; i<nhfdelay+COHPSK_NOM_SAMPLES_PER_FRAME; i++) {
- ch_fdm_delay[i].real = 0.0;
- ch_fdm_delay[i].imag = 0.0;
+ for (i = 0; i < BUF_N; i++) {
+ float mag =
+ sqrt(ch_in[i].real * ch_in[i].real + ch_in[i].imag * ch_in[i].imag);
+ float angle = atan2(ch_in[i].imag, ch_in[i].real);
+ if (mag > clip) {
+ mag = clip;
+ nclipped++;
+ }
+ tx_pwr += mag * mag;
+ /* we get a bit of overshoot in peak measurements if HT filter hasn't been
+ * primed */
+ if (frames * BUF_N > HT_N)
+ if (mag > peak) {
+ peak = mag;
+ // fprintf(stderr, "%d %f\n",frames, mag);
}
-
- /* optionally override delay from command line */
- if (user_multipath_delay >= 0.0) nhfdelay = floor(user_multipath_delay*Fs/1000);
-
- /* first values in file are HF gains */
-
- for (i=0; i<4; i++)
- ret = fread(&hf_gain, sizeof(float), 1, ffading);
- //fprintf(stderr, "hf_gain: %f\n", hf_gain);
+ ch_in[i].real = mag * cos(angle);
+ ch_in[i].imag = mag * sin(angle);
}
- assert(HT_N == sizeof(ht_coeff)/sizeof(COMP));
- for(i=0; i<HT_N; i++) {
- htbuf[i] = 0.0;
- }
- for(i=0; i<SSBFILT_N; i++) {
- ssbfiltbuf[i].real = 0.0; ssbfiltbuf[i].imag = 0.0;
- }
- COMP lo_phase = {1.0,0.0};
- COMP lo_freq;
- lo_freq.real = cos(2.0*M_PI*SSBFILT_CENTRE/Fs);
- lo_freq.imag = sin(2.0*M_PI*SSBFILT_CENTRE/Fs);
-
- fprintf(stderr, "ch: Fs: %d NodB: %4.2f foff: %4.2f Hz fading: %d nhfdelay: %d clip: %4.2f ssbfilt: %d complexout: %d\n",
- Fs, NodB, foff_hz, fading_en, nhfdelay, clip, ssbfilt_en, complex_out);
-
/* --------------------------------------------------------*\
- Main Loop
+ Channel
\*---------------------------------------------------------*/
- frames = 0;
- while(fread(buf, sizeof(short), BUF_N, fin) == BUF_N) {
- frames++;
+ fdmdv_freq_shift_coh(ch_fdm, ch_in, foff_hz, Fs, &phase_ch, BUF_N);
- /* Hilbert Transform to produce complex signal so we can do
- single sided freq shifts, HF channel models, and analog
- compression. Allows us to use real signal I/O.
+ /* optional HF fading -------------------------------------*/
- As the real and imag filters both have unity gain, ch_in[]
- has twice the power of the real input signal buf[].
- */
-
- for(i=0, j=HT_N; i<BUF_N; i++,j++) {
+ if (fading_en) {
+ /* update delayed signal buffer */
- htbuf[j] = (float)buf[i]*gain;
+ for (i = 0; i < nhfdelay; i++) ch_fdm_delay[i] = ch_fdm_delay[i + BUF_N];
+ for (j = 0; j < BUF_N; i++, j++) ch_fdm_delay[i] = ch_fdm[j];
- /* FIR filter with HT to get imag, just delay to get real */
+ /* combine direct and delayed paths, both multiplied by
+ "spreading" (Doppler) functions */
- ch_in[i].real = 0.0;
- ch_in[i].imag = 0.0;
- for(k=0; k<HT_N; k++) {
- ch_in[i].real += htbuf[j-k]*ht_coeff[k].real;
- ch_in[i].imag += htbuf[j-k]*ht_coeff[k].imag;
- }
- //printf("%d %f %f\n", i, ch_in[i].real, ch_in[i].imag);
+ for (i = 0; i < BUF_N; i++) {
+ ret = fread(&aspread, sizeof(COMP), 1, ffading);
+ if (ret == 0) {
+ fprintf(stderr,
+ "ch: Fading file finished - simulation stopping. You may "
+ "need more samples:\n");
+ goto gen_fading_file;
}
- assert(j <= (BUF_N+HT_N));
-
- /* update HT memory */
- for(i=0; i<HT_N; i++)
- htbuf[i] = htbuf[i+BUF_N];
-
- /* --------------------------------------------------------*\
- Clipping mag of complex signal
- \*---------------------------------------------------------*/
-
- for(i=0; i<BUF_N; i++) {
- float mag = sqrt(ch_in[i].real*ch_in[i].real + ch_in[i].imag*ch_in[i].imag);
- float angle = atan2(ch_in[i].imag, ch_in[i].real);
- if (mag > clip) {
- mag = clip;
- nclipped++;
- }
- tx_pwr += mag*mag;
- /* we get a bit of overshoot in peak measurements if HT filter hasn't been primed */
- if (frames*BUF_N > HT_N)
- if (mag > peak) {
- peak = mag;
- //fprintf(stderr, "%d %f\n",frames, mag);
- }
- ch_in[i].real = mag*cos(angle);
- ch_in[i].imag = mag*sin(angle);
+ ret = fread(&aspread_2ms, sizeof(COMP), 1, ffading);
+ if (ret == 0) {
+ fprintf(stderr,
+ "ch: Fading file finished - simulation stopping. You may "
+ "need more samples:\n");
+ goto gen_fading_file;
}
+ // printf("%f %f %f %f\n", aspread.real, aspread.imag, aspread_2ms.real,
+ // aspread_2ms.imag);
- /* --------------------------------------------------------*\
- Channel
- \*---------------------------------------------------------*/
-
- fdmdv_freq_shift_coh(ch_fdm, ch_in, foff_hz, Fs, &phase_ch, BUF_N);
-
- /* optional HF fading -------------------------------------*/
-
- if (fading_en) {
-
- /* update delayed signal buffer */
-
- for(i=0; i<nhfdelay; i++)
- ch_fdm_delay[i] = ch_fdm_delay[i+BUF_N];
- for(j=0; j<BUF_N; i++, j++)
- ch_fdm_delay[i] = ch_fdm[j];
-
- /* combine direct and delayed paths, both multiplied by
- "spreading" (Doppler) functions */
-
- for(i=0; i<BUF_N; i++) {
- ret = fread(&aspread, sizeof(COMP), 1, ffading);
- if (ret == 0) {
- fprintf(stderr, "ch: Fading file finished - simulation stopping. You may need more samples:\n");
- goto gen_fading_file;
- }
- ret = fread(&aspread_2ms, sizeof(COMP), 1, ffading);
- if (ret == 0) {
- fprintf(stderr, "ch: Fading file finished - simulation stopping. You may need more samples:\n");
- goto gen_fading_file;
- }
- //printf("%f %f %f %f\n", aspread.real, aspread.imag, aspread_2ms.real, aspread_2ms.imag);
+ direct = cmult(aspread, ch_fdm[i]);
+ delayed = cmult(aspread_2ms, ch_fdm_delay[i]);
+ ch_fdm[i] = fcmult(hf_gain, cadd(direct, delayed));
+ }
+ }
- direct = cmult(aspread, ch_fdm[i]);
- delayed = cmult(aspread_2ms, ch_fdm_delay[i]);
- ch_fdm[i] = fcmult(hf_gain, cadd(direct, delayed));
- }
- }
+ /* Measure power after fading model to make sure average pwr
+ is the same as AWGN channels. We only output the real
+ signal, which is half the power. */
- /* Measure power after fading model to make sure average pwr
- is the same as AWGN channels. We only output the real
- signal, which is half the power. */
+ for (i = 0; i < BUF_N; i++) {
+ tx_pwr_fade += pow(ch_fdm[i].real, 2.0);
+ }
- for(i=0; i<BUF_N; i++) {
- tx_pwr_fade += pow(ch_fdm[i].real, 2.0);
- }
+ /* AWGN noise ------------------------------------------*/
- /* AWGN noise ------------------------------------------*/
+ for (i = 0; i < BUF_N; i++) {
+ COMP n = noise();
+ scaled_noise = fcmult(sqrt(variance), n);
+ ch_fdm[i] = cadd(ch_fdm[i], scaled_noise);
+ noise_pwr += pow(scaled_noise.real, 2.0) + pow(scaled_noise.imag, 2.0);
+ }
- for(i=0; i<BUF_N; i++) {
- COMP n = noise();
- scaled_noise = fcmult(sqrt(variance), n);
- ch_fdm[i] = cadd(ch_fdm[i], scaled_noise);
- noise_pwr += pow(scaled_noise.real, 2.0) + pow(scaled_noise.imag, 2.0);
+ /* FIR filter to simulate (a rather flat) SSB filter. We
+ filter the complex signal by shifting it down to DC and
+ using real coefficients. */
+
+ for (i = 0, j = SSBFILT_N; i < BUF_N; i++, j++) {
+ if (ssbfilt_en) {
+ ssbfiltbuf[j] = cmult(ch_fdm[i], cconj(lo_phase));
+ ssbfiltout[i].real = 0.0;
+ ssbfiltout[i].imag = 0.0;
+ for (k = 0; k < SSBFILT_N; k++) {
+ ssbfiltout[i].real += ssbfiltbuf[j - k].real * ssbfilt_coeff[k];
+ ssbfiltout[i].imag += ssbfiltbuf[j - k].imag * ssbfilt_coeff[k];
}
+ ssbfiltout[i] = cmult(ssbfiltout[i], lo_phase);
+ lo_phase = cmult(lo_phase, lo_freq);
+ } else {
+ ssbfiltout[i] = ch_fdm[i];
+ }
+ }
- /* FIR filter to simulate (a rather flat) SSB filter. We
- filter the complex signal by shifting it down to DC and
- using real coefficients. */
-
- for(i=0, j=SSBFILT_N; i<BUF_N; i++,j++) {
- if (ssbfilt_en) {
- ssbfiltbuf[j] = cmult(ch_fdm[i], cconj(lo_phase));
- ssbfiltout[i].real = 0.0; ssbfiltout[i].imag = 0.0;
- for(k=0; k<SSBFILT_N; k++) {
- ssbfiltout[i].real += ssbfiltbuf[j-k].real*ssbfilt_coeff[k];
- ssbfiltout[i].imag += ssbfiltbuf[j-k].imag*ssbfilt_coeff[k];
- }
- ssbfiltout[i] = cmult(ssbfiltout[i], lo_phase);
- lo_phase = cmult(lo_phase, lo_freq);
- }
- else {
- ssbfiltout[i] = ch_fdm[i];
- }
+ /* update SSB filter memory */
+ for (i = 0; i < SSBFILT_N; i++) ssbfiltbuf[i] = ssbfiltbuf[i + BUF_N];
+
+ int nout = (complex_out + 1) * BUF_N;
+ short bufout[nout], *pout = bufout;
+ for (i = 0; i < BUF_N; i++) {
+ sam = ssbfiltout[i].real;
+ if (sam > 32767.0) {
+ noutclipped++;
+ sam = 32767.0;
+ }
+ if (sam < -32767.0) {
+ noutclipped++;
+ sam = -32767.0;
+ }
+ *pout++ = sam;
+ if (complex_out) {
+ sam = ssbfiltout[i].imag;
+ if (sam > 32767.0) {
+ noutclipped++;
+ sam = 32767.0;
}
-
- /* update SSB filter memory */
- for(i=0; i<SSBFILT_N; i++)
- ssbfiltbuf[i] = ssbfiltbuf[i+BUF_N];
-
- int nout = (complex_out+1)*BUF_N;
- short bufout[nout], *pout=bufout;
- for(i=0; i<BUF_N; i++) {
- sam = ssbfiltout[i].real;
- if (sam > 32767.0) { noutclipped++; sam = 32767.0; }
- if (sam < -32767.0) { noutclipped++; sam = -32767.0; }
- *pout++ = sam;
- if (complex_out) {
- sam = ssbfiltout[i].imag;
- if (sam > 32767.0) { noutclipped++; sam = 32767.0; }
- if (sam < -32767.0) { noutclipped++; sam = -32767.0; }
- *pout++ = sam;
- }
+ if (sam < -32767.0) {
+ noutclipped++;
+ sam = -32767.0;
}
-
- fwrite(bufout, sizeof(short), nout, fout);
-
- /* if this is in a pipeline, we probably don't want the usual
- buffering to occur */
-
- if (fout == stdout) fflush(stdout);
+ *pout++ = sam;
+ }
}
- fclose(fin);
- fclose(fout);
-
- int nsamples = frames*BUF_N;
- papr = 10*log10(peak*peak/(tx_pwr/nsamples));
- CNo = 10*log10(tx_pwr/(noise_pwr/(Fs)));
- snr3k = CNo - 10*log10(3000);
- float outclipped_percent = noutclipped*100.0/nsamples;
- fprintf(stderr, "ch: SNR3k(dB): %8.2f C/No....: %8.2f\n", snr3k, CNo);
- fprintf(stderr, "ch: peak.....: %8.2f RMS.....: %8.2f CPAPR.....: %5.2f \n", peak, sqrt(tx_pwr/nsamples), papr);
- fprintf(stderr, "ch: Nsamples.: %8d clipped.: %8.2f%% OutClipped: %5.2f%%\n",
- nsamples, nclipped*100.0/nsamples, outclipped_percent);
- if (outclipped_percent > 0.1) fprintf(stderr, "ch: WARNING output clipping\n");
-
- if (ffading != NULL) fclose(ffading);
- if (ch_fdm_delay != NULL) FREE(ch_fdm_delay);
- if (ctest) {
- /* special ctest mode: check CPAPR is around 0dB */
- if (fabs(papr) < 0.7) return 0; else return 1;
- }
- else return 0;
+ fwrite(bufout, sizeof(short), nout, fout);
+
+ /* if this is in a pipeline, we probably don't want the usual
+ buffering to occur */
+
+ if (fout == stdout) fflush(stdout);
+ }
+
+ fclose(fin);
+ fclose(fout);
+
+ int nsamples = frames * BUF_N;
+ papr = 10 * log10(peak * peak / (tx_pwr / nsamples));
+ CNo = 10 * log10(tx_pwr / (noise_pwr / (Fs)));
+ snr3k = CNo - 10 * log10(3000);
+ float outclipped_percent = noutclipped * 100.0 / nsamples;
+ fprintf(stderr, "ch: SNR3k(dB): %8.2f C/No....: %8.2f\n", snr3k, CNo);
+ fprintf(stderr,
+ "ch: peak.....: %8.2f RMS.....: %8.2f CPAPR.....: %5.2f \n", peak,
+ sqrt(tx_pwr / nsamples), papr);
+ fprintf(stderr,
+ "ch: Nsamples.: %8d clipped.: %8.2f%% OutClipped: %5.2f%%\n",
+ nsamples, nclipped * 100.0 / nsamples, outclipped_percent);
+ if (outclipped_percent > 0.1)
+ fprintf(stderr, "ch: WARNING output clipping\n");
+
+ if (ffading != NULL) fclose(ffading);
+ if (ch_fdm_delay != NULL) FREE(ch_fdm_delay);
+ if (ctest) {
+ /* special ctest mode: check CPAPR is around 0dB */
+ if (fabs(papr) < 0.7)
+ return 0;
+ else
+ return 1;
+ } else
+ return 0;
}