Skip to content
Snippets Groups Projects
freqsetup.h 13.9 KiB
Newer Older
 * Copyright 2016-2020
 * 
 * Bernd-Christian Renner, and
 * Hamburg University of Technology (TUHH).
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


#ifndef FREQSETUP_H
#define FREQSETUP_H

#include "fixpoint.h"

#include <stdint.h>
#include <stdbool.h>


#ifdef WIDEBAND
#  define FREQ_BAND_NUM_MAX        6   // max. number of frequency bands
#else
#  define FREQ_BAND_NUM_MAX        4   // max. number of frequency bands
#endif

#define FREQ_CARRIER_NUM_MAX       3   // max. number of carriers (hops) per band

// NOTE if these ever become "variables", FREQ_SYNC_SEQ_LEN must become varible as well
#define FREQ_SYNC_NUM_MAX          2   // max. number of sync frequencies
#define FREQ_SYNC_CARRIER_MAX      2

#define FREQ_SYNC_SEQ_LEN          (FREQ_SYNC_NUM_MAX * FREQ_SYNC_CARRIER_MAX)

#define FREQ_SFD_LEN               4
#define FREQ_SFD_SEQUENCE          {1,0,0,1}  // NOTE/TODO only "save" due to carrier changing? -> convert to data freqs

// sampling frequency when receiving
#ifndef SAMPLING_FREQ
#   define SAMPLING_FREQ            200000  /* hertz */
#endif
#define SAMPLING_CLK_DIV         (PBA_SPEED / (2 * SAMPLING_FREQ))
#if SAMPLING_CLK_DIV * 2 * SAMPLING_FREQ != PBA_SPEED
#	error "cpu speed is not a multiple of sampling frequency"
#endif

// tx sending/sampling speed-up (vs. receiving sampling frequency)
// TODO better define a frequency here?
#ifndef TX_FACTOR
#   define TX_FACTOR                    1  // scaling for sending
#endif



// sampling frequency when sending
#define TX_SAMPLING_CLK_DIV      ((SAMPLING_CLK_DIV) / (TX_FACTOR))
#if TX_SAMPLING_CLK_DIV * TX_FACTOR != SAMPLING_CLK_DIV
#	error "tx sampling frequency not a multiple of rx sampling frequency"
#endif

#define SYNC_MOD_INDEX  1 // TODO only implemented for sending (do not change atm)

#if SAMPLING_FREQ == 200000UL
#  ifdef HIGHSPEED
#    define SAMPLES_PER_SYMBOL  256  // must be power of 2
#    ifndef HIGHFREQ
#      define FREQ_MSG            "*** 200kHz, HIGHSPEED, LOWFREQ ***"
#      define FREQ_RX_LUT_FILE    "lut/freq-rx_25000-62500Hz_48x_256tap_200kHz.c"
#    else
#      define FREQ_MSG            "*** 200kHz, HIGHSPEED ***"
#      define FREQ_RX_LUT_FILE    "lut/freq-rx_50000-87500Hz_48x_256tap_200kHz.c"
#    endif
#  else
#    define SAMPLES_PER_SYMBOL  512  // must be power of 2
#    ifndef HIGHFREQ
#      define FREQ_MSG            "*** 200kHz, LOWFREQ ***"
#      define FREQ_RX_LUT_FILE    "lut/freq-rx_25000-62500Hz_48x_512tap_200kHz.c"
#    else
#      define FREQ_MSG            "*** 200kHz ***"
#      define FREQ_RX_LUT_FILE    "lut/freq-rx_50000-87500Hz_48x_512tap_200kHz.c"
#    endif
#  endif
#else
#  error "RX sampling frequency not supported"
#endif

#if TX_FACTOR * SAMPLING_FREQ == 200000UL
#  ifdef HIGHSPEED
#    ifndef HIGHFREQ
#      define FREQ_TX_LUT_FILE    "lut/freq-tx_25000-62500Hz_48x_256tap_200kHz.c"
#    else
#      define FREQ_TX_LUT_FILE    "lut/freq-tx_50000-87500Hz_48x_256tap_200kHz.c"
#    endif
#  else
#    ifndef HIGHFREQ
#      define FREQ_TX_LUT_FILE    "lut/freq-tx_25000-62500Hz_48x_512tap_200kHz.c"
#    else
#      define FREQ_TX_LUT_FILE    "lut/freq-tx_50000-87500Hz_48x_512tap_200kHz.c"
#    endif
#  endif
# else
#  error "TX sampling frequency not supported"
# endif


