From: drowe67 Date: Mon, 15 Jun 2015 05:07:50 +0000 (+0000) Subject: moved around the spectrum plotting functions a few times X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=9611e28188168e6d16c05b122a6c19bbe2e0469f;p=freetel-svn-tracking.git moved around the spectrum plotting functions a few times git-svn-id: https://svn.code.sf.net/p/freetel/code@2189 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/codec2-dev/src/CMakeLists.txt b/codec2-dev/src/CMakeLists.txt index 981c4116..18a4ce71 100644 --- a/codec2-dev/src/CMakeLists.txt +++ b/codec2-dev/src/CMakeLists.txt @@ -204,6 +204,7 @@ set(CODEC2_SRCS golay23.c freedv_api.c varicode.c + modem_stats.c ) set(CODEC2_PUBLIC_HEADERS @@ -245,7 +246,7 @@ target_link_libraries(fdmdv_get_test_bits ${CMAKE_REQUIRED_LIBRARIES}) add_executable(fdmdv_mod fdmdv_mod.c fdmdv.c kiss_fft.c) target_link_libraries(fdmdv_mod ${CMAKE_REQUIRED_LIBRARIES}) -add_executable(fdmdv_demod fdmdv_demod.c fdmdv.c kiss_fft.c octave.c) +add_executable(fdmdv_demod fdmdv_demod.c fdmdv.c kiss_fft.c octave.c modem_stats.c) target_link_libraries(fdmdv_demod ${CMAKE_REQUIRED_LIBRARIES}) add_executable(fdmdv_put_test_bits fdmdv_put_test_bits.c fdmdv.c kiss_fft.c) diff --git a/codec2-dev/src/codec2_cohpsk.h b/codec2-dev/src/codec2_cohpsk.h index 273a2c91..8e242750 100644 --- a/codec2-dev/src/codec2_cohpsk.h +++ b/codec2-dev/src/codec2_cohpsk.h @@ -38,6 +38,7 @@ oversampling rate */ #include "comp.h" +#include "modem_stats.h" struct COHPSK; @@ -46,5 +47,6 @@ void cohpsk_destroy(struct COHPSK *coh); void cohpsk_mod(struct COHPSK *cohpsk, COMP tx_fdm[], int tx_bits[]); void cohpsk_clip(COMP tx_fdm[]); void cohpsk_demod(struct COHPSK *cohpsk, float rx_bits[], int *reliable_sync_bit, COMP rx_fdm[], int *nin_frame); +void cohpsk_get_demod_stats(struct COHPSK *cohpsk, struct MODEM_STATS *stats); #endif diff --git a/codec2-dev/src/codec2_fdmdv.h b/codec2-dev/src/codec2_fdmdv.h index df1d3725..e440c1df 100644 --- a/codec2-dev/src/codec2_fdmdv.h +++ b/codec2-dev/src/codec2_fdmdv.h @@ -56,6 +56,7 @@ extern "C" { #endif #include "comp.h" +#include "modem_stats.h" #define FDMDV_NC 14 /* default number of data carriers */ #define FDMDV_NC_MAX 20 /* maximum number of data carriers */ @@ -72,25 +73,10 @@ extern "C" { #define FDMDV_OS_TAPS_16K 48 /* number of OS filter taps at 16kHz */ #define FDMDV_OS_TAPS_8K (FDMDV_OS_TAPS_16K/FDMDV_OS) /* number of OS filter taps at 8kHz */ -/* FFT points */ - -#define FDMDV_NSPEC 512 -#define FDMDV_MAX_F_HZ 4000 - /* FDMDV states and stats structures */ struct FDMDV; -struct FDMDV_STATS { - int Nc; - float snr_est; /* estimated SNR of rx signal in dB (3 kHz noise BW) */ - COMP rx_symbols[FDMDV_NC_MAX+1]; /* latest received symbols, for scatter plot */ - int sync; /* demod sync state */ - float foff; /* estimated freq offset in Hz */ - float rx_timing; /* estimated optimum timing offset in samples */ - float clock_offset; /* Estimated tx/rx sample clock offset in ppm */ -}; - struct FDMDV * fdmdv_create(int Nc); void fdmdv_destroy(struct FDMDV *fdmdv_state); void fdmdv_use_old_qpsk_mapping(struct FDMDV *fdmdv_state); @@ -105,8 +91,7 @@ void fdmdv_get_test_bits(struct FDMDV *fdmdv_state, int tx_bits[]); int fdmdv_error_pattern_size(struct FDMDV *fdmdv_state); void fdmdv_put_test_bits(struct FDMDV *f, int *sync, short error_pattern[], int *bit_errors, int *ntest_bits, int rx_bits[]); -void fdmdv_get_demod_stats(struct FDMDV *fdmdv_state, struct FDMDV_STATS *fdmdv_stats); -void fdmdv_get_rx_spectrum(struct FDMDV *fdmdv_state, float mag_dB[], COMP rx_fdm[], int nin); +void fdmdv_get_demod_stats(struct FDMDV *fdmdv_state, struct MODEM_STATS *stats); void fdmdv_8_to_16(float out16k[], float in8k[], int n); void fdmdv_8_to_16_short(short out16k[], short in8k[], int n); diff --git a/codec2-dev/src/cohpsk.c b/codec2-dev/src/cohpsk.c index 677d4f72..0c15013a 100644 --- a/codec2-dev/src/cohpsk.c +++ b/codec2-dev/src/cohpsk.c @@ -324,7 +324,7 @@ void qpsk_symbols_to_bits(struct COHPSK *coh, float rx_bits[], COMP ct_symb_buf[ } } - /* and finally optional diversity combination, note output is soft decm a "1" is < 0 */ + /* and finally optional diversity combination, note output is soft decn a "1" is < 0 */ for(c=0; cNc = COHPSK_NC*ND; + assert(stats->Nc <= MODEM_STATS_NC_MAX); + stats->snr_est = 20*log10(coh->sig_rms/coh->noise_rms); + stats->sync = coh->sync; + stats->foff = coh->f_est; + stats->rx_timing = coh->rx_timing; + stats->clock_offset = 0.0; /* TODO - implement clock offset estimation */ + + assert(stats->nr <= MODEM_STATS_NR_MAX); + stats->nr = NSYMROW; + for(c=0; crx_symbols[r][c] = coh->rx_symb[r][c]; + } + } +} diff --git a/codec2-dev/src/fdmdv.c b/codec2-dev/src/fdmdv.c index fa22dbf3..9feb6b77 100644 --- a/codec2-dev/src/fdmdv.c +++ b/codec2-dev/src/fdmdv.c @@ -182,11 +182,6 @@ struct FDMDV * fdmdv_create(int Nc) f->noise_est[c] = 0.0; } - for(i=0; i<2*FDMDV_NSPEC; i++) - f->fft_buf[i] = 0.0; - f->fft_cfg = kiss_fft_alloc (2*FDMDV_NSPEC, 0, NULL, NULL); - assert(f->fft_cfg != NULL); - f->sig_pwr_av = 0.0; return f; @@ -206,7 +201,6 @@ void fdmdv_destroy(struct FDMDV *fdmdv) { assert(fdmdv != NULL); KISS_FFT_FREE(fdmdv->fft_pilot_cfg); - KISS_FFT_FREE(fdmdv->fft_cfg); free(fdmdv->rx_test_bits_mem); free(fdmdv); } @@ -1611,19 +1605,22 @@ float calc_snr(int Nc, float sig_est[], float noise_est[]) \*---------------------------------------------------------------------------*/ -void fdmdv_get_demod_stats(struct FDMDV *fdmdv, struct FDMDV_STATS *fdmdv_stats) +void fdmdv_get_demod_stats(struct FDMDV *fdmdv, struct MODEM_STATS *stats) { int c; - fdmdv_stats->Nc = fdmdv->Nc; - fdmdv_stats->snr_est = calc_snr(fdmdv->Nc, fdmdv->sig_est, fdmdv->noise_est); - fdmdv_stats->sync = fdmdv->sync; - fdmdv_stats->foff = fdmdv->foff; - fdmdv_stats->rx_timing = fdmdv->rx_timing; - fdmdv_stats->clock_offset = 0.0; /* TODO - implement clock offset estimation */ + assert(fdmdv->Nc <= MODEM_STATS_NC_MAX); + + stats->Nc = fdmdv->Nc; + stats->snr_est = calc_snr(fdmdv->Nc, fdmdv->sig_est, fdmdv->noise_est); + stats->sync = fdmdv->sync; + stats->foff = fdmdv->foff; + stats->rx_timing = fdmdv->rx_timing; + stats->clock_offset = 0.0; /* TODO - implement clock offset estimation */ + stats->nr = 1; for(c=0; cNc+1; c++) { - fdmdv_stats->rx_symbols[c] = fdmdv->phase_difference[c]; + stats->rx_symbols[0][c] = fdmdv->phase_difference[c]; } } @@ -1757,71 +1754,6 @@ void fdmdv_16_to_8_short(short out8k[], short in16k[], int n) in16k[i] = in16k[i + n*FDMDV_OS]; } -/*---------------------------------------------------------------------------*\ - - FUNCTION....: fdmdv_get_rx_spectrum() - AUTHOR......: David Rowe - DATE CREATED: 9 June 2012 - - Returns the FDMDV_NSPEC point magnitude spectrum of the rx signal in - dB. The spectral samples are scaled so that 0dB is the peak, a good - range for plotting is 0 to -40dB. - - Note only the real part of the complex input signal is used at - present. A complex variable is used for input for compatability - with the other rx signal procesing. - - Successive calls can be used to build up a waterfall or spectrogram - plot, by mapping the received levels to colours. - - The time-frequency resolution of the spectrum can be adjusted by varying - FDMDV_NSPEC. Note that a 2*FDMDV_NSPEC size FFT is reqd to get - FDMDV_NSPEC output points. FDMDV_NSPEC must be a power of 2. - - See octave/tget_spec.m for a demo real time spectral display using - Octave. This demo averages the output over time to get a smoother - display: - - av = 0.9*av + 0.1*mag_dB - -\*---------------------------------------------------------------------------*/ - -void fdmdv_get_rx_spectrum(struct FDMDV *f, float mag_spec_dB[], - COMP rx_fdm[], int nin) -{ - int i,j; - COMP fft_in[2*FDMDV_NSPEC]; - COMP fft_out[2*FDMDV_NSPEC]; - float full_scale_dB; - - /* update buffer of input samples */ - - for(i=0; i<2*FDMDV_NSPEC-nin; i++) - f->fft_buf[i] = f->fft_buf[i+nin]; - for(j=0; jfft_buf[i] = rx_fdm[j].real; - assert(i == 2*FDMDV_NSPEC); - - /* window and FFT */ - - for(i=0; i<2*FDMDV_NSPEC; i++) { - fft_in[i].real = f->fft_buf[i] * (0.5 - 0.5*cosf((float)i*2.0*PI/(2*FDMDV_NSPEC))); - fft_in[i].imag = 0.0; - } - - kiss_fft(f->fft_cfg, (kiss_fft_cpx *)fft_in, (kiss_fft_cpx *)fft_out); - - /* FFT scales up a signal of level 1 FDMDV_NSPEC */ - - full_scale_dB = 20*log10(FDMDV_NSPEC); - - /* scale and convert to dB */ - - for(i=0; ifreedv_put_next_rx_char = NULL; f->total_bit_errors = 0; - + return f; } @@ -453,9 +453,11 @@ int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) { nin_prev = f->nin; fdmdv_demod(f->fdmdv, f->fdmdv_bits, &reliable_sync_bit, demod_in, &f->nin); - fdmdv_get_demod_stats(f->fdmdv, &f->fdmdv_stats); + fdmdv_get_demod_stats(f->fdmdv, &f->stats); + f->reliable_sync_bit = reliable_sync_bit; + f->snr_est = f->stats.snr_est; - if (f->fdmdv_stats.sync) { + if (f->stats.sync) { if (reliable_sync_bit == 0) { memcpy(f->rx_bits, f->fdmdv_bits, bits_per_fdmdv_frame*sizeof(int)); nout = 0; @@ -526,7 +528,7 @@ int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) { /* squelch if beneath SNR threshold */ - if (f->fdmdv_stats.snr_est < f->snr_thresh) { + if (f->stats.snr_est < f->snr_thresh) { for(i=0; in_speech_samples; i++) speech_out[i] = 0; } @@ -550,6 +552,9 @@ int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) { nin_prev = f->nin; cohpsk_demod(f->cohpsk, rx_bits, &reliable_sync_bit, demod_in, &f->nin); + f->reliable_sync_bit = reliable_sync_bit; + f->snr_est = 2.0; + fprintf(stderr, "%d\n", reliable_sync_bit); if (reliable_sync_bit) { @@ -587,11 +592,21 @@ int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) { nout = f->n_speech_samples; } else { + float t,a,b,s; + int t1,t2; + /* if not in sync pass through analog samples */ /* this lets us "hear" whats going on, e.g. during tuning */ - for(i=0; in_speech_samples; i++, t+=f->modem_sample_rate/FS) { + t1 = floor(t); t2 = ceil(t); + a = t - t1; + b = t2 - t1; + s = b*demod_in[t1].real + a*demod_in[t2].real; + speech_out[i] = FDMDV_SCALE*s; + } + nout = f->n_speech_samples; } } diff --git a/codec2-dev/src/freedv_api.h b/codec2-dev/src/freedv_api.h index 1382dcfc..bf4003b4 100644 --- a/codec2-dev/src/freedv_api.h +++ b/codec2-dev/src/freedv_api.h @@ -46,14 +46,14 @@ struct freedv { struct CODEC2 *codec2; struct FDMDV *fdmdv; - struct FDMDV_STATS fdmdv_stats; + struct MODEM_STATS stats; struct COHPSK *cohpsk; int n_speech_samples; int n_nom_modem_samples; // size of tx and most rx modenm sample buffers int n_max_modem_samples; // make your rx modem sample buffers this big - int modem_sample_rate; // caller is responsible for meeting this + int modem_sample_rate; // ATM caller is responsible for meeting this (TBC) int clip; // non-zero for cohpsk modem output clipping for low PAPR unsigned char *packed_codec_bits; @@ -64,6 +64,8 @@ struct freedv { int tx_sync_bit; int total_bit_errors; + int reliable_sync_bit; + float snr_est; float snr_thresh; int nin; diff --git a/codec2-dev/src/freedv_rx.c b/codec2-dev/src/freedv_rx.c index 740a33e8..eb1d8d91 100644 --- a/codec2-dev/src/freedv_rx.c +++ b/codec2-dev/src/freedv_rx.c @@ -121,7 +121,7 @@ int main(int argc, char *argv[]) { frame++; if (ftxt != NULL) { fprintf(ftxt, "frame: %d demod sync: %d demod snr: %3.2f dB bit errors: %d\n", frame, - freedv->fdmdv_stats.sync, freedv->fdmdv_stats.snr_est, freedv->total_bit_errors); + freedv->stats.sync, freedv->stats.snr_est, freedv->total_bit_errors); } /* if this is in a pipeline, we probably don't want the usual diff --git a/codec2-dev/src/modem_stats.c b/codec2-dev/src/modem_stats.c new file mode 100644 index 00000000..d13b1a02 --- /dev/null +++ b/codec2-dev/src/modem_stats.c @@ -0,0 +1,111 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: modem_stats.c + AUTHOR......: David Rowe + DATE CREATED: June 2015 + + Common functions for returning demod stats from fdmdv and cohpsk modems. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2015 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +#include +#include +#include "modem_stats.h" +#include "codec2_fdmdv.h" + +void modem_stats_open(struct MODEM_STATS *f) +{ + int i; + + for(i=0; i<2*MODEM_STATS_NSPEC; i++) + f->fft_buf[i] = 0.0; + f->fft_cfg = kiss_fft_alloc (2*MODEM_STATS_NSPEC, 0, NULL, NULL); + assert(f->fft_cfg != NULL); +} + +void modem_stats_close(struct MODEM_STATS *f) +{ + KISS_FFT_FREE(f->fft_cfg); +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: modem_stats_get_rx_spectrum() + AUTHOR......: David Rowe + DATE CREATED: 9 June 2012 + + Returns the MODEM_STATS_NSPEC point magnitude spectrum of the rx signal in + dB. The spectral samples are scaled so that 0dB is the peak, a good + range for plotting is 0 to -40dB. + + Note only the real part of the complex input signal is used at + present. A complex variable is used for input for compatability + with the other rx signal procesing. + + Successive calls can be used to build up a waterfall or spectrogram + plot, by mapping the received levels to colours. + + The time-frequency resolution of the spectrum can be adjusted by varying + MODEM_STATS_NSPEC. Note that a 2* MODEM_STATS_NSPEC size FFT is reqd to get + MODEM_STATS_NSPEC output points. MODEM_STATS_NSPEC must be a power of 2. + + See octave/tget_spec.m for a demo real time spectral display using + Octave. This demo averages the output over time to get a smoother + display: + + av = 0.9*av + 0.1*mag_dB + +\*---------------------------------------------------------------------------*/ + +void modem_stats_get_rx_spectrum(struct MODEM_STATS *f, float mag_spec_dB[], COMP rx_fdm[], int nin) +{ + int i,j; + COMP fft_in[2*MODEM_STATS_NSPEC]; + COMP fft_out[2*MODEM_STATS_NSPEC]; + float full_scale_dB; + + /* update buffer of input samples */ + + for(i=0; i<2*MODEM_STATS_NSPEC-nin; i++) + f->fft_buf[i] = f->fft_buf[i+nin]; + for(j=0; jfft_buf[i] = rx_fdm[j].real; + assert(i == 2*MODEM_STATS_NSPEC); + + /* window and FFT */ + + for(i=0; i<2*MODEM_STATS_NSPEC; i++) { + fft_in[i].real = f->fft_buf[i] * (0.5 - 0.5*cosf((float)i*2.0*M_PI/(2*MODEM_STATS_NSPEC))); + fft_in[i].imag = 0.0; + } + + kiss_fft(f->fft_cfg, (kiss_fft_cpx *)fft_in, (kiss_fft_cpx *)fft_out); + + /* FFT scales up a signal of level 1 FDMDV_NSPEC */ + + full_scale_dB = 20*log10(MODEM_STATS_NSPEC*FDMDV_SCALE); + + /* scale and convert to dB */ + + for(i=0; i. +*/ + +#ifdef __cplusplus + extern "C" { +#endif + +#ifndef __MODEM_STATS__ +#define __MODEM_STATS__ + +#include "comp.h" +#include "kiss_fft.h" + +#define MODEM_STATS_NC_MAX 20 +#define MODEM_STATS_NR_MAX 6 +#define MODEM_STATS_NSPEC 512 +#define MODEM_STATS_MAX_F_HZ 4000 + +struct MODEM_STATS { + int Nc; + float snr_est; /* estimated SNR of rx signal in dB (3 kHz noise BW) */ + COMP rx_symbols[MODEM_STATS_NR_MAX][MODEM_STATS_NC_MAX+1]; + /* latest received symbols, for scatter plot */ + int nr; /* number of rows in rx_symbols */ + int sync; /* demod sync state */ + float foff; /* estimated freq offset in Hz */ + float rx_timing; /* estimated optimum timing offset in samples */ + float clock_offset; /* Estimated tx/rx sample clock offset in ppm */ + + /* Buf for FFT/waterfall */ + + float fft_buf[2*MODEM_STATS_NSPEC]; + kiss_fft_cfg fft_cfg; +}; + +void modem_stats_open(struct MODEM_STATS *f); +void modem_stats_close(struct MODEM_STATS *f); +void modem_stats_get_rx_spectrum(struct MODEM_STATS *f, float mag_spec_dB[], COMP rx_fdm[], int nin); + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/codec2-dev/unittest/fdmdv_mem.c b/codec2-dev/unittest/fdmdv_mem.c index 06a0ca0f..ad105e83 100644 --- a/codec2-dev/unittest/fdmdv_mem.c +++ b/codec2-dev/unittest/fdmdv_mem.c @@ -40,25 +40,23 @@ int main(int argc, char *argv[]) { struct FDMDV *fdmdv; - printf("struct FDMDV..........: %d\n", sizeof(struct FDMDV)); - printf("prev_tx_symbols.......: %d\n", sizeof(fdmdv->prev_tx_symbols)); - printf("tx_filter_memory......: %d\n", sizeof(fdmdv->tx_filter_memory)); - printf("phase_tx..............: %d\n", sizeof(fdmdv->phase_tx)); - printf("freq..................: %d\n", sizeof(fdmdv->freq)); - printf("pilot_lut.............: %d\n", sizeof(fdmdv->pilot_lut)); - printf("pilot_baseband1.......: %d\n", sizeof(fdmdv->pilot_baseband1)); - printf("pilot_baseband2.......: %d\n", sizeof(fdmdv->pilot_baseband2)); - printf("pilot_lpf1............: %d\n", sizeof(fdmdv->pilot_lpf1)); - printf("pilot_lpf2............: %d\n", sizeof(fdmdv->pilot_lpf2)); - printf("S1....................: %d\n", sizeof(fdmdv->S1)); - printf("S2....................: %d\n", sizeof(fdmdv->S2)); - printf("phase_rx..............: %d\n", sizeof(fdmdv->phase_rx)); - printf("rx_fdm_mem............: %d\n", sizeof(fdmdv->rx_fdm_mem)); - printf("rx_filter_mem_timing..: %d\n", sizeof(fdmdv->rx_filter_mem_timing)); - printf("phase_difference......: %d\n", sizeof(fdmdv->phase_difference)); - printf("prev_rx_symbols.......: %d\n", sizeof(fdmdv->prev_rx_symbols)); - printf("fft_buf...............: %d\n", sizeof(fdmdv->fft_buf)); - printf("kiss_fft_cfg..........: %d\n", sizeof(fdmdv->fft_cfg)); + printf("struct FDMDV..........: %ld\n", sizeof(struct FDMDV)); + printf("prev_tx_symbols.......: %ld\n", sizeof(fdmdv->prev_tx_symbols)); + printf("tx_filter_memory......: %ld\n", sizeof(fdmdv->tx_filter_memory)); + printf("phase_tx..............: %ld\n", sizeof(fdmdv->phase_tx)); + printf("freq..................: %ld\n", sizeof(fdmdv->freq)); + printf("pilot_lut.............: %ld\n", sizeof(fdmdv->pilot_lut)); + printf("pilot_baseband1.......: %ld\n", sizeof(fdmdv->pilot_baseband1)); + printf("pilot_baseband2.......: %ld\n", sizeof(fdmdv->pilot_baseband2)); + printf("pilot_lpf1............: %ld\n", sizeof(fdmdv->pilot_lpf1)); + printf("pilot_lpf2............: %ld\n", sizeof(fdmdv->pilot_lpf2)); + printf("S1....................: %ld\n", sizeof(fdmdv->S1)); + printf("S2....................: %ld\n", sizeof(fdmdv->S2)); + printf("phase_rx..............: %ld\n", sizeof(fdmdv->phase_rx)); + printf("rx_fdm_mem............: %ld\n", sizeof(fdmdv->rx_fdm_mem)); + printf("rx_filter_mem_timing..: %ld\n", sizeof(fdmdv->rx_filter_mem_timing)); + printf("phase_difference......: %ld\n", sizeof(fdmdv->phase_difference)); + printf("prev_rx_symbols.......: %ld\n", sizeof(fdmdv->prev_rx_symbols)); return 0; }