From: wittend99 Date: Sun, 27 May 2012 02:53:08 +0000 (+0000) Subject: fdmdv2dll builds, as yet untested though. X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=724b65f26ac7306a2569069ff96227086388d52f;p=freetel-svn-tracking.git fdmdv2dll builds, as yet untested though. git-svn-id: https://svn.code.sf.net/p/freetel/code@501 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/fdmdv2/fdmdv2dll/Release/.gitignore b/fdmdv2/fdmdv2dll/Release/.gitignore deleted file mode 100644 index e69de29b..00000000 diff --git a/fdmdv2/fdmdv2dll/Release/fdmdv2-dll.dll b/fdmdv2/fdmdv2dll/Release/fdmdv2-dll.dll new file mode 100644 index 00000000..3152c2fd Binary files /dev/null and b/fdmdv2/fdmdv2dll/Release/fdmdv2-dll.dll differ diff --git a/fdmdv2/fdmdv2dll/Release/fdmdv2-dll.lib b/fdmdv2/fdmdv2dll/Release/fdmdv2-dll.lib new file mode 100644 index 00000000..16e9c48d Binary files /dev/null and b/fdmdv2/fdmdv2dll/Release/fdmdv2-dll.lib differ diff --git a/fdmdv2/fdmdv2dll/fdmdv2-dll.cpp b/fdmdv2/fdmdv2dll/fdmdv2-dll.cpp index 8f9469f2..0d1f8b8e 100644 --- a/fdmdv2/fdmdv2dll/fdmdv2-dll.cpp +++ b/fdmdv2/fdmdv2dll/fdmdv2-dll.cpp @@ -1,1390 +1,1406 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: codec2-dll.cpp - AUTHOR......: David Witten - DATE CREATED: 21 May 2011 - - Wrapper for the Codec2 codec and fdmdv modem APIs. - -\*---------------------------------------------------------------------------*/ - -/* - 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 "stdafx.h" -#include "fdmdv2-dll.h" - - -// This is an example of an exported variable -WIN32PROJECT_API int nwin32project=0; - -// This is an example of an exported function. -WIN32PROJECT_API int fnwin32project(void) -{ - return 42; -} - -// This is the constructor of a class that has been exported. -// see win32-project.h for the class definition -Cwin32project::Cwin32project() -{ - return; -} - - -/*---------------------------------------------------------------------------*\ - - FILE........: fdmdv.c - AUTHOR......: David Rowe - DATE CREATED: April 14 2012 - - Functions that implement the FDMDV modem. - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2012 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 . -*/ - -/*---------------------------------------------------------------------------*\ - - INCLUDES - -\*---------------------------------------------------------------------------*/ - -#include -#include -#include -#include -#include - -#include "fdmdv_internal.h" -#include "fdmdv.h" -#include "rn.h" -#include "test_bits.h" -#include "pilot_coeff.h" -#include "fft.h" -#include "hanning.h" -#include "os.h" - -/*---------------------------------------------------------------------------*\ - - FUNCTIONS - -\*---------------------------------------------------------------------------*/ - -static COMP cneg(COMP a) -{ - COMP res; - - res.real = -a.real; - res.imag = -a.imag; - - return res; -} - -static COMP cconj(COMP a) -{ - COMP res; - - res.real = a.real; - res.imag = -a.imag; - - return res; -} - -static COMP cmult(COMP a, COMP b) -{ - COMP res; - - res.real = a.real*b.real - a.imag*b.imag; - res.imag = a.real*b.imag + a.imag*b.real; - - return res; -} - -static COMP fcmult(float a, COMP b) -{ - COMP res; - - res.real = a*b.real; - res.imag = a*b.imag; - - return res; -} - -static COMP cadd(COMP a, COMP b) -{ - COMP res; - - res.real = a.real + b.real; - res.imag = a.imag + b.imag; - - return res; -} - -static float cabsolute(COMP a) -{ - return sqrt(pow(a.real, 2.0) + pow(a.imag, 2.0)); -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: fdmdv_create - AUTHOR......: David Rowe - DATE CREATED: 16/4/2012 - - Create and initialise an instance of the modem. Returns a pointer - to the modem states or NULL on failure. One set of states is - sufficient for a full duplex modem. - -\*---------------------------------------------------------------------------*/ - -WIN32PROJECT_API struct FDMDV *fdmdv_create(void) -{ - struct FDMDV *f; - int c, i, k; - float carrier_freq; - - assert(FDMDV_BITS_PER_FRAME == NC*NB); - assert(FDMDV_NOM_SAMPLES_PER_FRAME == M); - assert(FDMDV_MAX_SAMPLES_PER_FRAME == (M+M/P)); - - f = (struct FDMDV*)malloc(sizeof(struct FDMDV)); - if (f == NULL) - return NULL; - - f->current_test_bit = 0; - for(i=0; irx_test_bits_mem[i] = 0; - - f->tx_pilot_bit = 0; - - for(c=0; cprev_tx_symbols[c].real = 1.0; - f->prev_tx_symbols[c].imag = 0.0; - f->prev_rx_symbols[c].real = 1.0; - f->prev_rx_symbols[c].imag = 0.0; - - for(k=0; ktx_filter_memory[c][k].real = 0.0; - f->tx_filter_memory[c][k].imag = 0.0; - f->rx_filter_memory[c][k].real = 0.0; - f->rx_filter_memory[c][k].imag = 0.0; - } - - /* Spread initial FDM carrier phase out as far as possible. - This helped PAPR for a few dB. We don't need to adjust rx - phase as DQPSK takes care of that. */ - - f->phase_tx[c].real = cos(2.0*PI*c/(NC+1)); - f->phase_tx[c].imag = sin(2.0*PI*c/(NC+1)); - - f->phase_rx[c].real = 1.0; - f->phase_rx[c].imag = 0.0; - - for(k=0; krx_filter_mem_timing[c][k].real = 0.0; - f->rx_filter_mem_timing[c][k].imag = 0.0; - } - for(k=0; krx_baseband_mem_timing[c][k].real = 0.0; - f->rx_baseband_mem_timing[c][k].imag = 0.0; - } - } - - /* Set up frequency of each carrier */ - - for(c=0; cfreq[c].real = cos(2.0*PI*carrier_freq/FS); - f->freq[c].imag = sin(2.0*PI*carrier_freq/FS); - } - - for(c=NC/2; cfreq[c].real = cos(2.0*PI*carrier_freq/FS); - f->freq[c].imag = sin(2.0*PI*carrier_freq/FS); - } - - f->freq[NC].real = cos(2.0*PI*FCENTRE/FS); - f->freq[NC].imag = sin(2.0*PI*FCENTRE/FS); - - /* Generate DBPSK pilot Look Up Table (LUT) */ - - generate_pilot_lut(f->pilot_lut, &f->freq[NC]); - - /* freq Offset estimation states */ - - for(i=0; ipilot_baseband1[i].real = f->pilot_baseband2[i].real = 0.0; - f->pilot_baseband1[i].imag = f->pilot_baseband2[i].imag = 0.0; - } - f->pilot_lut_index = 0; - f->prev_pilot_lut_index = 3*M; - - for(i=0; ipilot_lpf1[i].real = f->pilot_lpf2[i].real = 0.0; - f->pilot_lpf1[i].imag = f->pilot_lpf2[i].imag = 0.0; - } - - f->foff = 0.0; - f->foff_rect.real = 1.0; - f->foff_rect.imag = 0.0; - f->foff_phase_rect.real = 1.0; - f->foff_phase_rect.imag = 0.0; - - f->fest_state = 0; - f->coarse_fine = COARSE; - - for(c=0; csig_est[c] = 0.0; - f->noise_est[c] = 0.0; - } - - return f; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: fdmdv_destroy - AUTHOR......: David Rowe - DATE CREATED: 16/4/2012 - - Destroy an instance of the modem. - -\*---------------------------------------------------------------------------*/ - -WIN32PROJECT_API void fdmdv_destroy(struct FDMDV *fdmdv) -{ - assert(fdmdv != NULL); - free(fdmdv); -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: fdmdv_get_test_bits() - AUTHOR......: David Rowe - DATE CREATED: 16/4/2012 - - Generate a frame of bits from a repeating sequence of random data. OK so - it's not very random if it repeats but it makes syncing at the demod easier - for test purposes. - -\*---------------------------------------------------------------------------*/ - -WIN32PROJECT_API void fdmdv_get_test_bits(struct FDMDV *f, int tx_bits[]) -{ - int i; - - for(i=0; icurrent_test_bit]; - f->current_test_bit++; - if (f->current_test_bit > (NTEST_BITS-1)) - f->current_test_bit = 0; - } - } - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: bits_to_dqpsk_symbols() - AUTHOR......: David Rowe - DATE CREATED: 16/4/2012 - - Maps bits to parallel DQPSK symbols. Generate Nc+1 QPSK symbols from - vector of (1,Nc*Nb) input tx_bits. The Nc+1 symbol is the +1 -1 +1 - .... BPSK sync carrier. - -\*---------------------------------------------------------------------------*/ - -void bits_to_dqpsk_symbols(COMP tx_symbols[], COMP prev_tx_symbols[], int tx_bits[], int *pilot_bit) -{ - int c, msb, lsb; - COMP j = {0.0,1.0}; - - /* map tx_bits to to Nc DQPSK symbols */ - - for(c=0; cprev_tx_symbols, tx_bits, &fdmdv->tx_pilot_bit); - memcpy(fdmdv->prev_tx_symbols, tx_symbols, sizeof(COMP)*(NC+1)); - tx_filter(tx_baseband, tx_symbols, fdmdv->tx_filter_memory); - fdm_upconvert(tx_fdm, tx_baseband, fdmdv->phase_tx, fdmdv->freq); - - *sync_bit = fdmdv->tx_pilot_bit; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: generate_pilot_fdm() - AUTHOR......: David Rowe - DATE CREATED: 19/4/2012 - - Generate M samples of DBPSK pilot signal for Freq offset estimation. - -\*---------------------------------------------------------------------------*/ - -void generate_pilot_fdm(COMP *pilot_fdm, int *bit, float *symbol, float *filter_mem, COMP *phase, COMP *freq) -{ - int i,j,k; - float tx_baseband[M]; - - /* +1 -1 +1 -1 DBPSK sync carrier, once filtered becomes (roughly) - two spectral lines at +/- RS/2 */ - - if (*bit) - *symbol = -*symbol; - else - *symbol = *symbol; - if (*bit) - *bit = 0; - else - *bit = 1; - - /* filter DPSK symbol to create M baseband samples */ - - filter_mem[NFILTER-1] = (sqrt(2)/2) * *symbol; - for(i=0; ireal; - pilot_fdm[i].imag = sqrt(2)*2*tx_baseband[i] * phase->imag; - } -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: generate_pilot_lut() - AUTHOR......: David Rowe - DATE CREATED: 19/4/2012 - - Generate a 4M sample vector of DBPSK pilot signal. As the pilot signal - is periodic in 4M samples we can then use this vector as a look up table - for pilot signal generation in the demod. - -\*---------------------------------------------------------------------------*/ - -void generate_pilot_lut(COMP pilot_lut[], COMP *pilot_freq) -{ - int pilot_rx_bit = 0; - float pilot_symbol = sqrt(2.0); - COMP pilot_phase = {1.0, 0.0}; - float pilot_filter_mem[NFILTER]; - COMP pilot[M]; - int i,f; - - for(i=0; i= 4) - memcpy(&pilot_lut[M*(f-4)], pilot, M*sizeof(COMP)); - } - -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: lpf_peak_pick() - AUTHOR......: David Rowe - DATE CREATED: 20/4/2012 - - LPF and peak pick part of freq est, put in a function as we call it twice. - -\*---------------------------------------------------------------------------*/ - -void lpf_peak_pick(float *foff, float *max, COMP pilot_baseband[], COMP pilot_lpf[], COMP S[], int nin) -{ - int i,j,k; - int mpilot; - float mag, imax; - int ix; - float r; - - /* LPF cutoff 200Hz, so we can handle max +/- 200 Hz freq offset */ - - for(i=0; i imax) { - imax = mag; - ix = i; - } - } - r = 2.0*200.0/MPILOTFFT; /* maps FFT bin to frequency in Hz */ - - if (ix >= MPILOTFFT/2) - *foff = (ix - MPILOTFFT)*r; - else - *foff = (ix)*r; - *max = imax; - -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: rx_est_freq_offset() - AUTHOR......: David Rowe - DATE CREATED: 19/4/2012 - - Estimate frequency offset of FDM signal using BPSK pilot. Note that - this algorithm is quite sensitive to pilot tone level wrt other - carriers, so test variations to the pilot amplitude carefully. - -\*---------------------------------------------------------------------------*/ - -float rx_est_freq_offset(struct FDMDV *f, float rx_fdm[], int nin) -{ - int i,j; - COMP pilot[M+M/P]; - COMP prev_pilot[M+M/P]; - float foff, foff1, foff2; - float max1, max2; - - assert(nin <= M+M/P); - - /* get pilot samples used for correlation/down conversion of rx signal */ - - for (i=0; ipilot_lut[f->pilot_lut_index]; - f->pilot_lut_index++; - if (f->pilot_lut_index >= 4*M) - f->pilot_lut_index = 0; - - prev_pilot[i] = f->pilot_lut[f->prev_pilot_lut_index]; - f->prev_pilot_lut_index++; - if (f->prev_pilot_lut_index >= 4*M) - f->prev_pilot_lut_index = 0; - } - - /* - Down convert latest M samples of pilot by multiplying by ideal - BPSK pilot signal we have generated locally. The peak of the - resulting signal is sensitive to the time shift between the - received and local version of the pilot, so we do it twice at - different time shifts and choose the maximum. - */ - - for(i=0; ipilot_baseband1[i] = f->pilot_baseband1[i+nin]; - f->pilot_baseband2[i] = f->pilot_baseband2[i+nin]; - } - - for(i=0,j=NPILOTBASEBAND-nin; ipilot_baseband1[j] = fcmult(rx_fdm[i], cconj(pilot[i])); - f->pilot_baseband2[j] = fcmult(rx_fdm[i], cconj(prev_pilot[i])); - } - - lpf_peak_pick(&foff1, &max1, f->pilot_baseband1, f->pilot_lpf1, f->S1, nin); - lpf_peak_pick(&foff2, &max2, f->pilot_baseband2, f->pilot_lpf2, f->S2, nin); - - if (max1 > max2) - foff = foff1; - else - foff = foff2; - - return foff; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: freq_shift() - AUTHOR......: David Rowe - DATE CREATED: 26/4/2012 - - Frequency shift modem signal. - -\*---------------------------------------------------------------------------*/ - -void freq_shift(COMP rx_fdm_fcorr[], float rx_fdm[], float foff, COMP *foff_rect, COMP *foff_phase_rect, int nin) -{ - int i; - - foff_rect->real = cos(2.0*PI*foff/FS); - foff_rect->imag = sin(2.0*PI*foff/FS); - for(i=0; i M) - rx_timing -= M; - if (rx_timing < -M) - rx_timing += M; - - /* rx_filt_mem_timing contains M + Nfilter + M samples of the - baseband signal at rate M this enables us to resample the - filtered rx symbol with M sample precision once we have - rx_timing */ - - for(c=0; c= 0) && (d.imag >= 0)) { - msb = 0; lsb = 0; - } - if ((d.real < 0) && (d.imag >= 0)) { - msb = 0; lsb = 1; - } - if ((d.real < 0) && (d.imag < 0)) { - msb = 1; lsb = 0; - } - if ((d.real >= 0) && (d.imag < 0)) { - msb = 1; lsb = 1; - } - rx_bits[2*c] = msb; - rx_bits[2*c+1] = lsb; - } - - /* Extract DBPSK encoded Sync bit and fine freq offset estimate */ - - phase_difference[NC] = cmult(rx_symbols[NC], cconj(prev_rx_symbols[NC])); - if (phase_difference[NC].real < 0) { - *sync_bit = 1; - ferr = phase_difference[NC].imag; - } - else { - *sync_bit = 0; - ferr = -phase_difference[NC].imag; - } - - /* pilot carrier gets an extra pi/4 rotation to make it consistent - with other carriers, as we need it for snr_update and scatter - diagram */ - - phase_difference[NC] = cmult(phase_difference[NC], pi_on_4); - - return ferr; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: snr_update() - AUTHOR......: David Rowe - DATE CREATED: 17 May 2012 - - Given phase differences update estimates of signal and noise levels. - -\*---------------------------------------------------------------------------*/ - -void snr_update(float sig_est[], float noise_est[], COMP phase_difference[]) -{ - float s[NC+1]; - COMP refl_symbols[NC+1]; - float n[NC+1]; - COMP pi_on_4; - int c; - - pi_on_4.real = cos(PI/4.0); - pi_on_4.imag = sin(PI/4.0); - - /* mag of each symbol is distance from origin, this gives us a - vector of mags, one for each carrier. */ - - for(c=0; crx_test_bits_mem[i] = f->rx_test_bits_mem[j]; - for(i=NTEST_BITS-FDMDV_BITS_PER_FRAME,j=0; irx_test_bits_mem[i] = rx_bits[j]; - - /* see how many bit errors we get when checked against test sequence */ - - *bit_errors = 0; - for(i=0; irx_test_bits_mem[i]; - //printf("%d %d %d %d\n", i, test_bits[i], f->rx_test_bits_mem[i], test_bits[i] ^ f->rx_test_bits_mem[i]); - } - - /* if less than a thresh we are aligned and in sync with test sequence */ - - ber = (float)*bit_errors/NTEST_BITS; - - *sync = 0; - if (ber < 0.2) - *sync = 1; - - *ntest_bits = NTEST_BITS; - -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: freq_state(() - AUTHOR......: David Rowe - DATE CREATED: 24/4/2012 - - Freq offset state machine. Moves between coarse and fine states - based on BPSK pilot sequence. Freq offset estimator occasionally - makes mistakes when used continuously. So we use it until we have - acquired the BPSK pilot, then switch to a more robust "fine" - tracking algorithm. If we lose sync we switch back to coarse mode - for fast-requisition of large frequency offsets. - -\*---------------------------------------------------------------------------*/ - -int freq_state(int sync_bit, int *state) -{ - int next_state, coarse_fine; - - /* acquire state, look for 6 symbol 010101 sequence from sync bit */ - - next_state = *state; - switch(*state) { - case 0: - if (sync_bit == 0) - next_state = 1; - break; - case 1: - if (sync_bit == 1) - next_state = 2; - else - next_state = 0; - break; - case 2: - if (sync_bit == 0) - next_state = 3; - else - next_state = 0; - break; - case 3: - if (sync_bit == 1) - next_state = 4; - else - next_state = 0; - break; - case 4: - if (sync_bit == 0) - next_state = 5; - else - next_state = 0; - break; - case 5: - if (sync_bit == 1) - next_state = 6; - else - next_state = 0; - break; - - /* states 6 and above are track mode, make sure we keep - getting 0101 sync bit sequence */ - - case 6: - if (sync_bit == 0) - next_state = 7; - else - next_state = 0; - - break; - case 7: - if (sync_bit == 1) - next_state = 6; - else - next_state = 0; - break; - } - - *state = next_state; - if (*state >= 6) - coarse_fine = FINE; - else - coarse_fine = COARSE; - - return coarse_fine; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: fdmdv_demod() - AUTHOR......: David Rowe - DATE CREATED: 26/4/2012 - - FDMDV demodulator, take an array of FDMDV_SAMPLES_PER_FRAME - modulated symbols, returns an array of FDMDV_BITS_PER_FRAME bits, - plus the sync bit. - - The number of input samples nin will normally be M == - FDMDV_SAMPLES_PER_FRAME. However to adjust for differences in - transmit and receive sample clocks nin will occasionally be M-M/P, - or M+M/P. - -\*---------------------------------------------------------------------------*/ - -WIN32PROJECT_API void fdmdv_demod(struct FDMDV *fdmdv, int rx_bits[], int *sync_bit, float rx_fdm[], int *nin) -{ - float foff_coarse, foff_fine; - COMP rx_fdm_fcorr[M+M/P]; - COMP rx_baseband[NC+1][M+M/P]; - COMP rx_filt[NC+1][P+1]; - COMP rx_symbols[NC+1]; - float env[NT*P]; - - /* freq offset estimation and correction */ - - foff_coarse = rx_est_freq_offset(fdmdv, rx_fdm, *nin); - - if (fdmdv->coarse_fine == COARSE) - fdmdv->foff = foff_coarse; - freq_shift(rx_fdm_fcorr, rx_fdm, fdmdv->foff, &fdmdv->foff_rect, &fdmdv->foff_phase_rect, *nin); - - /* baseband processing */ - - fdm_downconvert(rx_baseband, rx_fdm_fcorr, fdmdv->phase_rx, fdmdv->freq, *nin); - rx_filter(rx_filt, rx_baseband, fdmdv->rx_filter_memory, *nin); - fdmdv->rx_timing = rx_est_timing(rx_symbols, rx_filt, rx_baseband, fdmdv->rx_filter_mem_timing, env, fdmdv->rx_baseband_mem_timing, *nin); - - /* adjust number of input samples to keep timing within bounds */ - - *nin = M; - - if (fdmdv->rx_timing > 2*M/P) - *nin += M/P; - - if (fdmdv->rx_timing < 0) - *nin -= M/P; - - foff_fine = qpsk_to_bits(rx_bits, sync_bit, fdmdv->phase_difference, fdmdv->prev_rx_symbols, rx_symbols); - memcpy(fdmdv->prev_rx_symbols, rx_symbols, sizeof(COMP)*(NC+1)); - snr_update(fdmdv->sig_est, fdmdv->noise_est, fdmdv->phase_difference); - - /* freq offset estimation state machine */ - - fdmdv->coarse_fine = freq_state(*sync_bit, &fdmdv->fest_state); - fdmdv->foff -= TRACK_COEFF*foff_fine; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: calc_snr() - AUTHOR......: David Rowe - DATE CREATED: 17 May 2012 - - Calculate current SNR estimate (3000Hz noise BW) - -\*---------------------------------------------------------------------------*/ - -float calc_snr(float sig_est[], float noise_est[]) -{ - float S, SdB; - float mean, N50, N50dB, N3000dB; - float snr_dB; - int c; - - S = 0.0; - for(c=0; csnr_est = calc_snr(fdmdv->sig_est, fdmdv->noise_est); - fdmdv_stats->fest_coarse_fine = fdmdv->coarse_fine; - fdmdv_stats->foff = fdmdv->foff; - fdmdv_stats->rx_timing = fdmdv->rx_timing; - fdmdv_stats->clock_offset = 0.0; /* TODO - implement clock offset estimation */ - - assert((NC+1) == FDMDV_NSYM); - - for(c=0; crx_symbols[c] = fdmdv->phase_difference[c]; - } -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: fdmdv_8_to_48() - AUTHOR......: David Rowe - DATE CREATED: 9 May 2012 - - Changes the sample rate of a signal from 8 to 48 kHz. Experience - with PC based modems has shown that PC sound cards have a more - accurate sample clock when set for 48 kHz than 8 kHz. - - n is the number of samples at the 8 kHz rate, there are FDMDV_OS*n samples - at the 48 kHz rate. A memory of FDMDV_OS_TAPS/FDMDV_OS samples is reqd for - in8k[] (see t48_8.c unit test as example). - - This is a classic polyphase upsampler. We take the 8 kHz samples - and insert (FDMDV_OS-1) zeroes between each sample, then - FDMDV_OS_TAPS FIR low pass filter the signal at 4kHz. As most of - the input samples are zeroes, we only need to multiply non-zero - input samples by filter coefficients. The zero insertion and - filtering are combined in the code below and I'm too lazy to explain - it further right now.... - -\*---------------------------------------------------------------------------*/ - -WIN32PROJECT_API void fdmdv_8_to_48(float out48k[], float in8k[], int n) -{ - int i,j,k,l; - - for(i=0; i. +*/ +#define __USE_MATH_DEFINES + +#include "stdafx.h" +#include +#include +#include +#include +#include +#include + +#include "fdmdv_internal.h" +#include "fdmdv2-dll.h" +#include "rn.h" +#include "test_bits.h" +#include "pilot_coeff.h" +#include "fft.h" +#include "hanning.h" +#include "os.h" +/* +// This is an example of an exported variable +WIN32PROJECT_API int nwin32project=0; + +// This is an example of an exported function. +WIN32PROJECT_API int fnwin32project(void) +{ + return 42; +} + +// This is the constructor of a class that has been exported. +// see win32-project.h for the class definition +Cwin32project::Cwin32project() +{ + return; +} +*/ + +/*---------------------------------------------------------------------------*\ + +FILE........: fdmdv.c +AUTHOR......: David Rowe +DATE CREATED: April 14 2012 + +Functions that implement the FDMDV modem. + +\*---------------------------------------------------------------------------*/ + +/* +Copyright (C) 2012 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 . +*/ + +/*---------------------------------------------------------------------------*\ + +INCLUDES + +\*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*\ + +FUNCTIONS + +\*---------------------------------------------------------------------------*/ + + + +static inline double round(double val) +{ + return floor(val + 0.5); +} + + + +static COMP cneg(COMP a) +{ + COMP res; + + res.real = -a.real; + res.imag = -a.imag; + + return res; +} + +static COMP cconj(COMP a) +{ + COMP res; + + res.real = a.real; + res.imag = -a.imag; + + return res; +} + +static COMP cmult(COMP a, COMP b) +{ + COMP res; + + res.real = a.real*b.real - a.imag*b.imag; + res.imag = a.real*b.imag + a.imag*b.real; + + return res; +} + +static COMP fcmult(float a, COMP b) +{ + COMP res; + + res.real = a*b.real; + res.imag = a*b.imag; + + return res; +} + +static COMP cadd(COMP a, COMP b) +{ + COMP res; + + res.real = a.real + b.real; + res.imag = a.imag + b.imag; + + return res; +} + +static float cabsolute(COMP a) +{ + return sqrt((float)pow((float)a.real, (float)2.0) + (float)pow((float)a.imag, (float)2.0)); +} + +/*---------------------------------------------------------------------------*\ + +FUNCTION....: fdmdv_create +AUTHOR......: David Rowe +DATE CREATED: 16/4/2012 + +Create and initialise an instance of the modem. Returns a pointer +to the modem states or NULL on failure. One set of states is +sufficient for a full duplex modem. + +\*---------------------------------------------------------------------------*/ + +WIN32PROJECT_API struct FDMDV *fdmdv_create(void) +{ + struct FDMDV *f; + int c, i, k; + float carrier_freq; + + assert(FDMDV_BITS_PER_FRAME == NC*NB); + assert(FDMDV_NOM_SAMPLES_PER_FRAME == M); + assert(FDMDV_MAX_SAMPLES_PER_FRAME == (M+M/P)); + + f = (struct FDMDV*)malloc(sizeof(struct FDMDV)); + if (f == NULL) + return NULL; + + f->current_test_bit = 0; + for(i=0; irx_test_bits_mem[i] = 0; + + f->tx_pilot_bit = 0; + + for(c=0; cprev_tx_symbols[c].real = 1.0; + f->prev_tx_symbols[c].imag = 0.0; + f->prev_rx_symbols[c].real = 1.0; + f->prev_rx_symbols[c].imag = 0.0; + + for(k=0; ktx_filter_memory[c][k].real = 0.0; + f->tx_filter_memory[c][k].imag = 0.0; + f->rx_filter_memory[c][k].real = 0.0; + f->rx_filter_memory[c][k].imag = 0.0; + } + + /* Spread initial FDM carrier phase out as far as possible. + This helped PAPR for a few dB. We don't need to adjust rx + phase as DQPSK takes care of that. */ + + f->phase_tx[c].real = cos(2.0*PI*c/(NC+1)); + f->phase_tx[c].imag = sin(2.0*PI*c/(NC+1)); + + f->phase_rx[c].real = 1.0; + f->phase_rx[c].imag = 0.0; + + for(k=0; krx_filter_mem_timing[c][k].real = 0.0; + f->rx_filter_mem_timing[c][k].imag = 0.0; + } + for(k=0; krx_baseband_mem_timing[c][k].real = 0.0; + f->rx_baseband_mem_timing[c][k].imag = 0.0; + } + } + + /* Set up frequency of each carrier */ + + for(c=0; cfreq[c].real = cos(2.0*PI*carrier_freq/FS); + f->freq[c].imag = sin(2.0*PI*carrier_freq/FS); + } + + for(c=NC/2; cfreq[c].real = cos(2.0*PI*carrier_freq/FS); + f->freq[c].imag = sin(2.0*PI*carrier_freq/FS); + } + + f->freq[NC].real = cos(2.0*PI*FCENTRE/FS); + f->freq[NC].imag = sin(2.0*PI*FCENTRE/FS); + + /* Generate DBPSK pilot Look Up Table (LUT) */ + + generate_pilot_lut(f->pilot_lut, &f->freq[NC]); + + /* freq Offset estimation states */ + + for(i=0; ipilot_baseband1[i].real = f->pilot_baseband2[i].real = 0.0; + f->pilot_baseband1[i].imag = f->pilot_baseband2[i].imag = 0.0; + } + f->pilot_lut_index = 0; + f->prev_pilot_lut_index = 3*M; + + for(i=0; ipilot_lpf1[i].real = f->pilot_lpf2[i].real = 0.0; + f->pilot_lpf1[i].imag = f->pilot_lpf2[i].imag = 0.0; + } + + f->foff = 0.0; + f->foff_rect.real = 1.0; + f->foff_rect.imag = 0.0; + f->foff_phase_rect.real = 1.0; + f->foff_phase_rect.imag = 0.0; + + f->fest_state = 0; + f->coarse_fine = COARSE; + + for(c=0; csig_est[c] = 0.0; + f->noise_est[c] = 0.0; + } + + return f; +} + +/*---------------------------------------------------------------------------*\ + +FUNCTION....: fdmdv_destroy +AUTHOR......: David Rowe +DATE CREATED: 16/4/2012 + +Destroy an instance of the modem. + +\*---------------------------------------------------------------------------*/ + +WIN32PROJECT_API void fdmdv_destroy(struct FDMDV *fdmdv) +{ + assert(fdmdv != NULL); + free(fdmdv); +} + +/*---------------------------------------------------------------------------*\ + +FUNCTION....: fdmdv_get_test_bits() +AUTHOR......: David Rowe +DATE CREATED: 16/4/2012 + +Generate a frame of bits from a repeating sequence of random data. OK so +it's not very random if it repeats but it makes syncing at the demod easier +for test purposes. + +\*---------------------------------------------------------------------------*/ + +WIN32PROJECT_API void fdmdv_get_test_bits(struct FDMDV *f, int tx_bits[]) +{ + int i; + + for(i=0; icurrent_test_bit]; + f->current_test_bit++; + if (f->current_test_bit > (NTEST_BITS-1)) + f->current_test_bit = 0; + } +} + +/*---------------------------------------------------------------------------*\ + +FUNCTION....: bits_to_dqpsk_symbols() +AUTHOR......: David Rowe +DATE CREATED: 16/4/2012 + +Maps bits to parallel DQPSK symbols. Generate Nc+1 QPSK symbols from +vector of (1,Nc*Nb) input tx_bits. The Nc+1 symbol is the +1 -1 +1 +.... BPSK sync carrier. + +\*---------------------------------------------------------------------------*/ + +void bits_to_dqpsk_symbols(COMP tx_symbols[], COMP prev_tx_symbols[], int tx_bits[], int *pilot_bit) +{ + int c, msb, lsb; + COMP j = {0.0,1.0}; + + /* map tx_bits to to Nc DQPSK symbols */ + + for(c=0; cprev_tx_symbols, tx_bits, &fdmdv->tx_pilot_bit); + memcpy(fdmdv->prev_tx_symbols, tx_symbols, sizeof(COMP)*(NC+1)); + tx_filter(tx_baseband, tx_symbols, fdmdv->tx_filter_memory); + fdm_upconvert(tx_fdm, tx_baseband, fdmdv->phase_tx, fdmdv->freq); + + *sync_bit = fdmdv->tx_pilot_bit; +} + +/*---------------------------------------------------------------------------*\ + +FUNCTION....: generate_pilot_fdm() +AUTHOR......: David Rowe +DATE CREATED: 19/4/2012 + +Generate M samples of DBPSK pilot signal for Freq offset estimation. + +\*---------------------------------------------------------------------------*/ + +void generate_pilot_fdm(COMP *pilot_fdm, int *bit, float *symbol, float *filter_mem, COMP *phase, COMP *freq) +{ + int i,j,k; + float tx_baseband[M]; + + /* +1 -1 +1 -1 DBPSK sync carrier, once filtered becomes (roughly) + two spectral lines at +/- RS/2 */ + + if (*bit) + *symbol = -*symbol; + else + *symbol = *symbol; + if (*bit) + *bit = 0; + else + *bit = 1; + + /* filter DPSK symbol to create M baseband samples */ + + filter_mem[NFILTER-1] = (float)(sqrt(2.0)/2) * *symbol; + for(i=0; ireal; + pilot_fdm[i].imag = sqrt(2.0)*2*tx_baseband[i] * phase->imag; + } +} + +/*---------------------------------------------------------------------------*\ + +FUNCTION....: generate_pilot_lut() +AUTHOR......: David Rowe +DATE CREATED: 19/4/2012 + +Generate a 4M sample vector of DBPSK pilot signal. As the pilot signal +is periodic in 4M samples we can then use this vector as a look up table +for pilot signal generation in the demod. + +\*---------------------------------------------------------------------------*/ + +void generate_pilot_lut(COMP pilot_lut[], COMP *pilot_freq) +{ + int pilot_rx_bit = 0; + float pilot_symbol = sqrt(2.0); + COMP pilot_phase = {1.0, 0.0}; + float pilot_filter_mem[NFILTER]; + COMP pilot[M]; + int i,f; + + for(i=0; i= 4) + memcpy(&pilot_lut[M*(f-4)], pilot, M*sizeof(COMP)); + } + +} + +/*---------------------------------------------------------------------------*\ + +FUNCTION....: lpf_peak_pick() +AUTHOR......: David Rowe +DATE CREATED: 20/4/2012 + +LPF and peak pick part of freq est, put in a function as we call it twice. + +\*---------------------------------------------------------------------------*/ + +void lpf_peak_pick(float *foff, float *max, COMP pilot_baseband[], COMP pilot_lpf[], COMP S[], int nin) +{ + int i,j,k; + int mpilot; + float mag, imax; + int ix; + float r; + + /* LPF cutoff 200Hz, so we can handle max +/- 200 Hz freq offset */ + + for(i=0; i imax) + { + imax = mag; + ix = i; + } + } + r = 2.0*200.0/MPILOTFFT; /* maps FFT bin to frequency in Hz */ + + if (ix >= MPILOTFFT/2) + *foff = (ix - MPILOTFFT)*r; + else + *foff = (ix)*r; + *max = imax; + +} + +/*---------------------------------------------------------------------------*\ + +FUNCTION....: rx_est_freq_offset() +AUTHOR......: David Rowe +DATE CREATED: 19/4/2012 + +Estimate frequency offset of FDM signal using BPSK pilot. Note that +this algorithm is quite sensitive to pilot tone level wrt other +carriers, so test variations to the pilot amplitude carefully. + +\*---------------------------------------------------------------------------*/ + +float rx_est_freq_offset(struct FDMDV *f, float rx_fdm[], int nin) +{ + int i,j; + COMP pilot[M+M/P]; + COMP prev_pilot[M+M/P]; + float foff, foff1, foff2; + float max1, max2; + + assert(nin <= M+M/P); + + /* get pilot samples used for correlation/down conversion of rx signal */ + + for (i=0; ipilot_lut[f->pilot_lut_index]; + f->pilot_lut_index++; + if (f->pilot_lut_index >= 4*M) + f->pilot_lut_index = 0; + + prev_pilot[i] = f->pilot_lut[f->prev_pilot_lut_index]; + f->prev_pilot_lut_index++; + if (f->prev_pilot_lut_index >= 4*M) + f->prev_pilot_lut_index = 0; + } + + /* + Down convert latest M samples of pilot by multiplying by ideal + BPSK pilot signal we have generated locally. The peak of the + resulting signal is sensitive to the time shift between the + received and local version of the pilot, so we do it twice at + different time shifts and choose the maximum. + */ + + for(i=0; ipilot_baseband1[i] = f->pilot_baseband1[i+nin]; + f->pilot_baseband2[i] = f->pilot_baseband2[i+nin]; + } + + for(i=0,j=NPILOTBASEBAND-nin; ipilot_baseband1[j] = fcmult(rx_fdm[i], cconj(pilot[i])); + f->pilot_baseband2[j] = fcmult(rx_fdm[i], cconj(prev_pilot[i])); + } + + lpf_peak_pick(&foff1, &max1, f->pilot_baseband1, f->pilot_lpf1, f->S1, nin); + lpf_peak_pick(&foff2, &max2, f->pilot_baseband2, f->pilot_lpf2, f->S2, nin); + + if (max1 > max2) + foff = foff1; + else + foff = foff2; + + return foff; +} + +/*---------------------------------------------------------------------------*\ + +FUNCTION....: freq_shift() +AUTHOR......: David Rowe +DATE CREATED: 26/4/2012 + +Frequency shift modem signal. + +\*---------------------------------------------------------------------------*/ + +void freq_shift(COMP rx_fdm_fcorr[], float rx_fdm[], float foff, COMP *foff_rect, COMP *foff_phase_rect, int nin) +{ + int i; + + foff_rect->real = cos(2.0*PI*foff/FS); + foff_rect->imag = sin(2.0*PI*foff/FS); + for(i=0; i M) + rx_timing -= M; + if (rx_timing < -M) + rx_timing += M; + + /* rx_filt_mem_timing contains M + Nfilter + M samples of the + baseband signal at rate M this enables us to resample the + filtered rx symbol with M sample precision once we have + rx_timing */ + + for(c=0; c= 0) && (d.imag >= 0)) { + msb = 0; lsb = 0; + } + if ((d.real < 0) && (d.imag >= 0)) { + msb = 0; lsb = 1; + } + if ((d.real < 0) && (d.imag < 0)) { + msb = 1; lsb = 0; + } + if ((d.real >= 0) && (d.imag < 0)) { + msb = 1; lsb = 1; + } + rx_bits[2*c] = msb; + rx_bits[2*c+1] = lsb; + } + + /* Extract DBPSK encoded Sync bit and fine freq offset estimate */ + + phase_difference[NC] = cmult(rx_symbols[NC], cconj(prev_rx_symbols[NC])); + if (phase_difference[NC].real < 0) { + *sync_bit = 1; + ferr = phase_difference[NC].imag; + } + else { + *sync_bit = 0; + ferr = -phase_difference[NC].imag; + } + + /* pilot carrier gets an extra pi/4 rotation to make it consistent + with other carriers, as we need it for snr_update and scatter + diagram */ + + phase_difference[NC] = cmult(phase_difference[NC], pi_on_4); + + return ferr; +} + +/*---------------------------------------------------------------------------*\ + +FUNCTION....: snr_update() +AUTHOR......: David Rowe +DATE CREATED: 17 May 2012 + +Given phase differences update estimates of signal and noise levels. + +\*---------------------------------------------------------------------------*/ + +void snr_update(float sig_est[], float noise_est[], COMP phase_difference[]) +{ + float s[NC+1]; + COMP refl_symbols[NC+1]; + float n[NC+1]; + COMP pi_on_4; + int c; + + pi_on_4.real = cos(PI/4.0); + pi_on_4.imag = sin(PI/4.0); + + /* mag of each symbol is distance from origin, this gives us a + vector of mags, one for each carrier. */ + + for(c=0; crx_test_bits_mem[i] = f->rx_test_bits_mem[j]; + for(i=NTEST_BITS-FDMDV_BITS_PER_FRAME,j=0; irx_test_bits_mem[i] = rx_bits[j]; + + /* see how many bit errors we get when checked against test sequence */ + + *bit_errors = 0; + for(i=0; irx_test_bits_mem[i]; + //printf("%d %d %d %d\n", i, test_bits[i], f->rx_test_bits_mem[i], test_bits[i] ^ f->rx_test_bits_mem[i]); + } + + /* if less than a thresh we are aligned and in sync with test sequence */ + + ber = (float)*bit_errors/NTEST_BITS; + + *sync = 0; + if (ber < 0.2) + *sync = 1; + + *ntest_bits = NTEST_BITS; + +} + +/*---------------------------------------------------------------------------*\ + +FUNCTION....: freq_state(() +AUTHOR......: David Rowe +DATE CREATED: 24/4/2012 + +Freq offset state machine. Moves between coarse and fine states +based on BPSK pilot sequence. Freq offset estimator occasionally +makes mistakes when used continuously. So we use it until we have +acquired the BPSK pilot, then switch to a more robust "fine" +tracking algorithm. If we lose sync we switch back to coarse mode +for fast-requisition of large frequency offsets. + +\*---------------------------------------------------------------------------*/ + +int freq_state(int sync_bit, int *state) +{ + int next_state, coarse_fine; + + /* acquire state, look for 6 symbol 010101 sequence from sync bit */ + + next_state = *state; + switch(*state) { + case 0: + if (sync_bit == 0) + next_state = 1; + break; + case 1: + if (sync_bit == 1) + next_state = 2; + else + next_state = 0; + break; + case 2: + if (sync_bit == 0) + next_state = 3; + else + next_state = 0; + break; + case 3: + if (sync_bit == 1) + next_state = 4; + else + next_state = 0; + break; + case 4: + if (sync_bit == 0) + next_state = 5; + else + next_state = 0; + break; + case 5: + if (sync_bit == 1) + next_state = 6; + else + next_state = 0; + break; + + /* states 6 and above are track mode, make sure we keep + getting 0101 sync bit sequence */ + + case 6: + if (sync_bit == 0) + next_state = 7; + else + next_state = 0; + + break; + case 7: + if (sync_bit == 1) + next_state = 6; + else + next_state = 0; + break; + } + + *state = next_state; + if (*state >= 6) + coarse_fine = FINE; + else + coarse_fine = COARSE; + + return coarse_fine; +} + +/*---------------------------------------------------------------------------*\ + +FUNCTION....: fdmdv_demod() +AUTHOR......: David Rowe +DATE CREATED: 26/4/2012 + +FDMDV demodulator, take an array of FDMDV_SAMPLES_PER_FRAME +modulated symbols, returns an array of FDMDV_BITS_PER_FRAME bits, +plus the sync bit. + +The number of input samples nin will normally be M == +FDMDV_SAMPLES_PER_FRAME. However to adjust for differences in +transmit and receive sample clocks nin will occasionally be M-M/P, +or M+M/P. + +\*---------------------------------------------------------------------------*/ + +WIN32PROJECT_API void fdmdv_demod(struct FDMDV *fdmdv, int rx_bits[], int *sync_bit, float rx_fdm[], int *nin) +{ + float foff_coarse, foff_fine; + COMP rx_fdm_fcorr[M+M/P]; + COMP rx_baseband[NC+1][M+M/P]; + COMP rx_filt[NC+1][P+1]; + COMP rx_symbols[NC+1]; + float env[NT*P]; + + /* freq offset estimation and correction */ + + foff_coarse = rx_est_freq_offset(fdmdv, rx_fdm, *nin); + + if (fdmdv->coarse_fine == COARSE) + fdmdv->foff = foff_coarse; + freq_shift(rx_fdm_fcorr, rx_fdm, fdmdv->foff, &fdmdv->foff_rect, &fdmdv->foff_phase_rect, *nin); + + /* baseband processing */ + + fdm_downconvert(rx_baseband, rx_fdm_fcorr, fdmdv->phase_rx, fdmdv->freq, *nin); + rx_filter(rx_filt, rx_baseband, fdmdv->rx_filter_memory, *nin); + fdmdv->rx_timing = rx_est_timing(rx_symbols, rx_filt, rx_baseband, fdmdv->rx_filter_mem_timing, env, fdmdv->rx_baseband_mem_timing, *nin); + + /* adjust number of input samples to keep timing within bounds */ + + *nin = M; + + if (fdmdv->rx_timing > 2*M/P) + *nin += M/P; + + if (fdmdv->rx_timing < 0) + *nin -= M/P; + + foff_fine = qpsk_to_bits(rx_bits, sync_bit, fdmdv->phase_difference, fdmdv->prev_rx_symbols, rx_symbols); + memcpy(fdmdv->prev_rx_symbols, rx_symbols, sizeof(COMP)*(NC+1)); + snr_update(fdmdv->sig_est, fdmdv->noise_est, fdmdv->phase_difference); + + /* freq offset estimation state machine */ + + fdmdv->coarse_fine = freq_state(*sync_bit, &fdmdv->fest_state); + fdmdv->foff -= TRACK_COEFF*foff_fine; +} + +/*---------------------------------------------------------------------------*\ + +FUNCTION....: calc_snr() +AUTHOR......: David Rowe +DATE CREATED: 17 May 2012 + +Calculate current SNR estimate (3000Hz noise BW) + +\*---------------------------------------------------------------------------*/ + +float calc_snr(float sig_est[], float noise_est[]) +{ + float S, SdB; + float mean, N50, N50dB, N3000dB; + float snr_dB; + int c; + + S = 0.0; + for(c=0; csnr_est = calc_snr(fdmdv->sig_est, fdmdv->noise_est); + fdmdv_stats->fest_coarse_fine = fdmdv->coarse_fine; + fdmdv_stats->foff = fdmdv->foff; + fdmdv_stats->rx_timing = fdmdv->rx_timing; + fdmdv_stats->clock_offset = 0.0; /* TODO - implement clock offset estimation */ + + assert((NC+1) == FDMDV_NSYM); + + for(c=0; crx_symbols[c] = fdmdv->phase_difference[c]; + } +} + +/*---------------------------------------------------------------------------*\ + +FUNCTION....: fdmdv_8_to_48() +AUTHOR......: David Rowe +DATE CREATED: 9 May 2012 + +Changes the sample rate of a signal from 8 to 48 kHz. Experience +with PC based modems has shown that PC sound cards have a more +accurate sample clock when set for 48 kHz than 8 kHz. + +n is the number of samples at the 8 kHz rate, there are FDMDV_OS*n samples +at the 48 kHz rate. A memory of FDMDV_OS_TAPS/FDMDV_OS samples is reqd for +in8k[] (see t48_8.c unit test as example). + +This is a classic polyphase upsampler. We take the 8 kHz samples +and insert (FDMDV_OS-1) zeroes between each sample, then +FDMDV_OS_TAPS FIR low pass filter the signal at 4kHz. As most of +the input samples are zeroes, we only need to multiply non-zero +input samples by filter coefficients. The zero insertion and +filtering are combined in the code below and I'm too lazy to explain +it further right now.... + +\*---------------------------------------------------------------------------*/ + +WIN32PROJECT_API void fdmdv_8_to_48(float out48k[], float in8k[], int n) +{ + int i,j,k,l; + + for(i=0; itrue true WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN32PROJECT_EXPORTS;%(PreprocessorDefinitions) + ..\..\codec2-dev\src + 4305;4244;%(DisableSpecificWarnings) Windows @@ -78,6 +80,7 @@ + @@ -88,6 +91,7 @@ + @@ -96,6 +100,8 @@ + + diff --git a/fdmdv2/fdmdv2dll/fdmdv2-project.vcxproj.filters b/fdmdv2/fdmdv2dll/fdmdv2-project.vcxproj.filters index 5ef2042e..b7e4eadf 100644 --- a/fdmdv2/fdmdv2dll/fdmdv2-project.vcxproj.filters +++ b/fdmdv2/fdmdv2dll/fdmdv2-project.vcxproj.filters @@ -25,9 +25,6 @@ src - - src - src @@ -64,6 +61,15 @@ src + + src + + + src + + + src + @@ -117,6 +123,12 @@ src + + include + + + include + diff --git a/fdmdv2/fdmdv2dll/stdafx.h b/fdmdv2/fdmdv2dll/stdafx.h index 677e68a9..3ad2c6d1 100644 --- a/fdmdv2/fdmdv2dll/stdafx.h +++ b/fdmdv2/fdmdv2dll/stdafx.h @@ -11,6 +11,6 @@ // Windows Header Files: #include - +static inline double round(double val); // TODO: reference additional headers your program requires here