// transducer options
enum {
  TRANSDUCER_AS1,
  TRANSDUCER_FRAUNHOFER,
  TRANSDUCER_BUDDY,
  TRANSDUCER_AS1_ORIG,
  TRANSDUCER_FRAUNHOFER_ORIG,
  TRANSDUCER_NUM
};

#define TRANSDUCER_DFLT   TRANSDUCER_AS1

#ifndef HIGHFREQ
#  define GAIN_LUT_FILE           "lut/gain-25000-62500kHz_48x.c"
#else
#  define GAIN_LUT_FILE           "lut/gain-50000-87500kHz_48x.c"
#endif


// list all frequencies (NOTE these MUST match the actual
// implementation in the C-file)
#define FREQ_IDX(n)                (n)
#define FREQ_LIST_NUM              49
#define SAMPLES_PER_SYMBOL_MASK   (SAMPLES_PER_SYMBOL-1)
const fp16_t * const FREQ_LIST[FREQ_LIST_NUM];
const fp16_t * const FREQ_TXLIST[FREQ_LIST_NUM];


// sync/preamble length setup
#define SYNC_SEQ_NUM_MIN            2
#define SYNC_SEQ_NUM_MAX            8
#ifndef SYNC_SEQ_NUM_TX_DFLT
# define SYNC_SEQ_NUM_TX_DFLT       4
#endif
#ifndef SYNC_SEQ_NUM_RX_DFLT
# define SYNC_SEQ_NUM_RX_DFLT       3
#endif

#define SFD_SEQ_NUM_MAX (1 + (SYNC_SEQ_NUM_MAX - SYNC_SEQ_NUM_MIN))

// sanity check
#if SYNC_SEQ_NUM_RX_DFLT > SYNC_SEQ_NUM_TX_DFLT
# error "*** default sync rx sequence cannot be longer than tx sequence ***"
#endif

// number of leading/trailing sync symbols to ignore
// lead: should be 0 or 1 and MUST be less than SYNC_SYMBOLS_NUM_MIN-1
#define SYNC_SYMBOLS_NUM_RX_LEAD_IGNORE      0
// trail: should be 1 and MUST be less than FREQ_SFD_LEN
#define SYNC_SYMBOLS_NUM_RX_TRAIL_IGNORE     1

// macros for sync lengths
#define SYNC_SYMBOLS_NUM_TX(sn)  ((sn) * FREQ_SYNC_SEQ_LEN)
#define SYNC_SYMBOLS_NUM_RX(sn)  ((sn) * FREQ_SYNC_SEQ_LEN - SYNC_SYMBOLS_NUM_RX_TRAIL_IGNORE)
#define SYNC_SEQ_NUM_TX(sn)      ((sn) / FREQ_SYNC_SEQ_LEN)
#define SYNC_SEQ_NUM_RX(sn)      (((sn) + SYNC_SYMBOLS_NUM_RX_TRAIL_IGNORE) / FREQ_SYNC_SEQ_LEN)

// maximum number of symbols
#define SYNC_SYMBOLS_NUM_MAX       (SYNC_SEQ_NUM_MAX * FREQ_SYNC_SEQ_LEN)

// rx signal threshold setup
#define SIGNAL_THRESHOLD_MAX       (FP32_FROM_UINT(SAMPLES_PER_SYMBOL) / 2)
#define SIGNAL_THRESHOLD_DFLT      (SIGNAL_THRESHOLD_MAX / 10)    // 10%
//#define SIGNAL_THRESHOLD_DFLT      (SIGNAL_THRESHOLD_MAX / 20)  // 5%
//#define SIGNAL_THRESHOLD_DFLT      (SIGNAL_THRESHOLD_MAX / 4)   // 25%


// binary coding: symbols are space ("0") and mark ("1")
enum {
  SYMBOL_SPACE = 0,
  SYMBOL_MARK  = 1,
  NUM_SYMBOLS
};

// minimum window size for peak detection during sync
//#define SIGNAL_WINDOW_SIZE  (SAMPLES_PER_SYMBOL / 2)
#define SIGNAL_WINDOW_SIZE_MAX   (SAMPLES_PER_SYMBOL / 4)
#define SIGNAL_WINDOW_SIZE_DFLT  (SAMPLES_PER_SYMBOL / 8)

// NOTE should be at least SIGNAL_WINDOW_SIZE_MAX
#define SIGNAL_WINDOW_MAX_DELAY  (SAMPLES_PER_SYMBOL / 4)


// turn-around times for mode switching
//#define TXRX_TURNAROUND_TICKS    250  // num samples needed for tx -> rx
//#define RXTX_TURNAROUND_TICKS    250  // num samples needed for rx -> tx
// time in milli seconds
#define MS_TO_TICKS(t)           (((t) * SAMPLING_FREQ) / 1000UL)
#define US_TO_TICKS(t)           (((t) * SAMPLING_FREQ) / 1000000UL)
#define TICKS_TO_MS(t)           (((t) * 1000UL) / SAMPLING_FREQ)
#define TICKS_TO_US(t)           (((t) * 1000000ULL) / SAMPLING_FREQ)

#define TXRX_TURNAROUND_TICKS    MS_TO_TICKS(12)  // num samples needed for tx -> rx
#define RXTX_TURNAROUND_TICKS    MS_TO_TICKS(12)  // num samples needed for rx -> tx

// FIXME move these to tx amp implementation?
// problem 1: above should be constant! ALWAYS, platform indep, or modems will not work with each other!
// problem 2: below depend on the actual hardware!

//#define SAMPLES_TXSWITCH_WAIT    US_TO_TICKS(500)
//#define SAMPLES_TX_STABILIZE     MS_TO_TICKS(4)
// timings for TX enable
#define TXON_SUPPLY_STABILIZE_NS     MS_TO_TICKS(4)   // time for supply to come up

// timings for TX disable
#define TXOFF_OUTPUT_SETTLE_NS       US_TO_TICKS(500) // time for amp output to settle after transmission
#define TXOFF_SWITCH_DELAY_NS        US_TO_TICKS(500) // time to delay after switching hydrophone


/*
 * multiplication of wave forms with sampled signal
 * incoherent receiver requires a sine and cosine value
 */
typedef struct {
  fp16_t  sin;
  fp16_t  cos;
} freq_product_t;

/*
 * integral for coherent reception
 * requires a sine and cosine value (see freq_product_t)
 */
typedef struct {
  fp32_t  sin;
  fp32_t  cos;
} freq_integral_t;

typedef fp32_t freq_magnitude_t;  // FIXME 64-bit value, as square of Integral values?



// init
bool
freq_init(void);


// get preamble/sync length
uint8_t
freq_getNumSyncTxSymbols(void);


// set preamble/sync length
// input is sequence length (not num symbols)
bool
freq_setNumSyncTxSymbols(uint8_t numsymb);


// get preamble symbols to be received for sync
uint8_t
freq_getNumSyncRxSymbols(void);


// set preamble symbols to be received for sync
// input is sequence length (not num symbols)
bool
freq_setNumSyncRxSymbols(uint8_t numsymb);


// get number of SFD tries (max) needed after sync
uint8_t
freq_getNumSfdTries(void);


// frequency look-up tables for preamble / sync
// contains 2*SAMPLES_PER_SYMBOL values, where
// - even indices are sine values
// - odd indices are cosine values
//extern const fp16_t * const FREQ_SYNC_SPACE[FREQ_SYNC_NUM_MAX];
//extern const fp16_t * const FREQ_SYNC_MARK[FREQ_SYNC_NUM_MAX];

//typedef const fp16_t * (*getSyncFreq_t)(uint8_t num, uint8_t hop);

const fp16_t *
freq_getSyncFreq(uint8_t symbol, uint8_t num, uint8_t hop);

const fp16_t *
freq_getSyncTxFreq(uint8_t symbol, uint8_t num, uint8_t hop);

fp16_t
freq_getSyncTxGain(uint8_t symbol, uint8_t num, uint8_t hop);



// return pointer to first value of space signal for given band and carrier
const fp16_t *
freq_getFreq(uint8_t symbol, uint8_t band, uint8_t hop);

// return pointer to first value of symbol signal for given band and carrier
const fp16_t *
freq_getTxFreq(uint8_t symbol, uint8_t band, uint8_t hop);

// return relative gain of symbol frequency for transmissions
fp16_t
freq_getTxGain(uint8_t symbol, uint8_t band, uint8_t hop);


// return pointer to first element of rx filter
// const fp16_t *
// freq_getRxWin(void);


// return attenuation due to rx window
// uint8_t
// freq_getRxWinLossSq(void);


// get number of currently used bands
uint8_t
freq_getNumBands(void);


// set number of currently used bands
// @return true, if 0 < num <= MAX; false else
bool
freq_setNumBands(uint8_t num);


// get pointer to band sequence of bits
// (the result is an array of [FREQ_BAND_NUM_MAX][FREQ_CARRIER_NUM_MAX])
size_t
freq_getBandSequence(uint8_t * seq);


// set the hopping sequence for band
// (seq must always contain FREQ_CARRIER_NUM_MAX entries)
size_t
freq_setBandSequence(const uint8_t * seq);


// get number of currently used carriers (per band)
uint8_t
freq_getNumCarriers(void);


// set number of currently used carriers (for all bands)
// @return true, if 0 < num <= MAX; false else
bool
freq_setNumCarriers(uint8_t num);


// get pointer to hopping sequence of band
// (the result is an array of [FREQ_BAND_NUM_MAX][FREQ_CARRIER_NUM_MAX])
size_t
freq_getHoppingSequence(uint8_t * seq);


// set the hopping sequence for band
// (seq must always contain FREQ_CARRIER_NUM_MAX entries)
bool
freq_setHoppingSequence(const uint8_t * seq);


// get max threshold for a single frequency/bit per symbol
freq_magnitude_t
freq_getMaxSignalThreshold(void);


// get threshold that indicates a proper signal (rather than noise)
// as square valued
freq_magnitude_t
freq_getRxThreshold(void);


// get max threshold for a single frequency/bit per symbol
freq_magnitude_t
freq_getMaxSignalThresholdSq(void);


// get threshold that indicates a proper signal (rather than noise)
// as square valued
freq_magnitude_t
freq_getRxThresholdSq(void);


// set threshold that indicates a proper signal (rather than noise)
bool
freq_setRxThreshold(freq_magnitude_t thresh);


// get threshold that indicates a proper signal (rather than noise)
// as percentile of maximum value
uint8_t
freq_getRxThresholdPerc(void);


// set threshold that indicates a proper signal (rather than noise)
// in percent of maximum signal
bool
freq_setRxThresholdPerc(uint8_t perc);


// set txgain values from array v, the array *must* contain
// FREQ_LIST_NUM values (FREQ_LIST_NUM == num)
// return TRUE, if operation succeeded, FALSE else
//bool
//freq_setTxGainArray(fp16_t * v, uint8_t num);


// get txgain values by writing them into array v, the array *must* contain
// at least FREQ_LIST_NUM values (num > FREQ_LIST_NUM)
// return the number of values in the array (either 0 or FREQ_LIST_NUM)
//uint8_t
//freq_getTxGainArray(fp16_t * v, uint8_t num);

fp16_t
freq_getTxGainByIndex(uint8_t i);


uint16_t
freq_getSignalWindowSize(void);


void
freq_setSignalWindowSize(uint16_t newSize);


// change transducer gain table; index h must be from TRANSDUCER_*
bool
freq_setTransducer(uint8_t h);


// get transducer gain table index (from TRANSDUCER_*)
uint8_t
freq_getTransducer(void);


// get transducer description (of currently selected one)
const char *
freq_getTransducerDescr(void);


#endif /* FREQSETUP_H */