From aa0290bd1985943cd30f83d9d5b5b67c47c67923 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 15 Jun 2019 10:58:55 +0200 Subject: [PATCH] FreeDV: use mainstream freeDV modem from codec2 instead of internal library. Updated git checkout SHA1 to latest. Updated version and changelogs. --- CHANGELOG | 8 + CMakeLists.txt | 6 +- debian/changelog | 8 + external/CMakeLists.txt | 2 +- libfreedv/CMakeLists.txt | 83 - libfreedv/HRA_112_112.cpp | 27 - libfreedv/HRA_112_112.h | 23 - libfreedv/_kiss_fft_guts.h | 159 - libfreedv/codec2_cohpsk.h | 76 - libfreedv/codec2_fdmdv.h | 110 - libfreedv/codec2_fft.cpp | 163 -- libfreedv/codec2_fft.h | 108 - libfreedv/codec2_ofdm.h | 101 - libfreedv/cohpsk.cpp | 1394 --------- libfreedv/cohpsk_defs.h | 9 - libfreedv/cohpsk_internal.h | 131 - libfreedv/comp_prim.h | 149 - libfreedv/defines.h | 120 - libfreedv/fdmdv.cpp | 1995 ------------- libfreedv/fdmdv_internal.h | 200 -- libfreedv/fdv_arm_math.h | 41 - libfreedv/fmfsk.cpp | 373 --- libfreedv/fmfsk.h | 116 - libfreedv/freedv_api.cpp | 2591 ----------------- libfreedv/freedv_api_internal.h | 154 - libfreedv/freedv_data_channel.cpp | 353 --- libfreedv/freedv_data_channel.h | 75 - libfreedv/freedv_filter.cpp | 293 -- libfreedv/freedv_filter.h | 48 - libfreedv/freedv_filter_coef.h | 166 -- libfreedv/freedv_vhf_framing.cpp | 886 ------ libfreedv/freedv_vhf_framing.h | 104 - libfreedv/fsk.cpp | 1257 -------- libfreedv/fsk.h | 209 -- libfreedv/gp_interleaver.cpp | 123 - libfreedv/gp_interleaver.h | 46 - libfreedv/hanning.h | 649 ----- libfreedv/interldpc.cpp | 260 -- libfreedv/interldpc.h | 59 - libfreedv/kiss_fft.cpp | 416 --- libfreedv/kiss_fft.h | 123 - libfreedv/kiss_fftr.cpp | 163 -- libfreedv/kiss_fftr.h | 44 - libfreedv/libfreedv.h | 187 -- libfreedv/linreg.cpp | 110 - libfreedv/linreg.h | 40 - libfreedv/machdep.h | 57 - libfreedv/modem_probe.h | 153 - libfreedv/modem_stats.h | 79 - libfreedv/mpdecode_core.cpp | 726 ----- libfreedv/mpdecode_core.h | 51 - libfreedv/ofdm.cpp | 1750 ----------- libfreedv/ofdm_internal.h | 137 - libfreedv/os.h | 57 - libfreedv/phi0.cpp | 223 -- libfreedv/phi0.h | 11 - libfreedv/pilot_coeff.h | 46 - libfreedv/pilots_coh.h | 11 - libfreedv/rn.h | 969 ------ libfreedv/rn_coh.h | 609 ---- libfreedv/rxdec_coeff.h | 40 - libfreedv/test_bits.h | 170 -- libfreedv/test_bits_coh.h | 569 ---- plugins/channelrx/demodfreedv/CMakeLists.txt | 18 +- plugins/channelrx/demodfreedv/freedvdemod.cpp | 51 +- plugins/channelrx/demodfreedv/freedvdemod.h | 6 +- plugins/channeltx/modfreedv/CMakeLists.txt | 12 +- plugins/channeltx/modfreedv/freedvmod.cpp | 48 +- plugins/channeltx/modfreedv/freedvmod.h | 4 +- 69 files changed, 82 insertions(+), 19473 deletions(-) delete mode 100644 libfreedv/CMakeLists.txt delete mode 100644 libfreedv/HRA_112_112.cpp delete mode 100644 libfreedv/HRA_112_112.h delete mode 100644 libfreedv/_kiss_fft_guts.h delete mode 100644 libfreedv/codec2_cohpsk.h delete mode 100644 libfreedv/codec2_fdmdv.h delete mode 100644 libfreedv/codec2_fft.cpp delete mode 100644 libfreedv/codec2_fft.h delete mode 100644 libfreedv/codec2_ofdm.h delete mode 100644 libfreedv/cohpsk.cpp delete mode 100644 libfreedv/cohpsk_defs.h delete mode 100644 libfreedv/cohpsk_internal.h delete mode 100644 libfreedv/comp_prim.h delete mode 100644 libfreedv/defines.h delete mode 100644 libfreedv/fdmdv.cpp delete mode 100644 libfreedv/fdmdv_internal.h delete mode 100644 libfreedv/fdv_arm_math.h delete mode 100644 libfreedv/fmfsk.cpp delete mode 100644 libfreedv/fmfsk.h delete mode 100644 libfreedv/freedv_api.cpp delete mode 100644 libfreedv/freedv_api_internal.h delete mode 100644 libfreedv/freedv_data_channel.cpp delete mode 100644 libfreedv/freedv_data_channel.h delete mode 100644 libfreedv/freedv_filter.cpp delete mode 100644 libfreedv/freedv_filter.h delete mode 100644 libfreedv/freedv_filter_coef.h delete mode 100644 libfreedv/freedv_vhf_framing.cpp delete mode 100644 libfreedv/freedv_vhf_framing.h delete mode 100644 libfreedv/fsk.cpp delete mode 100644 libfreedv/fsk.h delete mode 100644 libfreedv/gp_interleaver.cpp delete mode 100644 libfreedv/gp_interleaver.h delete mode 100644 libfreedv/hanning.h delete mode 100644 libfreedv/interldpc.cpp delete mode 100644 libfreedv/interldpc.h delete mode 100644 libfreedv/kiss_fft.cpp delete mode 100644 libfreedv/kiss_fft.h delete mode 100644 libfreedv/kiss_fftr.cpp delete mode 100644 libfreedv/kiss_fftr.h delete mode 100644 libfreedv/libfreedv.h delete mode 100644 libfreedv/linreg.cpp delete mode 100644 libfreedv/linreg.h delete mode 100644 libfreedv/machdep.h delete mode 100644 libfreedv/modem_probe.h delete mode 100644 libfreedv/modem_stats.h delete mode 100644 libfreedv/mpdecode_core.cpp delete mode 100644 libfreedv/mpdecode_core.h delete mode 100644 libfreedv/ofdm.cpp delete mode 100644 libfreedv/ofdm_internal.h delete mode 100644 libfreedv/os.h delete mode 100644 libfreedv/phi0.cpp delete mode 100644 libfreedv/phi0.h delete mode 100644 libfreedv/pilot_coeff.h delete mode 100644 libfreedv/pilots_coh.h delete mode 100644 libfreedv/rn.h delete mode 100644 libfreedv/rn_coh.h delete mode 100644 libfreedv/rxdec_coeff.h delete mode 100644 libfreedv/test_bits.h delete mode 100644 libfreedv/test_bits_coh.h diff --git a/CHANGELOG b/CHANGELOG index 7810d19a0..4ff35c221 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,11 @@ +sdrangel (4.10.1-1) unstable; urgency=medium + + * Implemented device user arguments + * PVS-Studio static analysis corrections (5) + * FreeDV demod: use mainstream library from codec2 instead of internal + + -- Edouard Griffiths, F4EXB Sat, 15 Jun 2019 06:44:06 +0100 + sdrangel (4.10.0-1) unstable; urgency=medium * Support for KiwiSDR diff --git a/CMakeLists.txt b/CMakeLists.txt index 56df31705..47d8b7c7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) # configure version set(sdrangel_VERSION_MAJOR "4") set(sdrangel_VERSION_MINOR "10") -set(sdrangel_VERSION_PATCH "0") +set(sdrangel_VERSION_PATCH "1") set(sdrangel_VERSION_SUFFIX "") # SDRAngel cmake options @@ -374,10 +374,6 @@ if(ENABLE_XTRX) find_package(LibXTRX) endif() -if (CODEC2_FOUND) - add_subdirectory(libfreedv) -endif(CODEC2_FOUND) - if(ENABLE_FUNCUBE AND UNIX AND LIBUSB_FOUND) add_subdirectory(fcdlib) add_subdirectory(fcdhid) diff --git a/debian/changelog b/debian/changelog index 7810d19a0..4ff35c221 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +sdrangel (4.10.1-1) unstable; urgency=medium + + * Implemented device user arguments + * PVS-Studio static analysis corrections (5) + * FreeDV demod: use mainstream library from codec2 instead of internal + + -- Edouard Griffiths, F4EXB Sat, 15 Jun 2019 06:44:06 +0100 + sdrangel (4.10.0-1) unstable; urgency=medium * Support for KiwiSDR diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 0382d1790..6e1f3388c 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -8,7 +8,7 @@ # but make the configuration dirty # which version/tag/checkout to use -set(CODEC2_TAG 7a0187da3ffb06fd90c081216b50bab94d02d046) +set(CODEC2_TAG 76a20416d715ee06f8b36a9953506876689a3bd2) set(CM256CC_TAG f21e8bc1e9afdb0b28672743dcec111aec1d32d9) set(MBELIB_TAG "debian/1.3.0") set(SERIALDV_TAG abd65a0fc2d5339808194862d14119b0cba70424) diff --git a/libfreedv/CMakeLists.txt b/libfreedv/CMakeLists.txt deleted file mode 100644 index f5aee9577..000000000 --- a/libfreedv/CMakeLists.txt +++ /dev/null @@ -1,83 +0,0 @@ -project(freedv) - -set(freedv_SOURCES - codec2_fft.cpp - cohpsk.cpp - fdmdv.cpp - freedv_api.cpp - freedv_data_channel.cpp - freedv_filter.cpp - freedv_vhf_framing.cpp - fmfsk.cpp - fsk.cpp - gp_interleaver.cpp - HRA_112_112.cpp - interldpc.cpp - kiss_fft.cpp - kiss_fftr.cpp - linreg.cpp - mpdecode_core.cpp - ofdm.cpp - phi0.cpp -) - -set(freedv_HEADERS - codec2_cohpsk.h - codec2_fdmdv.h - codec2_fft.h - codec2_ofdm.h - cohpsk_defs.h - cohpsk_internal.h - comp_prim.h - defines.h - fdmdv_internal.h - fdv_arm_math.h - fmfsk.h - freedv_api_internal.h - freedv_data_channel.h - freedv_filter_coef.h - freedv_filter.h - freedv_vhf_framing.h - fsk.h - gp_interleaver.h - hanning.h - HRA_112_112.h - interldpc.h - _kiss_fft_guts.h - kiss_fft.h - kiss_fftr.h - libfreedv.h - linreg.h - machdep.h - modem_probe.h - modem_stats.h - mpdecode_core.h - ofdm_internal.h - os.h - phi0.h - pilot_coeff.h - pilots_coh.h - rn_coh.h - rn.h - rxdec_coeff.h - test_bits_coh.h - test_bits.h -) - -include_directories( - ${CODEC2_INCLUDE_DIR} -) - -add_library(freedv SHARED - ${freedv_SOURCES} -) - -if(ENABLE_EXTERNAL_LIBRARIES) - add_dependencies(freedv codec2) -endif() - -target_link_libraries(freedv - ${CODEC2_LIBRARIES} -) - -install(TARGETS freedv DESTINATION ${INSTALL_LIB_DIR}) diff --git a/libfreedv/HRA_112_112.cpp b/libfreedv/HRA_112_112.cpp deleted file mode 100644 index 406e11225..000000000 --- a/libfreedv/HRA_112_112.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - FILE....: HRA_112_112.c - - Static arrays for LDPC codec HRA_112_112, generated by ldpc_gen_c_h_file.m. -*/ - -#include -#include "HRA_112_112.h" - -namespace FreeDV -{ - -const uint16_t HRA_112_112_H_rows[] = { -22, 18, 15, 63, 16, 13, 1, 2, 29, 25, 28, 4, 36, 10, 38, 7, 60, 23, 11, 38, 28, 1, 12, 31, 57, 45, 57, 30, 23, 59, 67, 14, 16, 4, 14, 62, 15, 50, 7, 70, 64, 6, 42, 48, 9, 31, 19, 40, 49, 2, 25, 3, 41, 49, 36, 9, 29, 39, 31, 5, 17, 1, 29, 25, 11, 21, 18, 2, 8, 22, 39, 15, 8, 22, 13, 3, 19, 4, 21, 62, 34, 43, 6, 24, 17, 60, 8, 74, 6, 44, 60, 10, 33, 12, 26, 24, 45, 81, 69, 80, 41, 28, 23, 5, 10, 20, 52, 18, 13, 86, 3, 7, 59, 21, 65, 72, 34, 37, 26, 55, 47, 48, 34, 5, 44, 47, 68, 96, 82, 111, 61, 74, 30, 17, 55, 98, 81, 66, 89, 35, 74, 82, 91, 51, 55, 51, 30, 89, 61, 75, 40, 71, 73, 11, 56, 54, 19, 47, 94, 69, 64, 20, 64, 12, 54, 77, 42, 88, 36, 52, 90, 63, 70, 27, 32, 73, 91, 32, 56, 46, 9, 78, 51, 68, 88, 67, 20, 43, 40, 14, 66, 86, 39, 97, 38, 27, 50, 84, 54, 92, 61, 46, 67, 24, 58, 35, 58, 37, 98, 85, 73, 84, 48, 35, 57, 16, 26, 37, 65, 32, 72, 95, 107, 33, 77, 33, 85, 105, 106, 75, 56, 71, 79, 59, 52, 105, 79, 90, 93, 100, 88, 112, 86, 80, 65, 42, 106, 100, 93, 94, 99, 97, 93, 101, 111, 99, 83, 53, 85, 95, 108, 107, 41, 109, 84, 78, 104, 101, 69, 110, 98, 103, 80, 83, 77, 71, 76, 78, 87, 102, 104, 95, 96, 83, 87, 50, 110, 103, 112, 45, 58, 70, 94, 91, 89, 81, 101, 82, 63, 72, 100, 97, 76, 112, 53, 105, 49, 75, 109, 102, 66, 111, 68, 87, 92, 79, 96, 43, 90, 44, 110, 99, 102, 92, 103, 106, 62, 53, 27, 46, 108, 104, 107, 108, 109, 76 -}; - -const uint16_t HRA_112_112_H_cols[] = { -7, 8, 52, 12, 12, 42, 16, 69, 45, 14, 19, 23, 6, 32, 3, 5, 22, 2, 45, 50, 2, 1, 18, 84, 10, 7, 62, 11, 9, 21, 24, 63, 2, 5, 28, 13, 6, 15, 58, 39, 39, 22, 76, 13, 26, 68, 9, 10, 49, 38, 32, 11, 34, 44, 8, 7, 25, 67, 1, 17, 19, 36, 4, 41, 3, 26, 31, 15, 45, 40, 8, 4, 41, 20, 6, 53, 1, 42, 9, 20, 25, 17, 33, 41, 3, 19, 55, 17, 27, 14, 31, 88, 15, 26, 36, 16, 28, 24, 27, 16, 30, 56, 48, 43, 4, 5, 38, 37, 40, 46, 18, 18, 22, 50, 76, 34, 60, 83, 39, 73, 56, 92, 42, 52, 75, 35, 37, 33, 61, 67, 47, 75, 66, 70, 29, 92, 51, 95, 84, 21, 57, 28, 46, 66, 93, 11, 94, 55, 96, 20, 71, 48, 53, 43, 82, 90, 66, 90, 14, 44, 54, 62, 34, 58, 81, 53, 23, 43, 27, 93, 10, 86, 37, 80, 60, 49, 21, 79, 74, 72, 48, 61, 40, 76, 64, 29, 38, 79, 51, 54, 13, 49, 72, 30, 50, 86, 35, 80, 61, 56, 36, 59, 65, 91, 25, 47, 58, 59, 78, 47, 32, 24, 44, 86, 64, 57, 12, 23, 109, 107, 85, 63, 31, 65, 62, 68, 111, 78, 104, 89, 112, 87, 69, 105, 65, 94, 109, 78, 72, 104, 85, 108, 77, 106, 79, 74, 103, 96, 64, 105, 105, 102, 63, 35, 59, 108, 112, 81, 102, 57, 106, 83, 81, 77, 101, 55, 94, 96, 97, 106, 46, 101, 83, 85, 71, 107, 104, 87, 33, 67, 103, 95, 30, 91, 89, 103, 75, 51, 107, 87, 91, 89, 99, 68, 52, 109, 99, 88, 84, 112, 54, 70, 92, 100, 98, 74, 60, 100, 98, 110, 90, 73, 71, 95, 70, 100, 29, 69, 110, 93, 82, 97, 98, 77, 73, 99, 101, 108, 82, 102, 111, 110, 111, 97, 88, 80 -}; -const float HRA_112_112_input[] = { --3.7496794787890972, 14.372112019392226, -7.5640452729302359, 6.9426063455159657, 5.3103644888713299, -6.9203550501252273, 8.4296575778653775, 13.495087143587781, 18.111520666852243, -9.9125748623510912, 10.601298534930972, -10.468591112149715, -9.0757329437720475, -14.471433733514324, 5.2048820572852641, -11.353785810284556, -9.4511008284496416, -9.5255219979484025, -2.0499245561876696, -9.8739646459388748, 22.03442141444015, -9.9745566449839878, -8.4276711655946226, -4.9811962116476307, -13.018434575859896, -5.3358535334627293, -5.6704294937789648, 14.243964608060018, -11.417925510314507, 9.1332657371467878, -14.380214782394296, 14.090409878618974, 6.5602278279998272, 15.53025696352436, -9.1752771765906616, -11.384503450560766, 12.240329442222599, -12.640059450058276, -11.824715154614376, -13.487656131954735, 15.38073452845444, -13.816294924566529, 6.3461114450644454, -2.5192445130977559, -11.916088712873863, 5.4360722876642518, 0.038031547223147381, -12.367220238860654, -2.747864039796549, -14.920508782249289, 16.487336720060863, -13.290002442259247, 19.142698450560925, -0.39443060583296108, 11.723442316413736, -3.6131702833965047, -4.6196487103817017, -11.794290650694531, -14.342351103186955, 2.8079943208330334, -15.290175151123936, 9.0801740558512414, 10.184385069676226, 8.400722260237572, 9.3504690108712936, -14.223531676384166, 11.752768386971752, 11.36995822251677, -15.285021241405444, -13.070613695054403, -11.869191325617697, 4.3191750845563401, 2.0836933404582791, -16.363829786416495, -5.7778094839806595, 11.06389861779129, 13.285433846434705, 9.2552396418849021, -11.065999403824057, -10.167040394420443, -7.0107225044503565, 2.3886881673282474, 5.0014484787306932, -9.2464083853314278, -12.043309174487364, -11.638411967211738, -16.302815497922911, 13.347129717938067, -4.1390259986125226, 0.7947480277507295, 11.538620744796759, -7.4410706619926028, 14.572449028311253, 12.392747919231169, -3.3027890746379289, -9.8431096813736687, 11.582657487369399, -7.85736442083219, -7.3780721969188443, -7.4006260265172212, -8.3937994980934327, -6.6804071011469555, 19.656301355404196, 1.1084340389939762, 3.6028635453146465, -4.5409495140900562, 7.3831459854578982, -5.5905999874445662, -13.852328482738232, 8.9999210644983041, 8.4742375282492315, 16.989947243749878, 7.5590035165610168, -6.154674423116183, 4.1119120658251855, 12.351217703790844, 11.070972687846792, 11.182587746846833, -4.9345619923565645, 9.0054892370887334, -10.841725474869696, 13.902796293412067, -6.7575171884905396, -5.8196703210757335, 1.9284357540668857, 9.9905382141440455, -13.983067199220674, -4.9130522479706453, -8.2369300184767908, 6.8953565265629644, 2.9285103862640871, -2.6303471135655325, -8.3563361642086047, 9.5712349244763715, 4.9728623009661161, -11.045088919587242, -5.7781337596219604, -17.732999074602972, 8.1353860976076646, -11.066240843831284, -1.7079574457159534, -16.411685365171998, -9.0471090651358299, -10.959376227315447, 8.5840398495674126, 6.6373658260736024, 11.422094029020409, 14.85785089306844, 13.185747281780415, 4.2063935223916191, -6.9166135608899282, 10.843153262137262, 5.3913075109409441, -10.744469667642237, -12.491640291445655, 14.141118162062066, 16.425476099516025, 9.8833761863476042, 2.8719064151687883, 14.982021915112442, 1.3588165304065343, -11.657839635726177, 11.066314862965077, -3.0565490195476204, 1.7820159270701772, -13.535333311782074, 4.4026933190218367, -11.097334550496313, -11.322820869044248, 16.418516996530371, 5.8239202459876136, 15.054905601216154, -9.3058742038490152, 8.48902767802557, -8.3853534273227748, -7.9255089736435176, -9.6156735881618811, 11.502594413898008, -6.0542015398269911, 7.1229229147355149, 0.31483632310264387, -11.482093481730768, -9.3225703551629309, 5.8001228713062831, -9.3515917458791051, 7.9778737065172969, 9.7095180444854847, -14.060064536791135, 4.9797253221020545, -6.9210799657794224, 6.6736460552213845, -7.7636429824024606, 10.233132490278882, 8.401747393605044, -10.861100567451366, 13.631509744686715, -15.723791754613185, -8.7931294115815923, -9.9520037489001609, -10.312792052906007, -8.0681893911111917, -15.411052087079765, 10.938779471602952, -8.751795633239853, -9.1302029882284419, -2.3357314769649777, -7.9130658335895596, 2.7508172894969509, -9.1666780515772324, 12.793063537524359, -13.39091818112591, 7.2827402370664842, -10.400778532411657, -1.90854156128735, -4.1272702472088971, 12.696932922959466, -4.0180403457213805, 10.828999052972396, 14.720617452742685, -8.3763729074389719, 3.955093172344033, 0.90932711822659873, -5.6696817865337819, -5.8822086115513805 -}; -const char HRA_112_112_detected_data[] = { -1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1 -}; - -} // FreeDV diff --git a/libfreedv/HRA_112_112.h b/libfreedv/HRA_112_112.h deleted file mode 100644 index bc408a2ef..000000000 --- a/libfreedv/HRA_112_112.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - FILE....: HRA_112_112.h - - Static arrays for LDPC codec HRA_112_112, generated by ldpc_gen_c_h_file.m. -*/ - -#define HRA_112_112_NUMBERPARITYBITS 112 -#define HRA_112_112_MAX_ROW_WEIGHT 3 -#define HRA_112_112_CODELENGTH 224 -#define HRA_112_112_NUMBERROWSHCOLS 112 -#define HRA_112_112_MAX_COL_WEIGHT 3 -#define HRA_112_112_DEC_TYPE 0 -#define HRA_112_112_MAX_ITER 100 - -namespace FreeDV -{ - -extern const uint16_t HRA_112_112_H_rows[]; -extern const uint16_t HRA_112_112_H_cols[]; -extern const float HRA_112_112_input[]; -extern const char HRA_112_112_detected_data[]; - -} // FreeDV diff --git a/libfreedv/_kiss_fft_guts.h b/libfreedv/_kiss_fft_guts.h deleted file mode 100644 index 4a89ef6a6..000000000 --- a/libfreedv/_kiss_fft_guts.h +++ /dev/null @@ -1,159 +0,0 @@ -/* -Copyright (c) 2003-2010, Mark Borgerding - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * 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. - * Neither the author nor the names of any 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 OWNER 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. -*/ - -/* kiss_fft.h - defines kiss_fft_scalar as either short or a float type - and defines - typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ -#include "kiss_fft.h" -#include - -#define MAXFACTORS 32 -/* e.g. an fft of length 128 has 4 factors - as far as kissfft is concerned - 4*4*4*2 - */ - -namespace FreeDV -{ - -struct kiss_fft_state{ - int nfft; - int inverse; - int factors[2*MAXFACTORS]; - kiss_fft_cpx twiddles[1]; -}; - -/* - Explanation of macros dealing with complex math: - - C_MUL(m,a,b) : m = a*b - C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise - C_SUB( res, a,b) : res = a - b - C_SUBFROM( res , a) : res -= a - C_ADDTO( res , a) : res += a - * */ -#ifdef FIXED_POINT -#if (FIXED_POINT==32) -# define FRACBITS 31 -# define SAMPPROD int64_t -#define SAMP_MAX 2147483647 -#else -# define FRACBITS 15 -# define SAMPPROD int32_t -#define SAMP_MAX 32767 -#endif - -#define SAMP_MIN -SAMP_MAX - -#if defined(CHECK_OVERFLOW) -# define CHECK_OVERFLOW_OP(a,op,b) \ - if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \ - fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) ); } -#endif - - -# define smul(a,b) ( (SAMPPROD)(a)*(b) ) -# define sround( x ) (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS ) - -# define S_MUL(a,b) sround( smul(a,b) ) - -# define C_MUL(m,a,b) \ - do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \ - (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0) - -# define DIVSCALAR(x,k) \ - (x) = sround( smul( x, SAMP_MAX/k ) ) - -# define C_FIXDIV(c,div) \ - do { DIVSCALAR( (c).r , div); \ - DIVSCALAR( (c).i , div); }while (0) - -# define C_MULBYSCALAR( c, s ) \ - do{ (c).r = sround( smul( (c).r , s ) ) ;\ - (c).i = sround( smul( (c).i , s ) ) ; }while(0) - -#else /* not FIXED_POINT*/ - -# define S_MUL(a,b) ( (a)*(b) ) -#define C_MUL(m,a,b) \ - do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ - (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) -# define C_FIXDIV(c,div) /* NOOP */ -# define C_MULBYSCALAR( c, s ) \ - do{ (c).r *= (s);\ - (c).i *= (s); }while(0) -#endif - -#ifndef CHECK_OVERFLOW_OP -# define CHECK_OVERFLOW_OP(a,op,b) /* noop */ -#endif - -#define C_ADD( res, a,b)\ - do { \ - CHECK_OVERFLOW_OP((a).r,+,(b).r)\ - CHECK_OVERFLOW_OP((a).i,+,(b).i)\ - (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ - }while(0) -#define C_SUB( res, a,b)\ - do { \ - CHECK_OVERFLOW_OP((a).r,-,(b).r)\ - CHECK_OVERFLOW_OP((a).i,-,(b).i)\ - (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ - }while(0) -#define C_ADDTO( res , a)\ - do { \ - CHECK_OVERFLOW_OP((res).r,+,(a).r)\ - CHECK_OVERFLOW_OP((res).i,+,(a).i)\ - (res).r += (a).r; (res).i += (a).i;\ - }while(0) - -#define C_SUBFROM( res , a)\ - do {\ - CHECK_OVERFLOW_OP((res).r,-,(a).r)\ - CHECK_OVERFLOW_OP((res).i,-,(a).i)\ - (res).r -= (a).r; (res).i -= (a).i; \ - }while(0) - - -#ifdef FIXED_POINT -# define KISS_FFT_COS(phase) floorf(.5+SAMP_MAX * cosf (phase)) -# define KISS_FFT_SIN(phase) floorf(.5+SAMP_MAX * sinf (phase)) -# define HALF_OF(x) ((x)>>1) -#elif defined(USE_SIMD) -# define KISS_FFT_COS(phase) _mm_set1_ps( cosf(phase) ) -# define KISS_FFT_SIN(phase) _mm_set1_ps( sinf(phase) ) -# define HALF_OF(x) ((x)*_mm_set1_ps(.5)) -#else -# define KISS_FFT_COS(phase) (kiss_fft_scalar) cosf(phase) -# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sinf(phase) -# define HALF_OF(x) ((x)*.5) -#endif - -#define kf_cexp(x,phase) \ - do{ \ - (x)->r = KISS_FFT_COS(phase);\ - (x)->i = KISS_FFT_SIN(phase);\ - }while(0) - - -/* a debugging function */ -#define pcpx(c)\ - fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) ) - - -#define KISS_FFT_TMP_ALLOC(nbytes) KISS_FFT_MALLOC(nbytes) -#define KISS_FFT_TMP_FREE(ptr) KISS_FFT_FREE(ptr) - -} // FreeDV diff --git a/libfreedv/codec2_cohpsk.h b/libfreedv/codec2_cohpsk.h deleted file mode 100644 index f3b086feb..000000000 --- a/libfreedv/codec2_cohpsk.h +++ /dev/null @@ -1,76 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: codec2_cohpsk.h - AUTHOR......: David Rowe - DATE CREATED: March 2015 - - Functions that implement a coherent PSK FDM modem. - -\*---------------------------------------------------------------------------*/ - -/* - 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 . -*/ - -#ifndef __CODEC2_COHPSK__ -#define __CODEC2_COHPSK__ - -#define COHPSK_BITS_PER_FRAME 56 /* hard coded for now */ -#define COHPSK_NC 7 /* hard coded for now */ -#define COHPSK_NOM_SAMPLES_PER_FRAME 600 -#define COHPSK_MAX_SAMPLES_PER_FRAME 625 -#define COHPSK_RS 75 -#define COHPSK_FS 7500 /* note this is a wierd - value to get an integer - oversampling rate */ -#define COHPSK_CLIP 6.5 /* hard clipping for Nc*Nc=14 to reduce PAPR */ - -#include "codec2/comp.h" -#include "modem_stats.h" - -namespace FreeDV -{ - -struct COHPSK; - -extern const int test_bits_coh[]; - -struct COHPSK *cohpsk_create(void); -void cohpsk_destroy(struct COHPSK *coh); -void cohpsk_mod(struct COHPSK *cohpsk, COMP tx_fdm[], int tx_bits[], int nbits); -void cohpsk_clip(COMP tx_fdm[], float clip_thresh, int n); -void cohpsk_demod(struct COHPSK *cohpsk, float rx_bits[], int *sync, COMP rx_fdm[], int *nin_frame); -void cohpsk_get_demod_stats(struct COHPSK *cohpsk, struct MODEM_STATS *stats); -void cohpsk_set_verbose(struct COHPSK *coh, int verbose); -void cohpsk_get_test_bits(struct COHPSK *coh, int rx_bits[]); -void cohpsk_put_test_bits(struct COHPSK *coh, int *state, short error_pattern[], - int *bit_errors, char rx_bits[], int channel); -int cohpsk_error_pattern_size(void); -void cohpsk_set_frame(struct COHPSK *coh, int frame); -void fdmdv_freq_shift_coh(COMP rx_fdm_fcorr[], COMP rx_fdm[], float foff, float Fs, - COMP *foff_phase_rect, int nin); - -void cohpsk_set_freq_est_mode(struct COHPSK *coh, int used_simple_mode); - -/* used for accessing upper and lower bits before diversity combination */ - -float *cohpsk_get_rx_bits_lower(struct COHPSK *coh); -float *cohpsk_get_rx_bits_upper(struct COHPSK *coh); -void cohpsk_set_carrier_ampl(struct COHPSK *coh, int c, float ampl); - -} // FreeDV - -#endif diff --git a/libfreedv/codec2_fdmdv.h b/libfreedv/codec2_fdmdv.h deleted file mode 100644 index 1a1f5fb7a..000000000 --- a/libfreedv/codec2_fdmdv.h +++ /dev/null @@ -1,110 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: codec2_fdmdv.h - AUTHOR......: David Rowe - DATE CREATED: April 14 2012 - - A 1400 bit/s (nominal) Frequency Division Multiplexed Digital Voice - (FDMDV) modem. Used for digital audio over HF SSB. See - README_fdmdv.txt for more information, and fdmdv_mod.c and - fdmdv_demod.c for example usage. - - The name codec2_fdmdv.h is used to make it unique when "make - installed". - - References: - - [1] http://n1su.com/fdmdv/FDMDV_Docs_Rel_1_4b.pdf - -\*---------------------------------------------------------------------------*/ - -/* - 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 . -*/ - -#ifndef __FDMDV__ -#define __FDMDV__ - -/* set up the calling convention for DLL function import/export for - WIN32 cross compiling */ - -#ifdef __CODEC2_WIN32__ -#ifdef __CODEC2_BUILDING_DLL__ -#define CODEC2_WIN32SUPPORT __declspec(dllexport) __stdcall -#else -#define CODEC2_WIN32SUPPORT __declspec(dllimport) __stdcall -#endif -#else -#define CODEC2_WIN32SUPPORT -#endif - -#include "codec2/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 */ -#define FDMDV_BITS_PER_FRAME 28 /* 20ms frames, for nominal 1400 bit/s */ -#define FDMDV_NOM_SAMPLES_PER_FRAME 160 /* modulator output samples/frame and nominal demod samples/frame */ - /* at 8000 Hz sample rate */ -#define FDMDV_MAX_SAMPLES_PER_FRAME 200 /* max demod samples/frame, use this to allocate storage */ -#define FDMDV_SCALE 1000 /* suggested scaling for 16 bit shorts */ -#define FDMDV_FCENTRE 1500 /* Centre frequency, Nc/2 carriers below this, Nc/2 carriers above (Hz) */ - -/* 8 to 48 kHz sample rate conversion */ - -#define FDMDV_OS 2 /* oversampling rate */ -#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 */ - -namespace FreeDV -{ - -/* FDMDV states and stats structures */ - -struct FDMDV; - -struct FDMDV * fdmdv_create(int Nc); -void fdmdv_destroy(struct FDMDV *fdmdv_state); -void fdmdv_use_old_qpsk_mapping(struct FDMDV *fdmdv_state); -int fdmdv_bits_per_frame(struct FDMDV *fdmdv_state); -float fdmdv_get_fsep(struct FDMDV *fdmdv_state); -void fdmdv_set_fsep(struct FDMDV *fdmdv_state, float fsep); - -void fdmdv_mod(struct FDMDV *fdmdv_state, COMP tx_fdm[], int tx_bits[], int *sync_bit); -void fdmdv_demod(struct FDMDV *fdmdv_state, int rx_bits[], int *reliable_sync_bit, COMP rx_fdm[], int *nin); - -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 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); -void fdmdv_16_to_8(float out8k[], float in16k[], int n); -void fdmdv_16_to_8_short(short out8k[], short in16k[], int n); - -void fdmdv_freq_shift(COMP rx_fdm_fcorr[], COMP rx_fdm[], float foff, COMP *foff_phase_rect, int nin); - -/* debug/development function(s) */ - -void fdmdv_dump_osc_mags(struct FDMDV *f); -void fdmdv_simulate_channel(float *sig_pwr_av, COMP samples[], int nin, float target_snr); - -} // FreeDV - -#endif - diff --git a/libfreedv/codec2_fft.cpp b/libfreedv/codec2_fft.cpp deleted file mode 100644 index a3734694d..000000000 --- a/libfreedv/codec2_fft.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* - * codec2_fft.c - * - * Created on: 24.09.2016 - * Author: danilo - */ - -#include "codec2_fft.h" - -#ifdef USE_KISS_FFT -#include "_kiss_fft_guts.h" -#endif - -namespace FreeDV -{ - -#ifdef USE_KISS_FFT -#else -#if 0 -// caching constants in RAM did not seem to have an effect on performance -// TODO: Decide what to with this code -#define FFT_INIT_CACHE_SIZE 4 -const arm_cfft_instance_f32* fft_init_cache[FFT_INIT_CACHE_SIZE]; - -static const arm_cfft_instance_f32* arm_fft_instance2ram(const arm_cfft_instance_f32* in) -{ - - arm_cfft_instance_f32* out = malloc(sizeof(arm_cfft_instance_f32)); - - if (out) { - memcpy(out,in,sizeof(arm_cfft_instance_f32)); - out->pBitRevTable = malloc(out->bitRevLength * sizeof(uint16_t)); - out->pTwiddle = malloc(out->fftLen * sizeof(float32_t)); - memcpy((void*)out->pBitRevTable,in->pBitRevTable,out->bitRevLength * sizeof(uint16_t)); - memcpy((void*)out->pTwiddle,in->pTwiddle,out->fftLen * sizeof(float32_t)); - } - return out; -} - - -static const arm_cfft_instance_f32* arm_fft_cache_get(const arm_cfft_instance_f32* romfft) -{ - const arm_cfft_instance_f32* retval = NULL; - static int used = 0; - for (int i = 0; fft_init_cache[i] != NULL && i < used; i++) - { - if (romfft->fftLen == fft_init_cache[i]->fftLen) - { - retval = fft_init_cache[i]; - break; - } - } - if (retval == NULL && used < FFT_INIT_CACHE_SIZE) - { - retval = arm_fft_instance2ram(romfft); - fft_init_cache[used++] = retval; - } - if (retval == NULL) - { - retval = romfft; - } - return retval; -} -#endif -#endif - -void codec2_fft_free(codec2_fft_cfg cfg) -{ -#ifdef USE_KISS_FFT - KISS_FFT_FREE(cfg); -#else - FREE(cfg); -#endif -} - -codec2_fft_cfg codec2_fft_alloc(int nfft, int inverse_fft, void* mem, std::size_t* lenmem) -{ - codec2_fft_cfg retval; -#ifdef USE_KISS_FFT - retval = kiss_fft_alloc(nfft, inverse_fft, mem, lenmem); -#else - retval = MALLOC(sizeof(codec2_fft_struct)); - retval->inverse = inverse_fft; - switch(nfft) - { - case 128: - retval->instance = &arm_cfft_sR_f32_len128; - break; - case 256: - retval->instance = &arm_cfft_sR_f32_len256; - break; - case 512: - retval->instance = &arm_cfft_sR_f32_len512; - break; -// case 1024: -// retval->instance = &arm_cfft_sR_f32_len1024; -// break; - default: - abort(); - } - // retval->instance = arm_fft_cache_get(retval->instance); -#endif - return retval; -} - -codec2_fftr_cfg codec2_fftr_alloc(int nfft, int inverse_fft, void* mem, std::size_t* lenmem) -{ - codec2_fftr_cfg retval; -#ifdef USE_KISS_FFT - retval = kiss_fftr_alloc(nfft, inverse_fft, mem, lenmem); -#else - retval = MALLOC(sizeof(codec2_fftr_struct)); - retval->inverse = inverse_fft; - retval->instance = MALLOC(sizeof(arm_rfft_fast_instance_f32)); - arm_rfft_fast_init_f32(retval->instance,nfft); - // memcpy(&retval->instance->Sint,arm_fft_cache_get(&retval->instance->Sint),sizeof(arm_cfft_instance_f32)); -#endif - return retval; -} -void codec2_fftr_free(codec2_fftr_cfg cfg) -{ -#ifdef USE_KISS_FFT - KISS_FFT_FREE(cfg); -#else - FREE(cfg->instance); - FREE(cfg); -#endif -} - -// there is a little overhead for inplace kiss_fft but this is -// on the powerful platforms like the Raspberry or even x86 PC based ones -// not noticeable -// the reduced usage of RAM and increased performance on STM32 platforms -// should be worth it. -void codec2_fft_inplace(codec2_fft_cfg cfg, codec2_fft_cpx* inout) -{ - -#ifdef USE_KISS_FFT - kiss_fft_cpx in[512]; - // decide whether to use the local stack based buffer for in - // or to allow kiss_fft to allocate RAM - // second part is just to play safe since first method - // is much faster and uses less RAM - if (cfg->nfft <= 512) - { - memcpy(in,inout,cfg->nfft*sizeof(kiss_fft_cpx)); - kiss_fft(cfg, in, (kiss_fft_cpx*)inout); - } - else - { - kiss_fft(cfg, (kiss_fft_cpx*)inout, (kiss_fft_cpx*)inout); - } -#else - arm_cfft_f32(cfg->instance,(float*)inout,cfg->inverse,1); - if (cfg->inverse) - { - arm_scale_f32((float*)inout,cfg->instance->fftLen,(float*)inout,cfg->instance->fftLen*2); - } - -#endif -} - -} // FreeDV diff --git a/libfreedv/codec2_fft.h b/libfreedv/codec2_fft.h deleted file mode 100644 index 56f1ae422..000000000 --- a/libfreedv/codec2_fft.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * codec2_fft.h - * - * Created on: 17.09.2016 - * Author: danilo - */ - -#ifndef DRIVERS_FREEDV_CODEC2_FFT_H_ -#define DRIVERS_FREEDV_CODEC2_FFT_H_ - -#include -#include -#include -#include -#include -#include - -#include "codec2/comp.h" -#include "defines.h" -#include "kiss_fftr.h" - -#ifdef FDV_ARM_MATH - #include "fdv_arm_math.h" -#else - #define USE_KISS_FFT -#endif - -#ifdef USE_KISS_FFT - #include "kiss_fft.h" -#endif - -namespace FreeDV -{ - -typedef COMP codec2_fft_cpx; - -#ifdef USE_KISS_FFT - typedef kiss_fftr_cfg codec2_fftr_cfg; - typedef kiss_fft_cfg codec2_fft_cfg; - typedef kiss_fft_scalar codec2_fft_scalar; -#else - typedef float32_t codec2_fft_scalar; - typedef struct { - arm_rfft_fast_instance_f32* instance; - int inverse; - } codec2_fftr_struct; - - typedef codec2_fftr_struct* codec2_fftr_cfg; - - typedef struct { - const arm_cfft_instance_f32* instance; - int inverse; - } codec2_fft_struct; - typedef codec2_fft_struct* codec2_fft_cfg; -#endif - -static inline void codec2_fftr(codec2_fftr_cfg cfg, codec2_fft_scalar* in, codec2_fft_cpx* out) -{ -#ifdef USE_KISS_FFT - kiss_fftr(cfg, in, (kiss_fft_cpx*)out); -#else - arm_rfft_fast_f32(cfg->instance,in,(float*)out,cfg->inverse); - out->imag = 0; // remove out[FFT_ENC/2]->real stored in out[0].imag -#endif -} - -static inline void codec2_fftri(codec2_fftr_cfg cfg, codec2_fft_cpx* in, codec2_fft_scalar* out) -{ -#ifdef USE_KISS_FFT - kiss_fftri(cfg, (kiss_fft_cpx*)in, out); -#else - arm_rfft_fast_f32(cfg->instance,(float*)in,out,cfg->inverse); - // arm_scale_f32(out,cfg->instance->fftLenRFFT,out,cfg->instance->fftLenRFFT); -#endif - -} - -codec2_fft_cfg codec2_fft_alloc(int nfft, int inverse_fft, void* mem, std::size_t* lenmem); -codec2_fftr_cfg codec2_fftr_alloc(int nfft, int inverse_fft, void* mem, std::size_t* lenmem); -void codec2_fft_free(codec2_fft_cfg cfg); -void codec2_fftr_free(codec2_fftr_cfg cfg); - - -static inline void codec2_fft(codec2_fft_cfg cfg, codec2_fft_cpx* in, codec2_fft_cpx* out) -{ - -#ifdef USE_KISS_FFT - kiss_fft(cfg, (kiss_fft_cpx*)in, (kiss_fft_cpx*)out); -#else - memcpy(out,in,cfg->instance->fftLen*2*sizeof(float)); - arm_cfft_f32(cfg->instance,(float*)out,cfg->inverse,0); - // TODO: this is not nice, but for now required to keep changes minimal - // however, since main goal is to reduce the memory usage - // we should convert to an in place interface - // on PC like platforms the overhead of using the "inplace" kiss_fft calls - // is neglectable compared to the gain in memory usage on STM32 platforms - if (cfg->inverse) - { - arm_scale_f32((float*)out,cfg->instance->fftLen,(float*)out,cfg->instance->fftLen*2); - } -#endif -} - -void codec2_fft_inplace(codec2_fft_cfg cfg, codec2_fft_cpx* inout); - -} // FreeDV - -#endif diff --git a/libfreedv/codec2_ofdm.h b/libfreedv/codec2_ofdm.h deleted file mode 100644 index 21a09fbae..000000000 --- a/libfreedv/codec2_ofdm.h +++ /dev/null @@ -1,101 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: codec2_ofdm.h - AUTHORS.....: David Rowe & Steve Sampson - DATE CREATED: June 2017 - - External user references to the modem library. - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2017 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 . -*/ - -#ifndef CODEC2_OFDM_H -#define CODEC2_OFDM_H - -/* Includes */ - -#include -#include -#include - -#include "codec2/comp.h" -#include "modem_stats.h" - -/* Defines */ - -#define OFDM_AMP_SCALE (2E5*1.1491/1.06) /* use to scale to 16 bit short */ -#define OFDM_CLIP (32767*0.35) /* experimentally derived constant to reduce PAPR to about 8dB */ - -namespace FreeDV -{ - -struct OFDM_CONFIG; -struct OFDM; - -typedef enum { - search, - trial, - synced -} State; - -typedef enum { - unsync, /* force sync state machine to lose sync, and search for new sync */ - autosync, /* falls out of sync automatically */ - manualsync /* fall out of sync only under operator control */ -} Sync; - -/* create and destroy modem states */ - -struct OFDM *ofdm_create(const struct OFDM_CONFIG * config); -void ofdm_destroy(struct OFDM *); - -/* signal processing */ - -void ofdm_mod(struct OFDM *, COMP *, const int *); -void ofdm_demod(struct OFDM *, int *, COMP *); -void ofdm_demod_shorts(struct OFDM *, int *, short *, float); -int ofdm_sync_search(struct OFDM *, COMP *); -int ofdm_sync_search_shorts(struct OFDM *, short *, float); -void ofdm_sync_state_machine(struct OFDM *, uint8_t *); - -/* getters */ - -struct OFDM_CONFIG *ofdm_get_config_param(void); -int ofdm_get_nin(struct OFDM *); -int ofdm_get_samples_per_frame(void); -int ofdm_get_max_samples_per_frame(void); -int ofdm_get_bits_per_frame(void); -void ofdm_get_demod_stats(struct OFDM *ofdm, struct MODEM_STATS *stats); - -/* option setters */ - -void ofdm_set_verbose(struct OFDM *, int); -void ofdm_set_timing_enable(struct OFDM *, bool); -void ofdm_set_foff_est_enable(struct OFDM *, bool); -void ofdm_set_phase_est_enable(struct OFDM *, bool); -void ofdm_set_off_est_hz(struct OFDM *, float); -void ofdm_set_sync(struct OFDM *, Sync); -void ofdm_set_tx_bpf(struct OFDM *, bool); - -void ofdm_print_info(struct OFDM *); - -} // FreeDV - -#endif - diff --git a/libfreedv/cohpsk.cpp b/libfreedv/cohpsk.cpp deleted file mode 100644 index 346e2c8f4..000000000 --- a/libfreedv/cohpsk.cpp +++ /dev/null @@ -1,1394 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: cohpsk.c - AUTHOR......: David Rowe - DATE CREATED: March 2015 - - Functions that implement a coherent PSK FDM modem. - -\*---------------------------------------------------------------------------*/ - -/* - 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 . -*/ - -/*---------------------------------------------------------------------------*\ - - INCLUDES - -\*---------------------------------------------------------------------------*/ - -#include -#include -#include -#include -#include - -#include "codec2_cohpsk.h" -#include "cohpsk_defs.h" -#include "cohpsk_internal.h" -#include "fdmdv_internal.h" -#include "pilots_coh.h" -#include "comp_prim.h" -#include "kiss_fft.h" -#include "linreg.h" -#include "rn_coh.h" -#include "test_bits_coh.h" - -namespace FreeDV -{ - -static COMP qpsk_mod[] = { - { 1.0, 0.0}, - { 0.0, 1.0}, - { 0.0,-1.0}, - {-1.0, 0.0} -}; - -static int sampling_points[] = {0, 1, 6, 7}; - -void corr_with_pilots_comp(float *corr_out, float *mag_out, struct COHPSK *coh, int t, COMP f_fine); -void update_ct_symb_buf(COMP ct_symb_buf[][COHPSK_NC*ND], COMP ch_symb[][COHPSK_NC*ND]); - -/*---------------------------------------------------------------------------*\ - - FUNCTIONS - -\*---------------------------------------------------------------------------*/ - - -/*--------------------------------------------------------------------------* \ - - FUNCTION....: cohpsk_create - AUTHOR......: David Rowe - DATE CREATED: Marcg 2015 - - 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. - -\*---------------------------------------------------------------------------*/ - -struct COHPSK *cohpsk_create(void) -{ - struct COHPSK *coh; - struct FDMDV *fdmdv; - int r,c,p,i; - float freq_hz; - - assert(COHPSK_NC == PILOTS_NC); - assert(COHPSK_NOM_SAMPLES_PER_FRAME == (COHPSK_M*NSYMROWPILOT)); - assert(COHPSK_MAX_SAMPLES_PER_FRAME == (COHPSK_M*NSYMROWPILOT+COHPSK_M/P)); - assert(COHPSK_ND == ND); - assert(COHPSK_NSYM == NSYM); /* as we want to use the tx sym mem on fdmdv */ - assert(COHPSK_NT == NT); - - coh = (struct COHPSK*) malloc(sizeof(struct COHPSK)); - if (coh == NULL) - return NULL; - - /* set up buffer of tx pilot symbols for coh demod on rx */ - - for(r=0; r<2*NPILOTSFRAME; ) { - for(p=0; ppilot2[r][c] = pilots_coh[p][c]; - } - } - } - - /* Clear symbol buffer memory */ - - for (r=0; rct_symb_buf[r][c].real = 0.0; - coh->ct_symb_buf[r][c].imag = 0.0; - } - } - - coh->ff_phase.real = 1.0; coh->ff_phase.imag = 0.0; - coh->sync = 0; - coh->frame = 0; - coh->ratio = 0.0; - coh->nin = COHPSK_M; - - /* clear sync window buffer */ - - for (i=0; ich_fdm_frame_buf[i].real = 0.0; - coh->ch_fdm_frame_buf[i].imag = 0.0; - } - - /* set up fdmdv states so we can use those modem functions */ - - fdmdv = fdmdv_create(COHPSK_NC*ND - 1); - fdmdv->fsep = COHPSK_RS*(1.0 + COHPSK_EXCESS_BW); - for(c=0; cphase_tx[c].real = 1.0; - fdmdv->phase_tx[c].imag = 0.0; - - /* note non-linear carrier spacing to help PAPR, works v well in conjunction with CLIP */ - - freq_hz = fdmdv->fsep*( -(COHPSK_NC*ND)/2 - 0.5 + pow(c + 1.0, 0.98) ); - - fdmdv->freq[c].real = cosf(2.0*M_PI*freq_hz/COHPSK_FS); - fdmdv->freq[c].imag = sinf(2.0*M_PI*freq_hz/COHPSK_FS); - fdmdv->freq_pol[c] = 2.0*M_PI*freq_hz/COHPSK_FS; - - //printf("c: %d %f %f\n",c,freq_hz,fdmdv->freq_pol[c]); - for(i=0; irx_filter_memory[c][i].real = 0.0; - coh->rx_filter_memory[c][i].imag = 0.0; - } - - /* optional per-carrier amplitude weighting for testing */ - - coh->carrier_ampl[c] = 1.0; - } - fdmdv->fbb_rect.real = cosf(2.0*PI*FDMDV_FCENTRE/COHPSK_FS); - fdmdv->fbb_rect.imag = sinf(2.0*PI*FDMDV_FCENTRE/COHPSK_FS); - fdmdv->fbb_pol = 2.0*PI*FDMDV_FCENTRE/COHPSK_FS; - - coh->fdmdv = fdmdv; - - coh->sig_rms = coh->noise_rms = 0.0; - - for(c=0; crx_symb[r][c].real = 0.0; - coh->rx_symb[r][c].imag = 0.0; - } - } - - coh->verbose = 0; - - /* disable optional logging by default */ - - coh->rx_baseband_log = NULL; - coh->rx_baseband_log_col_index = 0; - coh->rx_filt_log = NULL; - coh->rx_filt_log_col_index = 0; - coh->ch_symb_log = NULL; - coh->ch_symb_log_r = 0; - coh->rx_timing_log = NULL; - coh->rx_timing_log_index = 0; - - /* test frames */ - - coh->ptest_bits_coh_tx = coh->ptest_bits_coh_rx[0] = coh->ptest_bits_coh_rx[1] = (int*)test_bits_coh; - coh->ptest_bits_coh_end = (int*)test_bits_coh + sizeof(test_bits_coh)/sizeof(int); - - /* Disable 'reduce' frequency estimation mode */ - coh->freq_est_mode_reduced = 0; - - return coh; -} - - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: cohpsk_destroy - AUTHOR......: David Rowe - DATE CREATED: March 2015 - - Destroy an instance of the modem. - -\*---------------------------------------------------------------------------*/ - -void cohpsk_destroy(struct COHPSK *coh) -{ - assert(coh != NULL); - fdmdv_destroy(coh->fdmdv); - free(coh); -} - - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: bits_to_qpsk_symbols() - AUTHOR......: David Rowe - DATE CREATED: March 2015 - - Rate Rs modulator. Maps bits to parallel DQPSK symbols and inserts pilot symbols. - -\*---------------------------------------------------------------------------*/ - -void bits_to_qpsk_symbols(COMP tx_symb[][COHPSK_NC*ND], int tx_bits[], int nbits) -{ - int i, r, c, p_r, data_r, d, diversity; - short bits; - - /* check allowed number of bits supplied matches number of QPSK - symbols in the frame */ - - assert( (NSYMROW*COHPSK_NC*2 == nbits) || (NSYMROW*COHPSK_NC*2*ND == nbits)); - - /* if we input twice as many bits we don't do diversity */ - - if (NSYMROW*COHPSK_NC*2 == nbits) { - diversity = 1; /* diversity mode */ - } - else { - diversity = 2; /* twice as many bits, non diversity mode */ - } - - /* - Insert two rows of Nc pilots at beginning of data frame. - - Organise QPSK symbols into a NSYMBROWS rows by PILOTS_NC*ND cols matrix, - each column is a carrier, time flows down the cols...... - - Note: the "& 0x1" prevents and non binary tx_bits[] screwing up - our lives. Call me defensive. - - sqrtf(ND) term ensures the same energy/symbol for different - diversity factors. - */ - - r = 0; - for(p_r=0; p_r<2; p_r++) { - for(c=0; cpilot2[p][pc], ct_symb_buf[sampling_points[p]][c]); - } - - linreg(&m, &b, x, y, NPILOTSFRAME+2); - for(r=0; rphi_[r][c] = atan2(yfit.imag, yfit.real); - } - - /* amplitude estimation */ - - mag = 0.0; - for(p=0; pamp_[r][c] = amp_; - } - } - - /* now correct phase of data symbols */ - - for(c=0; cphi_[r][c]); phi_rect.imag = -sinf(coh->phi_[r][c]); - coh->rx_symb[r][c] = cmult(ct_symb_buf[NPILOTSFRAME + r][c], phi_rect); - i = c*NSYMROW + r; - rx_symb_linear[i] = coh->rx_symb[r][c]; - } - } - - /* and finally optional diversity combination, note output is soft decn a "1" is < 0 */ - - for(c=0; crx_symb[r][c]; - for (d=1; drx_symb[r][c + COHPSK_NC*d]); - } - rot = cmult(div_symb, pi_on_4); - i = c*NSYMROW + r; - rx_bits[2*i+1] = rot.real; - rx_bits[2*i] = rot.imag; - - /* demodulate bits from upper and lower carriers separately for test purposes */ - - assert(ND == 2); - - i = c*NSYMROW + r; - rot = cmult(coh->rx_symb[r][c], pi_on_4); - coh->rx_bits_lower[2*i+1] = rot.real; - coh->rx_bits_lower[2*i] = rot.imag; - rot = cmult(coh->rx_symb[r][c + COHPSK_NC], pi_on_4); - coh->rx_bits_upper[2*i+1] = rot.real; - coh->rx_bits_upper[2*i] = rot.imag; - } - } - - - /* estimate RMS signal and noise */ - - mag = 0.0; - for(i=0; isig_rms = mag/(NSYMROW*COHPSK_NC*ND); - - sum_x = 0; - sum_xx = 0; - n = 0; - for (i=0; i coh->sig_rms) { - sum_x += s.imag; - sum_xx += s.imag*s.imag; - n++; - } - } - - noise_var = 0; - if (n > 1) { - noise_var = (n*sum_xx - sum_x*sum_x)/(n*(n-1)); - } - coh->noise_rms = sqrtf(noise_var); - -} - - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: tx_filter_and_upconvert_coh() - AUTHOR......: David Rowe - DATE CREATED: May 2015 - - Given NC symbols construct M samples (1 symbol) of NC filtered - and upconverted symbols. - - TODO: work out a way to merge with fdmdv version, e.g. run time define M/NSYM, - and run unittests on fdmdv and cohpsk modem afterwards. - -\*---------------------------------------------------------------------------*/ - -void tx_filter_and_upconvert_coh(COMP tx_fdm[], int Nc,const COMP tx_symbols[], - COMP tx_filter_memory[COHPSK_NC*ND][COHPSK_NSYM], - COMP phase_tx[], COMP freq[], - COMP *fbb_phase, COMP fbb_rect) -{ - int c; - int i,j,k; - COMP gain; - COMP tx_baseband; - COMP two = {2.0, 0.0}; - float mag; - - gain.real = sqrtf(2.0)/2.0; - gain.imag = 0.0; - - for(i=0; ireal /= mag; - fbb_phase->imag /= mag; - - /* shift memory, inserting zeros at end */ - - for(i=0; ict_symb_buf[t+sampling_points[p]][c]); - pc = c % COHPSK_NC; - acorr = cadd(acorr, fcmult(coh->pilot2[p][pc], f_corr)); - mag += cabsolute(f_corr); - } - corr += cabsolute(acorr); - } - - *corr_out = corr; - *mag_out = mag; -} - - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: frame_sync_fine_freq_est() - AUTHOR......: David Rowe - DATE CREATED: April 2015 - - Returns an estimate of frame sync (coarse timing) offset and fine - frequency offset, advances to next sync state if we have a reliable - match for frame sync. - -\*---------------------------------------------------------------------------*/ - -void frame_sync_fine_freq_est(struct COHPSK *coh, COMP ch_symb[][COHPSK_NC*ND], int sync, int *next_sync) -{ - int t; - float f_fine, mag, max_corr, max_mag, corr, delta_f_fine, f_fine_range ; - COMP f_fine_d_ph; - - if(coh->freq_est_mode_reduced){ - delta_f_fine = 1.3; - f_fine_range = 10; - }else{ - delta_f_fine = .25; - f_fine_range = 20; - } - - /* Represent f_fine scan as delta2-phase */ - const COMP f_fine_d2_ph = comp_exp_j(2*M_PI*delta_f_fine/COHPSK_RS); - - f_fine = -f_fine_range; - - update_ct_symb_buf(coh->ct_symb_buf, ch_symb); - /* sample pilots at start of this frame and start of next frame */ - - if (sync == 0) { - - /* Represent f_fine as complex delta-phase instead of frequency */ - f_fine_d_ph = comp_exp_j(2*M_PI*f_fine/COHPSK_RS); - - - /* sample correlation over 2D grid of time and fine freq points */ - max_corr = max_mag = 0; - for (f_fine=-f_fine_range; f_fine<=f_fine_range; f_fine+=delta_f_fine) { - for (t=0; t= max_corr) { - max_corr = corr; - max_mag = mag; - coh->ct = t; - coh->f_fine_est = f_fine; - } - } - /* Advance f_fine */ - f_fine_d_ph = cmult(f_fine_d_ph,f_fine_d2_ph); - } - - - coh->ff_rect.real = cosf(coh->f_fine_est*2.0*M_PI/COHPSK_RS); - coh->ff_rect.imag = -sinf(coh->f_fine_est*2.0*M_PI/COHPSK_RS); - if (coh->verbose) - fprintf(stderr, " [%d] fine freq f: %6.2f max_ratio: %f ct: %d\n", coh->frame, (double)coh->f_fine_est, (double)(max_corr/max_mag), coh->ct); - - if (max_corr/max_mag > 0.9) { - if (coh->verbose) - fprintf(stderr, " [%d] encouraging sync word!\n", coh->frame); - coh->sync_timer = 0; - *next_sync = 1; - } - else { - *next_sync = 0; - } - coh->ratio = max_corr/max_mag; - } -} - - -void update_ct_symb_buf(COMP ct_symb_buf[][COHPSK_NC*ND], COMP ch_symb[][COHPSK_NC*ND]) -{ - int r, c, i; - - /* update memory in symbol buffer */ - - for(r=0; rct, comp_exp_j(2*M_PI*coh->f_fine_est/COHPSK_RS)); - coh->ratio = fabsf(corr)/mag; - - // printf("%f\n", cabsolute(corr)/mag); - - if (fabsf(corr)/mag < 0.8) - coh->sync_timer++; - else - coh->sync_timer = 0; - - if (coh->sync_timer == 10) { - if (coh->verbose) - fprintf(stderr," [%d] lost sync ....\n", coh->frame); - next_sync = 0; - } - } - - sync = next_sync; - - return sync; -} - - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: cohpsk_mod() - AUTHOR......: David Rowe - DATE CREATED: 5/4/2015 - - COHPSK modulator, take a frame of COHPSK_BITS_PER_FRAME or - 2*COHPSK_BITS_PER_FRAME bits and generates a frame of - COHPSK_NOM_SAMPLES_PER_FRAME modulated symbols. - - if nbits == COHPSK_BITS_PER_FRAME, diveristy mode is used, if nbits - == 2*COHPSK_BITS_PER_FRAME diversity mode is not used. - - The output signal is complex to support single sided frequency - shifting, for example when testing frequency offsets in channel - simulation. - -\*---------------------------------------------------------------------------*/ - -void cohpsk_mod(struct COHPSK *coh, COMP tx_fdm[], int tx_bits[], int nbits) -{ - struct FDMDV *fdmdv = coh->fdmdv; - COMP tx_symb[NSYMROWPILOT][COHPSK_NC*ND]; - COMP tx_onesym[COHPSK_NC*ND]; - int r,c; - - bits_to_qpsk_symbols(tx_symb, tx_bits, nbits); - - for(r=0; rcarrier_ampl[c], tx_symb[r][c]); - tx_filter_and_upconvert_coh(&tx_fdm[r*COHPSK_M], COHPSK_NC*ND , tx_onesym, fdmdv->tx_filter_memory, - fdmdv->phase_tx, fdmdv->freq, &fdmdv->fbb_phase_tx, fdmdv->fbb_rect); - } -} - - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: cohpsk_clip() - AUTHOR......: David Rowe - DATE CREATED: May 2015 - - Hard clips a cohpsk modulator signal to improve PAPR, CLIP threshold - hard coded and will need to be changed if NC*ND does. - -\*---------------------------------------------------------------------------*/ - -void cohpsk_clip(COMP tx_fdm[], float clip_thresh, int n) -{ - COMP sam; - float mag; - int i; - - for(i=0; i clip_thresh) { - sam = fcmult(clip_thresh/mag, sam); - } - tx_fdm[i] = sam; - } - } - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: fdm_downconvert_coh - AUTHOR......: David Rowe - DATE CREATED: May 2015 - - Frequency shift each modem carrier down to NC baseband signals. - - TODO: try to combine with fdmdv version, carefully re-test fdmdv modem. - -\*---------------------------------------------------------------------------*/ - -void fdm_downconvert_coh(COMP rx_baseband[COHPSK_NC][COHPSK_M+COHPSK_M/P], int Nc, COMP rx_fdm[], COMP phase_rx[], COMP freq[], int nin) -{ - int i,c; - float mag; - - /* maximum number of input samples to demod */ - - assert(nin <= (COHPSK_M+COHPSK_M/P)); - - /* downconvert */ - - for (c=0; creal /= mag; - foff_phase_rect->imag /= mag; -} - - -void rate_Fs_rx_processing(struct COHPSK *coh, COMP ch_symb[][COHPSK_NC*ND], COMP ch_fdm_frame[], float *f_est, int nsymb, int nin, int freq_track) -{ - struct FDMDV *fdmdv = coh->fdmdv; - int r, c, i, ch_fdm_frame_index; - COMP rx_fdm_frame_bb[COHPSK_M+COHPSK_M/P]; - COMP rx_baseband[COHPSK_NC*ND][COHPSK_M+COHPSK_M/P]; - COMP rx_filt[COHPSK_NC*ND][P+1]; - float env[NT*P], rx_timing; - COMP rx_onesym[COHPSK_NC*ND]; - float beta, g; - COMP adiff, amod_strip, mod_strip; - - ch_fdm_frame_index = 0; - rx_timing = 0; - - for (r=0; rfbb_phase_rx, nin); - ch_fdm_frame_index += nin; - fdm_downconvert_coh(rx_baseband, COHPSK_NC*ND, rx_fdm_frame_bb, fdmdv->phase_rx, fdmdv->freq, nin); - rx_filter_coh(rx_filt, COHPSK_NC*ND, rx_baseband, coh->rx_filter_memory, nin); - rx_timing = rx_est_timing(rx_onesym, fdmdv->Nc, rx_filt, fdmdv->rx_filter_mem_timing, env, nin, COHPSK_M); - - for(c=0; cNc+1; c++) { - //printf("rx_onesym[%d] %f %f prev_rx_symbols[%d] %f %f\n", c, rx_onesym[c].real, rx_onesym[c].imag, - // fdmdv->prev_rx_symbols[c].real, fdmdv->prev_rx_symbols[c].imag); - adiff = cmult(rx_onesym[c], cconj(fdmdv->prev_rx_symbols[c])); - fdmdv->prev_rx_symbols[c] = rx_onesym[c]; - - /* 4th power strips QPSK modulation, by multiplying phase by 4 - Using the abs value of the real coord was found to help - non-linear issues when noise power was large. */ - - amod_strip = cmult(adiff, adiff); - amod_strip = cmult(amod_strip, amod_strip); - amod_strip.real = fabsf(amod_strip.real); - mod_strip = cadd(mod_strip, amod_strip); - } - //printf("modstrip: %f %f\n", mod_strip.real, mod_strip.imag); - - /* loop filter made up of 1st order IIR plus integrator. Integerator - was found to be reqd */ - - fdmdv->foff_filt = (1.0-beta)*fdmdv->foff_filt + beta*atan2(mod_strip.imag, mod_strip.real); - //printf("foff_filt: %f angle: %f\n", fdmdv->foff_filt, atan2(mod_strip.imag, mod_strip.real)); - *f_est += g*fdmdv->foff_filt; - } - - /* Optional logging used for testing against Octave version */ - - if (coh->rx_baseband_log) { - assert(nin <= (COHPSK_M+COHPSK_M/P)); - for(c=0; crx_baseband_log[c*coh->rx_baseband_log_col_sz + coh->rx_baseband_log_col_index + i] = rx_baseband[c][i]; - } - } - coh->rx_baseband_log_col_index += nin; - assert(coh->rx_baseband_log_col_index <= coh->rx_baseband_log_col_sz); - } - - if (coh->rx_filt_log) { - for(c=0; crx_filt_log[c*coh->rx_filt_log_col_sz + coh->rx_filt_log_col_index + i] = rx_filt[c][i]; - } - } - coh->rx_filt_log_col_index += nin/(COHPSK_M/P); - } - - if (coh->ch_symb_log) { - for(c=0; cch_symb_log[coh->ch_symb_log_r*COHPSK_NC*ND + c] = ch_symb[r][c]; - } - coh->ch_symb_log_r++; - } - - if (coh->rx_timing_log) { - coh->rx_timing_log[coh->rx_timing_log_index] = rx_timing; - coh->rx_timing_log_index++; - //printf("rx_timing_log_index: %d\n", coh->rx_timing_log_index); - } - - /* we only allow a timing shift on one symbol per frame */ - - if (nin != COHPSK_M) - nin = COHPSK_M; - } - - coh->rx_timing = rx_timing; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: cohpsk_set_freq_est_mode() - AUTHOR......: Brady O'Brien - DATE CREATED: 12 Dec 2017 - - Enables or disables a 'simple' frequency estimation mode. Simple frequency - estimation uses substantially less CPU when cohpsk modem is not sunk than - default mode, but may take many frames to sync. - -\*---------------------------------------------------------------------------*/ -void cohpsk_set_freq_est_mode(struct COHPSK *coh, int use_simple_mode){ - if(use_simple_mode){ - coh->freq_est_mode_reduced = 1; - }else{ - coh->freq_est_mode_reduced = 0; - } -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: cohpsk_demod() - AUTHOR......: David Rowe - DATE CREATED: 5/4/2015 - - COHPSK demodulator, takes an array of (nominally) nin_frame = - COHPSK_NOM_SAMPLES_PER_FRAME modulated samples, returns an array of - COHPSK_BITS_PER_FRAME bits. - - The input signal is complex to support single sided frequency shifting - before the demod input (e.g. click to tune feature). - -\*---------------------------------------------------------------------------*/ - -void cohpsk_demod(struct COHPSK *coh, float rx_bits[], int *sync_good, COMP rx_fdm[], int *nin_frame) -{ - COMP ch_symb[NSW*NSYMROWPILOT][COHPSK_NC*ND]; - int i, j, sync, anext_sync, next_sync, nin, r, c, ns_done; - float max_ratio, f_est; - - assert(*nin_frame <= COHPSK_MAX_SAMPLES_PER_FRAME); - - next_sync = sync = coh->sync; - - for (i=0; ich_fdm_frame_buf[i] = coh->ch_fdm_frame_buf[i+*nin_frame]; - //printf("nin_frame: %d i: %d i+nin_frame: %d\n", *nin_frame, i, i+*nin_frame); - for (j=0; ich_fdm_frame_buf[i] = rx_fdm[j]; - //printf("i: %d j: %d rx_fdm[0]: %f %f\n", i,j, rx_fdm[0].real, rx_fdm[0].imag); - - /* if out of sync do Initial Freq offset estimation using NSW frames to flush out filter memories */ - - if (sync == 0) { - - - max_ratio = 0.0; - f_est = 0.0; - - coh->f_est -= 20; - if(coh->f_est < FDMDV_FCENTRE - 60.0){ - coh->f_est = FDMDV_FCENTRE + 60; - } - - if(!coh->freq_est_mode_reduced){ - coh->f_est = FDMDV_FCENTRE-40.0; - } - - ns_done = 0; - //for (coh->f_est = FDMDV_FCENTRE-40.0; coh->f_est <= FDMDV_FCENTRE+40.0; coh->f_est += 40.0) - while(!ns_done){ - - /* Use slower freq estimator; only do one chunk of freq range */ - if(coh->freq_est_mode_reduced){ - coh->f_est -= 20; - if(coh->f_est < FDMDV_FCENTRE - 60.0){ - coh->f_est = FDMDV_FCENTRE + 60; - } - ns_done = 1; - }else{ - /* we can test +/- 20Hz, so we break this up into 3 tests to cover +/- 60Hz */ - if(coh->f_est > FDMDV_FCENTRE+40.0) ns_done = 1; - } - - if (coh->verbose) - fprintf(stderr, " [%d] acohpsk.f_est: %f +/- 20\n", coh->frame, (double)coh->f_est); - - /* we are out of sync so reset f_est and process two frames to clean out memories */ - - rate_Fs_rx_processing(coh, ch_symb, coh->ch_fdm_frame_buf, &coh->f_est, NSW*NSYMROWPILOT, COHPSK_M, 0); - for (i=0; ict_symb_buf, &ch_symb[i*NSYMROWPILOT]); - } - frame_sync_fine_freq_est(coh, &ch_symb[(NSW-1)*NSYMROWPILOT], sync, &anext_sync); - - if (anext_sync == 1) { - //printf(" [%d] acohpsk.ratio: %f\n", f, coh->ratio); - if (coh->ratio > max_ratio) { - max_ratio = coh->ratio; - f_est = coh->f_est - coh->f_fine_est; - next_sync = anext_sync; - } - } - - if(!coh->freq_est_mode_reduced){ - coh->f_est += 40; - } - } - - if (next_sync == 1) { - - /* we've found a sync candidate! - re-process last NSW frames with adjusted f_est then check again */ - - coh->f_est = f_est; - - if (coh->verbose) - fprintf(stderr, " [%d] trying sync and f_est: %f\n", coh->frame, (double)coh->f_est); - - rate_Fs_rx_processing(coh, ch_symb, coh->ch_fdm_frame_buf, &coh->f_est, NSW*NSYMROWPILOT, COHPSK_M, 0); - for (i=0; ict_symb_buf, &ch_symb[i*NSYMROWPILOT]); - } - /* - for(i=0; ict_symb_buf[i][0].real, coh->ct_symb_buf[i][0].imag); - } - */ - frame_sync_fine_freq_est(coh, &ch_symb[(NSW-1)*NSYMROWPILOT], sync, &next_sync); - - if (fabs(coh->f_fine_est) > 2.0) { - if (coh->verbose) - fprintf(stderr, " [%d] Hmm %f is a bit big :(\n", coh->frame, (double)coh->f_fine_est); - next_sync = 0; - } - } - - if (next_sync == 1) { - /* OK we are in sync! - demodulate first frame (demod completed below) */ - - if (coh->verbose) - fprintf(stderr, " [%d] in sync! f_est: %f ratio: %f \n", coh->frame, (double)coh->f_est, (double)coh->ratio); - for(r=0; rct_symb_ff_buf[r][c] = coh->ct_symb_buf[coh->ct+r][c]; - } - } - - /* If in sync just do sample rate processing on latest frame */ - - if (sync == 1) { - rate_Fs_rx_processing(coh, ch_symb, rx_fdm, &coh->f_est, NSYMROWPILOT, coh->nin, 1); - frame_sync_fine_freq_est(coh, ch_symb, sync, &next_sync); - - for(r=0; r<2; r++) - for(c=0; cct_symb_ff_buf[r][c] = coh->ct_symb_ff_buf[r+NSYMROWPILOT][c]; - for(; rct_symb_ff_buf[r][c] = coh->ct_symb_buf[coh->ct+r][c]; - } - - /* if we are in sync complete demodulation with symbol rate processing */ - - *sync_good = 0; - if ((next_sync == 1) || (sync == 1)) { - qpsk_symbols_to_bits(coh, rx_bits, coh->ct_symb_ff_buf); - *sync_good = 1; - } - - sync = sync_state_machine(coh, sync, next_sync); - coh->sync = sync; - - /* work out how many samples we need for the next call to account - for differences in tx and rx sample clocks */ - - nin = COHPSK_M; - if (sync == 1) { - if (coh->rx_timing > COHPSK_M/P) - nin = COHPSK_M + COHPSK_M/P; - if (coh->rx_timing < -COHPSK_M/P) - nin = COHPSK_M - COHPSK_M/P; - } - coh->nin = nin; - *nin_frame = (NSYMROWPILOT-1)*COHPSK_M + nin; - //if (coh->verbose) - // fprintf(stderr, "%f %d %d\n", coh->rx_timing, nin, *nin_frame); -} - - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: cohpsk_fs_offset() - AUTHOR......: David Rowe - DATE CREATED: May 2015 - - Simulates small Fs offset between mod and demod. - -\*---------------------------------------------------------------------------*/ - -int cohpsk_fs_offset(COMP out[], COMP in[], int n, float sample_rate_ppm) -{ - double tin, f; - int tout, t1, t2; - - tin = 0.0; tout = 0; - while (tin < n) { - t1 = floor(tin); - t2 = ceil(tin); - f = tin - t1; - out[tout].real = (1.0-f)*in[t1].real + f*in[t2].real; - out[tout].imag = (1.0-f)*in[t1].imag + f*in[t2].imag; - tout += 1; - tin += 1.0 + sample_rate_ppm/1E6; - //printf("tin: %f tout: %d f: %f\n", tin, tout, f); - } - - return tout; -} - - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: cohpsk_get_demod_stats() - AUTHOR......: David Rowe - DATE CREATED: 14 June 2015 - - Fills stats structure with a bunch of demod information. - -\*---------------------------------------------------------------------------*/ - -void cohpsk_get_demod_stats(struct COHPSK *coh, struct MODEM_STATS *stats) -{ - int c,r; - COMP pi_4; - float new_snr_est; - - pi_4.real = cosf(M_PI/4.0); - pi_4.imag = sinf(M_PI/4.0); - - stats->Nc = COHPSK_NC*ND; - assert(stats->Nc <= MODEM_STATS_NC_MAX); - new_snr_est = 20*log10((coh->sig_rms+1E-6)/(coh->noise_rms+1E-6)) - 10*log10(3000.0/700.0); - stats->snr_est = 0.9*stats->snr_est + 0.1*new_snr_est; - - //fprintf(stderr, "sig_rms: %f noise_rms: %f snr_est: %f\n", coh->sig_rms, coh->noise_rms, stats->snr_est); - stats->sync = coh->sync; - stats->foff = coh->f_est - FDMDV_FCENTRE; - stats->rx_timing = coh->rx_timing; - stats->clock_offset = 0.0; /* TODO - implement clock offset estimation */ - - assert(NSYMROW <= MODEM_STATS_NR_MAX); - stats->nr = NSYMROW; - for(c=0; crx_symbols[r][c] = cmult(coh->rx_symb[r][c], pi_4); - } - } -} - - -void cohpsk_set_verbose(struct COHPSK *coh, int verbose) -{ - assert(coh != NULL); - coh->verbose = verbose; -} - - -void cohpsk_set_frame(struct COHPSK *coh, int frame) -{ - assert(coh != NULL); - coh->frame = frame; -} - - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: cohpsk_get_test_bits() - AUTHOR......: David Rowe - DATE CREATED: June 2015 - - Returns a frame of known test bits. - -\*---------------------------------------------------------------------------*/ - -void cohpsk_get_test_bits(struct COHPSK *coh, int rx_bits[]) -{ - memcpy(rx_bits, coh->ptest_bits_coh_tx, sizeof(int)*COHPSK_BITS_PER_FRAME); - coh->ptest_bits_coh_tx += COHPSK_BITS_PER_FRAME; - if (coh->ptest_bits_coh_tx >=coh->ptest_bits_coh_end) { - coh->ptest_bits_coh_tx = (int*)test_bits_coh; - } -} - - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: cohpsk_put_test_bits() - AUTHOR......: David Rowe - DATE CREATED: June 2015 - - Accepts bits from demod and attempts to sync with the known - test_bits sequence. When synced measures bit errors. - - Has states to track two separate received test sequences based on - channel 0 or 1. - -\*---------------------------------------------------------------------------*/ - -void cohpsk_put_test_bits(struct COHPSK *coh, int *state, short error_pattern[], - int *bit_errors, char rx_bits_char[], int channel) -{ - int i, next_state, anerror; - int rx_bits[COHPSK_BITS_PER_FRAME]; - - assert((channel == 0) || (channel == 1)); - int *ptest_bits_coh_rx = coh->ptest_bits_coh_rx[channel]; - - for(i=0; i 1)) { - fprintf(stderr, "i: %d rx_bits: %d ptest_bits_coh_rx: %d\n", i, rx_bits[i], ptest_bits_coh_rx[i]); - } - *bit_errors += anerror; - error_pattern[i] = anerror; - } - - /* state logic */ - - next_state = *state; - - if (*state == 0) { - if (*bit_errors < 4) { - next_state = 1; - ptest_bits_coh_rx += COHPSK_BITS_PER_FRAME; - if (ptest_bits_coh_rx >= coh->ptest_bits_coh_end) { - ptest_bits_coh_rx = (int*)test_bits_coh; - } - } - } - - /* if 5 frames with large BER reset test frame sync */ - - if (*state > 0) { - if (*bit_errors > 8) { - if (*state == 6) - next_state = 0; - else - next_state = *state+1; - } - else - next_state = 1; - } - - if (*state > 0) { - ptest_bits_coh_rx += COHPSK_BITS_PER_FRAME; - if (ptest_bits_coh_rx >= coh->ptest_bits_coh_end) { - ptest_bits_coh_rx = (int*)test_bits_coh; - } - } - - //fprintf(stderr, "state: %d next_state: %d bit_errors: %d\n", *state, next_state, *bit_errors); - - *state = next_state; - coh->ptest_bits_coh_rx[channel] = ptest_bits_coh_rx; -} - - -int cohpsk_error_pattern_size(void) { - return COHPSK_BITS_PER_FRAME; -} - - -float *cohpsk_get_rx_bits_lower(struct COHPSK *coh) { - return coh->rx_bits_lower; -} - -float *cohpsk_get_rx_bits_upper(struct COHPSK *coh) { - return coh->rx_bits_upper; -} - -void cohpsk_set_carrier_ampl(struct COHPSK *coh, int c, float ampl) { - assert(c < COHPSK_NC*ND); - coh->carrier_ampl[c] = ampl; - fprintf(stderr, "cohpsk_set_carrier_ampl: %d %f\n", c, (double)ampl); -} - -} // FreeDV diff --git a/libfreedv/cohpsk_defs.h b/libfreedv/cohpsk_defs.h deleted file mode 100644 index 28b756e41..000000000 --- a/libfreedv/cohpsk_defs.h +++ /dev/null @@ -1,9 +0,0 @@ -/* Generated by write_pilot_file() Octave function */ - -#define NSYMROW 4 /* number of data symbols per carrier (number of rows) */ -#define NS 4 /* number of data symbols between pilots */ -#define NPILOTSFRAME 2 /* number of pilot symbols per carrier */ -#define PILOTS_NC 7 /* number of carriers */ - -#define NSYMROWPILOT 6 /* number of rows after pilots inserted */ - diff --git a/libfreedv/cohpsk_internal.h b/libfreedv/cohpsk_internal.h deleted file mode 100644 index f3221c778..000000000 --- a/libfreedv/cohpsk_internal.h +++ /dev/null @@ -1,131 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: cohpsk_internal.h - AUTHOR......: David Rowe - DATE CREATED: March 2015 - - Functions that implement a coherent PSK FDM modem. - -\*---------------------------------------------------------------------------*/ - -/* - 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 . -*/ - -#ifndef __COHPSK_INTERNAL__ -#define __COHPSK_INTERNAL__ - -#define NCT_SYMB_BUF (2*NSYMROWPILOT+2) -#define ND 2 /* diversity factor ND 1 is no diveristy, ND we have orginal plus - one copy */ -#define NSW 4 /* number of sync window frames */ -#define COHPSK_ND 2 /* diversity factor */ -#define COHPSK_M 100 /* oversampling rate */ -#define COHPSK_NSYM 6 -#define COHPSK_NFILTER (COHPSK_NSYM*COHPSK_M) -#define COHPSK_EXCESS_BW 0.5 /* excess BW factor of root nyq filter */ -#define COHPSK_NT 5 /* number of symbols we estimate timing over */ - -#include "fdmdv_internal.h" -#include "kiss_fft.h" - -namespace FreeDV -{ - -struct COHPSK { - COMP ch_fdm_frame_buf[NSW*NSYMROWPILOT*COHPSK_M]; /* buffer of several frames of symbols from channel */ - float pilot2[2*NPILOTSFRAME][COHPSK_NC]; - float phi_[NSYMROWPILOT][COHPSK_NC*ND]; /* phase estimates for this frame of rx data symbols */ - float amp_[NSYMROW][COHPSK_NC*ND]; /* amplitude estimates for this frame of rx data symbols */ - COMP rx_symb[NSYMROWPILOT][COHPSK_NC*ND]; /* demodulated symbols */ - float f_est; - COMP rx_filter_memory[COHPSK_NC*ND][COHPSK_NFILTER]; - COMP ct_symb_buf[NCT_SYMB_BUF][COHPSK_NC*ND]; - int ct; /* coarse timing offset in symbols */ - float rx_timing; /* fine timing for last symbol in frame */ - int nin; /* number of samples to input for next symbol */ - float f_fine_est; - COMP ff_rect; - COMP ff_phase; - COMP ct_symb_ff_buf[NSYMROWPILOT+2][COHPSK_NC*ND]; - int sync; - int sync_timer; - - int frame; - float ratio; - - float sig_rms; - float noise_rms; - - struct FDMDV *fdmdv; - - int verbose; - - int *ptest_bits_coh_tx; - int *ptest_bits_coh_rx[2]; - int *ptest_bits_coh_end; - - /* counting bit errors using pilots */ - - int npilotbits; - int npilotbiterrors; - - /* optional log variables used for testing Octave to C port */ - - COMP *rx_baseband_log; - int rx_baseband_log_col_index; - int rx_baseband_log_col_sz; - - COMP *rx_filt_log; - int rx_filt_log_col_index; - int rx_filt_log_col_sz; - - COMP *ch_symb_log; - int ch_symb_log_r; - int ch_symb_log_col_sz; - - float *rx_timing_log; - int rx_timing_log_index; - - /* demodulated bits before diversity combination for test/instrumentation purposes */ - - float rx_bits_lower[COHPSK_BITS_PER_FRAME]; - float rx_bits_upper[COHPSK_BITS_PER_FRAME]; - - /* tx amplitude weights for each carrier for test/instrumentation */ - - float carrier_ampl[COHPSK_NC*ND]; - - /* Flag enabling simple freq est mode */ - int freq_est_mode_reduced; -}; - -void bits_to_qpsk_symbols(COMP tx_symb[][COHPSK_NC*COHPSK_ND], int tx_bits[], int nbits); -void qpsk_symbols_to_bits(struct COHPSK *coh, float rx_bits[], COMP ct_symb_buf[][COHPSK_NC*COHPSK_ND]); -void tx_filter_and_upconvert_coh(COMP tx_fdm[], int Nc, const COMP tx_symbols[], - COMP tx_filter_memory[COHPSK_NC][COHPSK_NSYM], - COMP phase_tx[], COMP freq[], - COMP *fbb_phase, COMP fbb_rect); -void fdm_downconvert_coh(COMP rx_baseband[COHPSK_NC][COHPSK_M+COHPSK_M/P], int Nc, COMP rx_fdm[], COMP phase_rx[], COMP freq[], int nin); -void rx_filter_coh(COMP rx_filt[COHPSK_NC+1][P+1], int Nc, COMP rx_baseband[COHPSK_NC+1][COHPSK_M+COHPSK_M/P], COMP rx_filter_memory[COHPSK_NC+1][COHPSK_NFILTER], int nin); -void frame_sync_fine_freq_est(struct COHPSK *coh, COMP ch_symb[][COHPSK_NC*COHPSK_ND], int sync, int *next_sync); -void fine_freq_correct(struct COHPSK *coh, int sync, int next_sync); -int sync_state_machine(struct COHPSK *coh, int sync, int next_sync); -int cohpsk_fs_offset(COMP out[], COMP in[], int n, float sample_rate_ppm); - -} // FreeDV - -#endif diff --git a/libfreedv/comp_prim.h b/libfreedv/comp_prim.h deleted file mode 100644 index b8477768a..000000000 --- a/libfreedv/comp_prim.h +++ /dev/null @@ -1,149 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: comp_prim.h - AUTHOR......: David Rowe - DATE CREATED: Marh 2015 - - Complex number maths primitives. - -\*---------------------------------------------------------------------------*/ - -/* - 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 . -*/ - -#ifndef __COMP_PRIM__ -#define __COMP_PRIM__ - -#include -#include "codec2/comp.h" - -namespace FreeDV -{ - -/*---------------------------------------------------------------------------*\ - - FUNCTIONS - -\*---------------------------------------------------------------------------*/ - -inline static COMP cneg(COMP a) -{ - COMP res; - - res.real = -a.real; - res.imag = -a.imag; - - return res; -} - -inline static COMP cconj(COMP a) -{ - COMP res; - - res.real = a.real; - res.imag = -a.imag; - - return res; -} - -inline 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; -} - -inline static COMP fcmult(float a, COMP b) -{ - COMP res; - - res.real = a*b.real; - res.imag = a*b.imag; - - return res; -} - -inline static COMP cadd(COMP a, COMP b) -{ - COMP res; - - res.real = a.real + b.real; - res.imag = a.imag + b.imag; - - return res; -} - -inline static float cabsolute(COMP a) -{ - return sqrt(pow(a.real, 2.0) + pow(a.imag, 2.0)); -} - -/* - * Euler's formula in a new convenient function - */ -inline static COMP comp_exp_j(float phi){ - COMP res; - res.real = cosf(phi); - res.imag = sinf(phi); - return res; -} - -/* - * Quick and easy complex 0 - */ -inline static COMP comp0(){ - COMP res; - res.real = 0; - res.imag = 0; - return res; -} - -/* - * Quick and easy complex subtract - */ -inline static COMP csub(COMP a, COMP b){ - COMP res; - res.real = a.real-b.real; - res.imag = a.imag-b.imag; - return res; -} - -/* - * Compare the magnitude of a and b. if |a|>|b|, return true, otw false. - * This needs no square roots - */ -inline static int comp_mag_gt(COMP a,COMP b){ - return ((a.real*a.real)+(a.imag*a.imag)) > ((b.real*b.real)+(b.imag*b.imag)); -} - -/* - * Normalize a complex number's magnitude to 1 - */ -inline static COMP comp_normalize(COMP a){ - COMP b; - float av = cabsolute(a); - b.real = a.real/av; - b.imag = a.imag/av; - return b; -} - -} // FreeDV - -#endif diff --git a/libfreedv/defines.h b/libfreedv/defines.h deleted file mode 100644 index d30f06807..000000000 --- a/libfreedv/defines.h +++ /dev/null @@ -1,120 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: defines.h - AUTHOR......: David Rowe - DATE CREATED: 23/4/93 - - Defines and structures used throughout the codec. - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2009 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 . -*/ - -#ifndef __DEFINES__ -#define __DEFINES__ - -/*---------------------------------------------------------------------------*\ - - DEFINES - -\*---------------------------------------------------------------------------*/ - -/* General defines */ - -#define N_S 0.01 /* internal proc frame length in secs */ -#define TW_S 0.005 /* trapezoidal synth window overlap */ -#define MAX_AMP 160 /* maximum number of harmonics */ -#ifndef PI -#define PI 3.141592654 /* mathematical constant */ -#endif -#define TWO_PI 6.283185307 /* mathematical constant */ -#define MAX_STR 2048 /* maximum string size */ - -#define FFT_ENC 512 /* size of FFT used for encoder */ -#define FFT_DEC 512 /* size of FFT used in decoder */ -#define V_THRESH 6.0 /* voicing threshold in dB */ -#define LPC_ORD 10 /* LPC order */ -#define LPC_ORD_LOW 6 /* LPC order for lower rates */ - -/* Pitch estimation defines */ - -#define M_PITCH_S 0.0400 /* pitch analysis window in s */ -#define P_MIN_S 0.0025 /* minimum pitch period in s */ -#define P_MAX_S 0.0200 /* maximum pitch period in s */ - -namespace FreeDV -{ - -/*---------------------------------------------------------------------------*\ - - TYPEDEFS - -\*---------------------------------------------------------------------------*/ - -/* Structure to hold constants calculated at run time based on sample rate */ - -typedef struct { - int Fs; /* sample rate of this instance */ - int n_samp; /* number of samples per 10ms frame at Fs */ - int max_amp; /* maximum number of harmonics */ - int m_pitch; /* pitch estimation window size in samples */ - int p_min; /* minimum pitch period in samples */ - int p_max; /* maximum pitch period in samples */ - float Wo_min; - float Wo_max; - int nw; /* analysis window size in samples */ - int tw; /* trapezoidal synthesis window overlap */ -} C2CONST; - -/* Structure to hold model parameters for one frame */ - -typedef struct { - float Wo; /* fundamental frequency estimate in radians */ - int L; /* number of harmonics */ - float A[MAX_AMP+1]; /* amplitiude of each harmonic */ - float phi[MAX_AMP+1]; /* phase of each harmonic */ - int voiced; /* non-zero if this frame is voiced */ -} MODEL; - -/* describes each codebook */ - -struct lsp_codebook { - int k; /* dimension of vector */ - int log2m; /* number of bits in m */ - int m; /* elements in codebook */ - const float * cb; /* The elements */ -}; - -extern const struct lsp_codebook lsp_cb[]; -extern const struct lsp_codebook lsp_cbd[]; -extern const struct lsp_codebook lsp_cbvq[]; -extern const struct lsp_codebook lsp_cbjnd[]; -extern const struct lsp_codebook lsp_cbdt[]; -extern const struct lsp_codebook lsp_cbjvm[]; -extern const struct lsp_codebook lsp_cbvqanssi[]; -extern const struct lsp_codebook mel_cb[]; -extern const struct lsp_codebook ge_cb[]; -extern const struct lsp_codebook lspmelvq_cb[]; -extern const struct lsp_codebook newamp1vq_cb[]; -extern const struct lsp_codebook newamp1_energy_cb[]; -extern const struct lsp_codebook newamp2vq_cb[]; -extern const struct lsp_codebook newamp2_energy_cb[]; - -} // FreeDV - -#endif diff --git a/libfreedv/fdmdv.cpp b/libfreedv/fdmdv.cpp deleted file mode 100644 index efe38b4b9..000000000 --- a/libfreedv/fdmdv.cpp +++ /dev/null @@ -1,1995 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - 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 "fdv_arm_math.h" - -#include "fdmdv_internal.h" -#include "codec2_fdmdv.h" -#include "comp_prim.h" -#include "rn.h" -#include "rxdec_coeff.h" -#include "test_bits.h" -#include "pilot_coeff.h" -#include "codec2_fft.h" -#include "hanning.h" -#include "os.h" -#include "machdep.h" - -namespace FreeDV -{ - -static int sync_uw[] = {1,-1,1,-1,1,-1}; -#ifdef __EMBEDDED__ -#define printf gdb_stdio_printf -#endif - -static const COMP pi_on_4 = { .70710678118654752439, .70710678118654752439 }; // COSF(PI/4) , SINF(PI/4) - - -/*--------------------------------------------------------------------------* \ - - 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. - -\*---------------------------------------------------------------------------*/ - -struct FDMDV * fdmdv_create(int Nc) -{ - struct FDMDV *f; - int c, i, k; - - assert(NC == FDMDV_NC_MAX); /* check public and private #defines match */ - assert(Nc <= NC); - assert(FDMDV_NOM_SAMPLES_PER_FRAME == M_FAC); - assert(FDMDV_MAX_SAMPLES_PER_FRAME == (M_FAC+M_FAC/P)); - - f = (struct FDMDV*) malloc(sizeof(struct FDMDV)); - if (f == NULL) - return NULL; - - f->Nc = Nc; - - f->ntest_bits = Nc*NB*4; - f->current_test_bit = 0; - f->rx_test_bits_mem = (int*) malloc(sizeof(int)*f->ntest_bits); - assert(f->rx_test_bits_mem != NULL); - for(i=0; intest_bits; i++) - f->rx_test_bits_mem[i] = 0; - assert((sizeof(test_bits)/sizeof(int)) >= (std::size_t) f->ntest_bits); - - f->old_qpsk_mapping = 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; - } - - /* 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 = COSF(2.0*PI*c/(Nc+1)); - f->phase_tx[c].imag = SINF(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; - } - } - f->prev_tx_symbols[Nc].real = 2.0; - - fdmdv_set_fsep(f, FSEP); - f->freq[Nc].real = COSF(2.0*PI*0.0/FS); - f->freq[Nc].imag = SINF(2.0*PI*0.0/FS); - f->freq_pol[Nc] = 2.0*PI*0.0/FS; - - f->fbb_rect.real = COSF(2.0*PI*FDMDV_FCENTRE/FS); - f->fbb_rect.imag = SINF(2.0*PI*FDMDV_FCENTRE/FS); - f->fbb_pol = 2.0*PI*FDMDV_FCENTRE/FS; - f->fbb_phase_tx.real = 1.0; - f->fbb_phase_tx.imag = 0.0; - f->fbb_phase_rx.real = 1.0; - f->fbb_phase_rx.imag = 0.0; - - /* Generate DBPSK pilot Look Up Table (LUT) */ - - generate_pilot_lut(f->pilot_lut, &f->freq[Nc]); - - /* freq Offset estimation states */ - - f->fft_pilot_cfg = codec2_fft_alloc (MPILOTFFT, 0, NULL, NULL); - assert(f->fft_pilot_cfg != NULL); - - 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_FAC; - - for(i=0; irxdec_lpf_mem[i].real = 0.0; - f->rxdec_lpf_mem[i].imag = 0.0; - } - - 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_phase_rect.real = 1.0; - f->foff_phase_rect.imag = 0.0; - - for(i=0; irx_fdm_mem[i].real = 0.0; - f->rx_fdm_mem[i].imag = 0.0; - } - - f->fest_state = 0; - f->sync = 0; - f->timer = 0; - for(i=0; isync_mem[i] = 0; - - for(c=0; csig_est[c] = 0.0; - f->noise_est[c] = 0.0; - } - - f->sig_pwr_av = 0.0; - f->foff_filt = 0.0; - - return f; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: fdmdv_destroy - AUTHOR......: David Rowe - DATE CREATED: 16/4/2012 - - Destroy an instance of the modem. - -\*---------------------------------------------------------------------------*/ - -void fdmdv_destroy(struct FDMDV *fdmdv) -{ - assert(fdmdv != NULL); - codec2_fft_free(fdmdv->fft_pilot_cfg); - free(fdmdv->rx_test_bits_mem); - free(fdmdv); -} - - -void fdmdv_use_old_qpsk_mapping(struct FDMDV *fdmdv) { - fdmdv->old_qpsk_mapping = 1; -} - - -int fdmdv_bits_per_frame(struct FDMDV *fdmdv) -{ - return (fdmdv->Nc * NB); -} - -/*---------------------------------------------------------------------------*\ - - 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. - -\*---------------------------------------------------------------------------*/ - -void fdmdv_get_test_bits(struct FDMDV *f, int tx_bits[]) -{ - int i; - int bits_per_frame = fdmdv_bits_per_frame(f); - - for(i=0; icurrent_test_bit]; - f->current_test_bit++; - if (f->current_test_bit > (f->ntest_bits-1)) - f->current_test_bit = 0; - } -} - -float fdmdv_get_fsep(struct FDMDV *f) -{ - return f->fsep; -} - -void fdmdv_set_fsep(struct FDMDV *f, float fsep) { - int c; - float carrier_freq; - - f->fsep = fsep; - - /* Set up frequency of each carrier */ - - for(c=0; cNc/2; c++) { - carrier_freq = (-f->Nc/2 + c)*f->fsep; - f->freq[c].real = COSF(2.0*PI*carrier_freq/FS); - f->freq[c].imag = SINF(2.0*PI*carrier_freq/FS); - f->freq_pol[c] = 2.0*PI*carrier_freq/FS; - } - - for(c=f->Nc/2; cNc; c++) { - carrier_freq = (-f->Nc/2 + c + 1)*f->fsep; - f->freq[c].real = COSF(2.0*PI*carrier_freq/FS); - f->freq[c].imag = SINF(2.0*PI*carrier_freq/FS); - f->freq_pol[c] = 2.0*PI*carrier_freq/FS; - } -} - - -/*---------------------------------------------------------------------------*\ - - 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[], int Nc, COMP prev_tx_symbols[], int tx_bits[], int *pilot_bit, int old_qpsk_mapping) -{ - int c, msb, lsb; - COMP j = {0.0,1.0}; - - /* Map tx_bits to to Nc DQPSK symbols. Note legacy support for - old (suboptimal) V0.91 FreeDV mapping */ - - for(c=0; creal /= mag; - fbb_phase->imag /= mag; - - /* shift memory, inserting zeros at end */ - - for(i=0; ireal /= mag; - fbb_phase->imag /= mag; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: fdmdv_mod() - AUTHOR......: David Rowe - DATE CREATED: 26/4/2012 - - FDMDV modulator, take a frame of FDMDV_BITS_PER_FRAME bits and - generates a frame of FDMDV_SAMPLES_PER_FRAME modulated symbols. - Sync bit is returned to aid alignment of your next frame. - - The sync_bit value returned will be used for the _next_ frame. - - The output signal is complex to support single sided frequency - shifting, for example when testing frequency offsets in channel - simulation. - -\*---------------------------------------------------------------------------*/ - -void fdmdv_mod(struct FDMDV *fdmdv, COMP tx_fdm[], int tx_bits[], int *sync_bit) -{ - COMP tx_symbols[NC+1]; - PROFILE_VAR(mod_start, tx_filter_and_upconvert_start); - - PROFILE_SAMPLE(mod_start); - bits_to_dqpsk_symbols(tx_symbols, fdmdv->Nc, fdmdv->prev_tx_symbols, tx_bits, &fdmdv->tx_pilot_bit, fdmdv->old_qpsk_mapping); - memcpy(fdmdv->prev_tx_symbols, tx_symbols, sizeof(COMP)*(fdmdv->Nc+1)); - PROFILE_SAMPLE_AND_LOG(tx_filter_and_upconvert_start, mod_start, " bits_to_dqpsk_symbols"); - tx_filter_and_upconvert(tx_fdm, fdmdv->Nc, tx_symbols, fdmdv->tx_filter_memory, - fdmdv->phase_tx, fdmdv->freq, &fdmdv->fbb_phase_tx, fdmdv->fbb_rect); - PROFILE_SAMPLE_AND_LOG2(tx_filter_and_upconvert_start, " tx_filter_and_upconvert"); - - *sync_bit = fdmdv->tx_pilot_bit; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: generate_pilot_fdm() - AUTHOR......: David Rowe - DATE CREATED: 19/4/2012 - - Generate M_FAC 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_FAC]; - - /* +1 -1 +1 -1 DBPSK sync carrier, once filtered becomes (roughly) - two spectral lines at +/- RS/2 */ - - if (*bit) - *symbol = -*symbol; - - if (*bit) - *bit = 0; - else - *bit = 1; - - /* filter DPSK symbol to create M_FAC baseband samples */ - - filter_mem[NFILTER-1] = (sqrtf(2)/2) * *symbol; - for(i=0; ireal; - pilot_fdm[i].imag = sqrtf(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 = sqrtf(2.0); - COMP pilot_phase = {1.0, 0.0}; - float pilot_filter_mem[NFILTER]; - COMP pilot[M_FAC]; - int i,f; - - for(i=0; i= 4) - memcpy(&pilot_lut[M_FAC*(f-4)], pilot, M_FAC*sizeof(COMP)); - } - - // create complex conjugate since we need this and only this later on - for (f=0;f<4*M_FAC;f++) - { - pilot_lut[f] = cconj(pilot_lut[f]); - } - -} - -/*---------------------------------------------------------------------------*\ - - 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[], codec2_fft_cfg fft_pilot_cfg, COMP S[], int nin, - int do_fft) -{ - 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, COMP rx_fdm[], int nin, int do_fft) -{ - int i; -#ifndef FDV_ARM_MATH - int j; -#endif - COMP pilot[M_FAC+M_FAC/P]; - COMP prev_pilot[M_FAC+M_FAC/P]; - float foff, foff1, foff2; - float max1, max2; - - assert(nin <= M_FAC+M_FAC/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_FAC) - 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_FAC) - f->prev_pilot_lut_index = 0; - } - - /* - Down convert latest M_FAC 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]; - } - -#ifndef FDV_ARM_MATH - for(i=0,j=NPILOTBASEBAND-nin; ipilot_baseband1[j] = cmult(rx_fdm[i], pilot[i]); - f->pilot_baseband2[j] = cmult(rx_fdm[i], prev_pilot[i]); - } -#else - // TODO: Maybe a handwritten mult taking advantage of rx_fdm[0] being - // used twice would be faster but this is for sure faster than - // the implementation above in any case. - arm_cmplx_mult_cmplx_f32(&rx_fdm[0].real,&pilot[0].real,&f->pilot_baseband1[NPILOTBASEBAND-nin].real,nin); - arm_cmplx_mult_cmplx_f32(&rx_fdm[0].real,&prev_pilot[0].real,&f->pilot_baseband2[NPILOTBASEBAND-nin].real,nin); -#endif - - lpf_peak_pick(&foff1, &max1, f->pilot_baseband1, f->pilot_lpf1, f->fft_pilot_cfg, f->S1, nin, do_fft); - lpf_peak_pick(&foff2, &max2, f->pilot_baseband2, f->pilot_lpf2, f->fft_pilot_cfg, f->S2, nin, do_fft); - - if (max1 > max2) - foff = foff1; - else - foff = foff2; - - return foff; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: fdmdv_freq_shift() - AUTHOR......: David Rowe - DATE CREATED: 26/4/2012 - - Frequency shift modem signal. The use of complex input and output allows - single sided frequency shifting (no images). - -\*---------------------------------------------------------------------------*/ - -void fdmdv_freq_shift(COMP rx_fdm_fcorr[], COMP rx_fdm[], float foff, - COMP *foff_phase_rect, int nin) -{ - COMP foff_rect; - float mag; - int i; - - foff_rect.real = COSF(2.0*PI*foff/FS); - foff_rect.imag = SINF(2.0*PI*foff/FS); - for(i=0; ireal /= mag; - foff_phase_rect->imag /= mag; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: fdm_downconvert - AUTHOR......: David Rowe - DATE CREATED: 22/4/2012 - - Frequency shift each modem carrier down to Nc+1 baseband signals. - -\*---------------------------------------------------------------------------*/ - -void fdm_downconvert(COMP rx_baseband[NC+1][M_FAC+M_FAC/P], int Nc, COMP rx_fdm[], COMP phase_rx[], COMP freq[], int nin) -{ - int i,c; - float mag; - - /* maximum number of input samples to demod */ - - assert(nin <= (M_FAC+M_FAC/P)); - - /* downconvert */ - - for (c=0; c - nin - |--------------------------|---------| - 1 | - phase_rx(c) - - This means winding phase(c) back from this point - to ensure phase continuity. - - */ - - //PROFILE_SAMPLE(windback_start); - windback_phase = -freq_pol[c]*NFILTER; - windback_phase_rect.real = COSF(windback_phase); - windback_phase_rect.imag = SINF(windback_phase); - phase_rx[c] = cmult(phase_rx[c],windback_phase_rect); - //PROFILE_SAMPLE_AND_LOG(downconvert_start, windback_start, " windback"); - - /* down convert all samples in buffer */ - - st = NRX_FDM_MEM-1; /* end of buffer */ - st -= nin-1; /* first new sample */ - st -= NFILTER; /* first sample used in filtering */ - - /* freq shift per dec_rate step is dec_rate times original shift */ - - f_rect = freq[c]; - for(i=0; i P) - rx_timing -= P; - if (rx_timing < -P) - rx_timing += P; - - /* rx_filter_mem_timing contains Nt*P samples (Nt symbols at rate - P), where Nt is odd. Lets use linear interpolation to resample - in the centre of the timing estimation window .*/ - - rx_timing += floorf(NT/2.0)*P; - low_sample = floorf(rx_timing); - fract = rx_timing - low_sample; - high_sample = ceilf(rx_timing); - - //printf("rx_timing: %f low_sample: %d high_sample: %d fract: %f\n", rx_timing, low_sample, high_sample, fract); - - 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)) { - if (old_qpsk_mapping) { - msb = 1; lsb = 0; - } else { - msb = 1; lsb = 1; - } - } - if ((d.real >= 0) && (d.imag < 0)) { - if (old_qpsk_mapping) { - msb = 1; lsb = 1; - } else { - msb = 1; lsb = 0; - } - } - rx_bits[2*c] = msb; - rx_bits[2*c+1] = lsb; - } - - /* Extract DBPSK encoded Sync bit and fine freq offset estimate */ - - norm = 1.0/(cabsolute(prev_rx_symbols[Nc])+1E-6); - phase_difference[Nc] = cmult(rx_symbols[Nc], fcmult(norm, cconj(prev_rx_symbols[Nc]))); - if (phase_difference[Nc].real < 0) { - *sync_bit = 1; - ferr = phase_difference[Nc].imag*norm; /* make f_err magnitude insensitive */ - } - else { - *sync_bit = 0; - ferr = -phase_difference[Nc].imag*norm; - } - - /* 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[], int Nc, COMP phase_difference[]) -{ - float s[NC+1]; - COMP refl_symbols[NC+1]; - float n[NC+1]; - int c; - - - /* mag of each symbol is distance from origin, this gives us a - vector of mags, one for each carrier. */ - - for(c=0; cntest_bits; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: fdmdv_put_test_bits() - AUTHOR......: David Rowe - DATE CREATED: 24/4/2012 - - Accepts nbits from rx and attempts to sync with test_bits sequence. - If sync OK measures bit errors. - -\*---------------------------------------------------------------------------*/ - -void fdmdv_put_test_bits(struct FDMDV *f, int *sync, short error_pattern[], - int *bit_errors, int *ntest_bits, int rx_bits[]) -{ - int i,j; - float ber; - int bits_per_frame = fdmdv_bits_per_frame(f); - - /* Append to our memory */ - - for(i=0,j=bits_per_frame; intest_bits-bits_per_frame; i++,j++) - f->rx_test_bits_mem[i] = f->rx_test_bits_mem[j]; - for(i=f->ntest_bits-bits_per_frame,j=0; intest_bits; i++,j++) - f->rx_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; intest_bits; i++) { - error_pattern[i] = test_bits[i] ^ f->rx_test_bits_mem[i]; - *bit_errors += error_pattern[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/f->ntest_bits; - - *sync = 0; - if (ber < 0.2) - *sync = 1; - - *ntest_bits = f->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 re-acquisition of large frequency offsets. - - The sync state is also useful for higher layers to determine when - there is valid FDMDV data for decoding. We want to reliably and - quickly get into sync, stay in sync even on fading channels, and - fall out of sync quickly if tx stops or it's a false sync. - - In multipath fading channels the BPSK sync carrier may be pushed - down in the noise, despite other carriers being at full strength. - We want to avoid loss of sync in these cases. - -\*---------------------------------------------------------------------------*/ - -int freq_state(int *reliable_sync_bit, int sync_bit, int *state, int *timer, int *sync_mem) -{ - int next_state, sync, unique_word, i, corr; - - /* look for 6 symbols (120ms) 101010 of sync sequence */ - - unique_word = 0; - for(i=0; ifbb_phase_rx, *nin); - - /* freq offset estimation and correction */ - - PROFILE_SAMPLE(demod_start); - foff_coarse = rx_est_freq_offset(fdmdv, rx_fdm_bb, *nin, !fdmdv->sync); - PROFILE_SAMPLE_AND_LOG(fdmdv_freq_shift_start, demod_start, " rx_est_freq_offset"); - - if (fdmdv->sync == 0) - fdmdv->foff = foff_coarse; - fdmdv_freq_shift(rx_fdm_fcorr, rx_fdm_bb, -fdmdv->foff, &fdmdv->foff_phase_rect, *nin); - PROFILE_SAMPLE_AND_LOG(down_convert_and_rx_filter_start, fdmdv_freq_shift_start, " fdmdv_freq_shift"); - - /* baseband processing */ - - rxdec_filter(rx_fdm_filter, rx_fdm_fcorr, fdmdv->rxdec_lpf_mem, *nin); - down_convert_and_rx_filter(rx_filt, fdmdv->Nc, rx_fdm_filter, fdmdv->rx_fdm_mem, fdmdv->phase_rx, fdmdv->freq, - fdmdv->freq_pol, *nin, M_FAC/Q); - PROFILE_SAMPLE_AND_LOG(rx_est_timing_start, down_convert_and_rx_filter_start, " down_convert_and_rx_filter"); - fdmdv->rx_timing = rx_est_timing(rx_symbols, fdmdv->Nc, rx_filt, fdmdv->rx_filter_mem_timing, env, *nin, M_FAC); - PROFILE_SAMPLE_AND_LOG(qpsk_to_bits_start, rx_est_timing_start, " rx_est_timing"); - - /* Adjust number of input samples to keep timing within bounds */ - - *nin = M_FAC; - - if (fdmdv->rx_timing > M_FAC/P) - *nin += M_FAC/P; - - if (fdmdv->rx_timing < -M_FAC/P) - *nin -= M_FAC/P; - - foff_fine = qpsk_to_bits(rx_bits, &sync_bit, fdmdv->Nc, fdmdv->phase_difference, fdmdv->prev_rx_symbols, rx_symbols, - fdmdv->old_qpsk_mapping); - memcpy(fdmdv->prev_rx_symbols, rx_symbols, sizeof(COMP)*(fdmdv->Nc+1)); - PROFILE_SAMPLE_AND_LOG(snr_update_start, qpsk_to_bits_start, " qpsk_to_bits"); - snr_update(fdmdv->sig_est, fdmdv->noise_est, fdmdv->Nc, fdmdv->phase_difference); - PROFILE_SAMPLE_AND_LOG(freq_state_start, snr_update_start, " snr_update"); - - /* freq offset estimation state machine */ - - fdmdv->sync = freq_state(reliable_sync_bit, sync_bit, &fdmdv->fest_state, &fdmdv->timer, fdmdv->sync_mem); - PROFILE_SAMPLE_AND_LOG2(freq_state_start, " freq_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(int Nc, 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; cNc <= 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++) { - stats->rx_symbols[0][c] = fdmdv->phase_difference[c]; - } -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: fdmdv_8_to_16() - AUTHOR......: David Rowe - DATE CREATED: 9 May 2012 - - Changes the sample rate of a signal from 8 to 16 kHz. Support function for - SM1000. - -\*---------------------------------------------------------------------------*/ - -void fdmdv_8_to_16(float out16k[], float in8k[], int n) -{ - int i,k,l; - float acc; - - /* make sure n is an integer multiple of the oversampling rate, ow - this function breaks */ - - assert((n % FDMDV_OS) == 0); - - /* this version unrolled for specific FDMDV_OS */ - - assert(FDMDV_OS == 2); - - for(i=0; iNc; i++) - fprintf(stderr," %1.3f", (double)cabsolute(f->phase_tx[i])); - fprintf(stderr,"\nfreq[]:\n"); - for(i=0; i<=f->Nc; i++) - fprintf(stderr," %1.3f", (double)cabsolute(f->freq[i])); - fprintf(stderr,"\nfoff_phase_rect: %1.3f", (double)cabsolute(f->foff_phase_rect)); - fprintf(stderr,"\nphase_rx[]:\n"); - for(i=0; i<=f->Nc; i++) - fprintf(stderr," %1.3f", (double)cabsolute(f->phase_rx[i])); - fprintf(stderr, "\n\n"); -} - - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: randn() - AUTHOR......: David Rowe - DATE CREATED: 2 August 2014 - - Simple approximation to normal (gaussian) random number generator - with 0 mean and unit variance. - -\*---------------------------------------------------------------------------*/ - -#define RANDN_IT 12 /* This magic number of iterations gives us a - unit variance. I think beacuse var = - (b-a)^2/12 for one uniform random variable, so - for a sum of n random variables it's - n(b-a)^2/12, or for b=1, a = 0, n=12, we get - var = 12(1-0)^2/12 = 1 */ - -static float randn() { - int i; - float rn = 0.0; - - for(i=0; isig_pwr_av: %e target_snr_linear: %f noise_pwr_4000Hz: %e noise_gain: %e\n", - sig_pwr, f->sig_pwr_av, target_snr_linear, noise_pwr_4000Hz, noise_gain); - */ -} - -} // FreeDV - diff --git a/libfreedv/fdmdv_internal.h b/libfreedv/fdmdv_internal.h deleted file mode 100644 index dceb6b222..000000000 --- a/libfreedv/fdmdv_internal.h +++ /dev/null @@ -1,200 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: fdmdv_internal.h - AUTHOR......: David Rowe - DATE CREATED: April 16 2012 - - Header file for FDMDV internal functions, exposed via this header - file for testing. - -\*---------------------------------------------------------------------------*/ - -/* - 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 . -*/ - -#ifndef __FDMDV_INTERNAL__ -#define __FDMDV_INTERNAL__ - -#include "codec2/comp.h" -#include "codec2_fdmdv.h" -#include "codec2_fft.h" - -/*---------------------------------------------------------------------------*\ - - DEFINES - -\*---------------------------------------------------------------------------*/ - -#ifndef PI -#define PI 3.141592654 -#endif -#define FS 8000 /* sample rate in Hz */ -#define T (1.0/FS) /* sample period in seconds */ -#define RS 50 /* symbol rate in Hz */ -#define NC 20 /* max number of data carriers (plus one pilot in the centre) */ -#define NB 2 /* Bits/symbol for QPSK modulation */ -#define RB (NC*RS*NB) /* bit rate */ -#define M_FAC (FS/RS) /* oversampling factor */ -#define NSYM 6 /* number of symbols to filter over */ -#define NFILTER (NSYM*M_FAC) /* size of tx/rx filters at sample rate M */ - -#define FSEP 75 /* Default separation between carriers (Hz) */ - -#define NT 5 /* number of symbols we estimate timing over */ -#define P 4 /* oversample factor used for initial rx symbol filtering output */ -#define Q (M_FAC/4) /* oversample factor used for initial rx symbol filtering input */ -#define NRXDEC 31 /* number of taps in the rx decimation filter */ - -#define NPILOT_LUT (4*M_FAC) /* number of pilot look up table samples */ -#define NPILOTCOEFF 30 /* number of FIR filter coeffs in LP filter */ -#define NPILOTBASEBAND (NPILOTCOEFF+M_FAC+M_FAC/P) /* number of pilot baseband samples reqd for pilot LPF */ -#define NPILOTLPF (4*M_FAC) /* number of samples we DFT pilot over, pilot est window */ -#define MPILOTFFT 256 - -#define NSYNC_MEM 6 - -#define NRX_FDM_MEM (NFILTER+M_FAC+M_FAC/P) /* size of rx filter memory */ -#define NRXDECMEM (NRXDEC+M_FAC+M_FAC/P) /* size of rx decimation filter memory */ - -/* averaging filter coeffs */ - -#define TRACK_COEFF 0.5 -#define SNR_COEFF 0.9 /* SNR est averaging filter coeff */ - -namespace FreeDV -{ - -/*---------------------------------------------------------------------------*\ - - STRUCT for States - -\*---------------------------------------------------------------------------*/ - -struct FDMDV { - - int Nc; - float fsep; - - /* test data (test frame) states */ - - int ntest_bits; - int current_test_bit; - int *rx_test_bits_mem; - - /* Modulator */ - - int old_qpsk_mapping; - int tx_pilot_bit; - COMP prev_tx_symbols[NC+1]; - COMP tx_filter_memory[NC+1][NSYM]; - COMP phase_tx[NC+1]; - COMP freq[NC+1]; - float freq_pol[NC+1]; - - /* Pilot generation at demodulator */ - - COMP pilot_lut[NPILOT_LUT]; - int pilot_lut_index; - int prev_pilot_lut_index; - - /* freq offset estimation states */ - - codec2_fft_cfg fft_pilot_cfg; - COMP pilot_baseband1[NPILOTBASEBAND]; - COMP pilot_baseband2[NPILOTBASEBAND]; - COMP pilot_lpf1[NPILOTLPF]; - COMP pilot_lpf2[NPILOTLPF]; - COMP S1[MPILOTFFT]; - COMP S2[MPILOTFFT]; - - /* baseband to low IF carrier states */ - - COMP fbb_rect; - float fbb_pol; - COMP fbb_phase_tx; - COMP fbb_phase_rx; - - /* freq offset correction states */ - - float foff; - COMP foff_phase_rect; - float foff_filt; - - /* Demodulator */ - - COMP rxdec_lpf_mem[NRXDECMEM]; - COMP rx_fdm_mem[NRX_FDM_MEM]; - COMP phase_rx[NC+1]; - COMP rx_filter_mem_timing[NC+1][NT*P]; - float rx_timing; - COMP phase_difference[NC+1]; - COMP prev_rx_symbols[NC+1]; - - /* sync state machine */ - - int sync_mem[NSYNC_MEM]; - int fest_state; - int sync; - int timer; - - /* SNR estimation states */ - - float sig_est[NC+1]; - float noise_est[NC+1]; - - /* channel simulation */ - - float sig_pwr_av; -}; - -/*---------------------------------------------------------------------------*\ - - FUNCTION PROTOTYPES - -\*---------------------------------------------------------------------------*/ - -void bits_to_dqpsk_symbols(COMP tx_symbols[], int Nc, COMP prev_tx_symbols[], int tx_bits[], int *pilot_bit, int old_qpsk_mapping); -void tx_filter(COMP tx_baseband[NC+1][M_FAC], int Nc, COMP tx_symbols[], COMP tx_filter_memory[NC+1][NSYM]); -void fdm_upconvert(COMP tx_fdm[], int Nc, COMP tx_baseband[NC+1][M_FAC], COMP phase_tx[], COMP freq_tx[], - COMP *fbb_phase, COMP fbb_rect); -void tx_filter_and_upconvert(COMP tx_fdm[], int Nc, COMP tx_symbols[], - COMP tx_filter_memory[NC+1][NSYM], - COMP phase_tx[], COMP freq[], COMP *fbb_phase, COMP fbb_rect); -void generate_pilot_fdm(COMP *pilot_fdm, int *bit, float *symbol, float *filter_mem, COMP *phase, COMP *freq); -void generate_pilot_lut(COMP pilot_lut[], COMP *pilot_freq); -float rx_est_freq_offset(struct FDMDV *f, COMP rx_fdm[], int nin, int do_fft); -void lpf_peak_pick(float *foff, float *max, COMP pilot_baseband[], COMP pilot_lpf[], codec2_fft_cfg fft_pilot_cfg, COMP S[], int nin, int do_fft); -void fdm_downconvert(COMP rx_baseband[NC+1][M_FAC+M_FAC/P], int Nc, COMP rx_fdm[], COMP phase_rx[], COMP freq[], int nin); -void rxdec_filter(COMP rx_fdm_filter[], COMP rx_fdm[], COMP rxdec_lpf_mem[], int nin); -void rx_filter(COMP rx_filt[NC+1][P+1], int Nc, COMP rx_baseband[NC+1][M_FAC+M_FAC/P], COMP rx_filter_memory[NC+1][NFILTER], int nin); -void down_convert_and_rx_filter(COMP rx_filt[NC+1][P+1], int Nc, COMP rx_fdm[], - COMP rx_fdm_mem[], COMP phase_rx[], COMP freq[], - float freq_pol[], int nin, int dec_rate); -float rx_est_timing(COMP rx_symbols[], int Nc, - COMP rx_filt[NC+1][P+1], - COMP rx_filter_mem_timing[NC+1][NT*P], - float env[], - int nin, - int m); -float qpsk_to_bits(int rx_bits[], int *sync_bit, int Nc, COMP phase_difference[], COMP prev_rx_symbols[], COMP rx_symbols[], int old_qpsk_mapping); -void snr_update(float sig_est[], float noise_est[], int Nc, COMP phase_difference[]); -int freq_state(int *reliable_sync_bit, int sync_bit, int *state, int *timer, int *sync_mem); -float calc_snr(int Nc, float sig_est[], float noise_est[]); - -} // FreeDV - -#endif diff --git a/libfreedv/fdv_arm_math.h b/libfreedv/fdv_arm_math.h deleted file mode 100644 index b50706bac..000000000 --- a/libfreedv/fdv_arm_math.h +++ /dev/null @@ -1,41 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: fdv_arm_math.h - AUTHOR......: David Rowe - DATE CREATED: Feb 13 2019 - - Bundles access to ARM CORTEX M specific functions which are enabled by - defining FDV_ARM_MATH - -\*---------------------------------------------------------------------------*/ - -/* - 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 . -*/ - -#ifndef __FDV_ARM_MATH__ -#define __FDV_ARM_MATH__ - -#ifdef FDV_ARM_MATH - #include "arm_const_structs.h" - #define SINF(a) arm_sin_f32(a) - #define COSF(a) arm_cos_f32(a) -#else - #define SINF(a) sinf(a) - #define COSF(a) cosf(a) -#endif - -#endif diff --git a/libfreedv/fmfsk.cpp b/libfreedv/fmfsk.cpp deleted file mode 100644 index 4056dc6c9..000000000 --- a/libfreedv/fmfsk.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: fmfsk.c - AUTHOR......: Brady O'Brien - DATE CREATED: 6 February 2016 - - C Implementation of a FM+ME+FSK modem for FreeDV mode B and other applications - (better APRS, anyone?) - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2016 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 -#include -#include -#include - - -#include "fmfsk.h" -#include "modem_probe.h" -#include "comp_prim.h" - -#define STD_PROC_BITS 96 - -namespace FreeDV -{ - -/* - * Create a new fmfsk modem instance. - * - * int Fs - sample rate - * int Rb - non-manchester bitrate - * returns - new struct FMFSK on sucess, NULL on failure - */ -struct FMFSK * fmfsk_create(int Fs,int Rb){ - assert( Fs % (Rb*2) == 0 ); /* Sample freq must be divisible by symbol rate */ - - int nbits = STD_PROC_BITS; - - /* Allocate the struct */ - struct FMFSK *fmfsk = (struct FMFSK *) malloc(sizeof(struct FMFSK)); - if(fmfsk==NULL) return NULL; - - /* Set up static parameters */ - fmfsk->Rb = Rb; - fmfsk->Rs = Rb*2; - fmfsk->Fs = Fs; - fmfsk->Ts = Fs/fmfsk->Rs; - fmfsk->N = nbits*2*fmfsk->Ts; - fmfsk->nmem = fmfsk->N+(fmfsk->Ts*4); - fmfsk->nsym = nbits*2; - fmfsk->nbit = nbits; - - /* Set up demod state */ - fmfsk->lodd = 0; - fmfsk->nin = fmfsk->N; - fmfsk->snr_mean = 0; - - float *oldsamps = (float*) malloc(sizeof(float)*fmfsk->nmem); - if(oldsamps == NULL){ - free(fmfsk); - return NULL; - } - - fmfsk->oldsamps = oldsamps; - - fmfsk->stats = (struct MODEM_STATS*)malloc(sizeof(struct MODEM_STATS)); - if (fmfsk->stats == NULL) { - free(oldsamps); - free(fmfsk); - return NULL; - } - - return fmfsk; -} - -/* - * Destroys an fmfsk modem and deallocates memory - */ -void fmfsk_destroy(struct FMFSK *fmfsk){ - free(fmfsk->oldsamps); - free(fmfsk); -} - -/* - * Returns the number of samples that must be fed to fmfsk_demod the next - * cycle - */ -uint32_t fmfsk_nin(struct FMFSK *fmfsk){ - return (uint32_t)fmfsk->nin; -} - -void fmfsk_get_demod_stats(struct FMFSK *fmfsk,struct MODEM_STATS *stats){ - /* copy from internal stats, note we can't overwrite stats completely - as it has other states rqd by caller, also we want a consistent - interface across modem types for the freedv_api. - */ - - stats->clock_offset = fmfsk->stats->clock_offset; - stats->snr_est = fmfsk->stats->snr_est; // TODO: make this SNR not Eb/No - stats->rx_timing = fmfsk->stats->rx_timing; - stats->foff = fmfsk->stats->foff; - - stats->neyesamp = fmfsk->stats->neyesamp; - stats->neyetr = fmfsk->stats->neyetr; - memcpy(stats->rx_eye, fmfsk->stats->rx_eye, sizeof(stats->rx_eye)); - - /* these fields not used for FSK so set to something sensible */ - - stats->sync = 0; - stats->nr = fmfsk->stats->nr; - stats->Nc = fmfsk->stats->Nc; -} - -/* - * Modulates nbit bits into N samples to be sent through an FM radio - * - * struct FSK *fsk - FSK config/state struct, set up by fsk_create - * float mod_out[] - Buffer for N samples of modulated FMFSK - * uint8_t tx_bits[] - Buffer containing Nbits unpacked bits - */ - -void fmfsk_mod(struct FMFSK *fmfsk, float fmfsk_out[],uint8_t bits_in[]){ - int i,j; - int nbit = fmfsk->nbit; - int Ts = fmfsk->Ts; - - for(i=0; iTs; - int Fs = fmfsk->Fs; - int Rs = fmfsk->Rs; - int nin = fmfsk->nin; - int N = fmfsk->N; - int nsym = fmfsk->nsym; - int nbit = fmfsk->nbit; - int nmem = fmfsk->nmem; - float *oldsamps = fmfsk->oldsamps; - int nold = nmem-nin; - COMP phi_ft,dphi_ft; /* Phase and delta-phase for fine timing estimator */ - float t; - COMP x; /* Magic fine timing angle */ - float norm_rx_timing,old_norm_rx_timing,d_norm_rx_timing,appm; - int rx_timing,sample_offset; - int next_nin; - float apeven,apodd; /* Approx. prob of even or odd stream being correct */ - float currv,mdiff,lastv; - int neyesamp; - int neyeoffset; - float eye_max; - uint8_t mbit; - float var_signal = 0, var_noise = 0, lastFabsV; - - /* Shift in nin samples */ - memmove(&oldsamps[0] , &oldsamps[nmem-nold], sizeof(float)*nold); - memcpy (&oldsamps[nold], &fmfsk_in[0] , sizeof(float)*nin ); - - /* Allocate memory for filtering */ - float *rx_filt = (float*) malloc(sizeof(float)*(nsym+1)*Ts); - - /* Integrate over Ts input symbols at every offset */ - for(i=0; i<(nsym+1)*Ts; i++){ - t=0; - /* Integrate over some samples */ - for(j=i;jnorm_rx_timing; - fmfsk->norm_rx_timing = norm_rx_timing; - - /* Estimate sample clock offset */ - d_norm_rx_timing = norm_rx_timing - old_norm_rx_timing; - - /* Filter out big jumps in due to nin change */ - if(fabsf(d_norm_rx_timing) < .2){ - appm = 1e6*d_norm_rx_timing/(float)nsym; - fmfsk->ppm = .9*fmfsk->ppm + .1*appm; - } - - /* Figure out how far offset the sample points are */ - sample_offset = (Ts/2)+Ts+rx_timing-1; - - /* Request fewer or greater samples next time, if fine timing is far - * enough off. This also makes it possible to tolerate clock offsets */ - next_nin = N; - if(norm_rx_timing > -.2) - next_nin += Ts/2; - if(norm_rx_timing < -.65) - next_nin -= Ts/2; - fmfsk->nin = next_nin; - - /* Make first diff of this round the last sample of the last round, - * for the odd stream */ - lastv = fmfsk->lodd; - lastFabsV = fabs(lastv); - apeven = 0; - apodd = 0; - for(i=0; i0 ? 1 : 0; - lastv = currv; - - // Calculate the signal variance. Note that the mean is zero - var_signal += currv * currv; - - /* Calculate the variance of the noise between samples (symbols). A quick variance estimate - * without calculating mean can be done by differentiating (remove mean) and then - * dividing by 2. Fabs the samples as we are looking at how close the samples are to each - * other as if they were all the same polarity/symbol. */ - currv = fabs(currv); - var_noise += (currv - lastFabsV) * (currv - lastFabsV); - lastFabsV = currv; - - mdiff = mdiff>0 ? mdiff : 0-mdiff; - - /* Put bit in it's stream */ - if((i%2)==1){ - apeven += mdiff; - /* Even stream goes in LSB */ - rx_bits[i>>1] |= mbit ? 0x1 : 0x0; - }else{ - apodd += mdiff; - /* Odd in second-to-LSB */ - rx_bits[i>>1] = mbit ? 0x2 : 0x0; - } - } - - /* Div by 2 to correct variance when doing via differentiation.*/ - var_noise *= 0.5; - - if(apeven>apodd){ - /* Zero out odd bits from output bitstream */ - for(i=0;i>1; - } - - /* Save last sample of int stream for next demod round */ - fmfsk->lodd = lastv; - - /* Save demod statistics */ - fmfsk->stats->Nc = 0; - fmfsk->stats->nr = 0; - - /* Clock offset and RX timing are all we know here */ - fmfsk->stats->clock_offset = fmfsk->ppm; - fmfsk->stats->rx_timing = (float)rx_timing; - - /* Zero out all of the other things */ - fmfsk->stats->foff = 0; - - /* Use moving average to smooth SNR display */ - if(fmfsk->snr_mean < 0.1) - fmfsk->snr_mean = (10.0 * log10f(var_signal / var_noise)); - else - fmfsk->snr_mean = 0.9 * fmfsk->snr_mean + 0.1 * (10.0 * log10f(var_signal / var_noise)); - fmfsk->stats->snr_est = fmfsk->snr_mean; - - /* Collect an eye diagram */ - /* Take a sample for the eye diagrams */ - neyesamp = fmfsk->stats->neyesamp = Ts*4; - neyeoffset = sample_offset+(Ts*2*28); - - fmfsk->stats->neyetr = 8; - for(k=0; kstats->neyetr; k++) - for(j=0; jstats->rx_eye[k][j] = rx_filt[k*neyesamp+neyeoffset+j]; - //fmfsk->stats->rx_eye[k][j] = fmfsk_in[k*neyesamp+neyeoffset+j]; - eye_max = 0; - - /* Normalize eye to +/- 1 */ - for(i=0; istats->neyetr; i++) - for(j=0; jstats->rx_eye[i][j])>eye_max) - eye_max = fabsf(fmfsk->stats->rx_eye[i][j]); - - for(i=0; istats->neyetr; i++) - for(j=0; jstats->rx_eye[i][j] = (fmfsk->stats->rx_eye[i][j]/(2*eye_max))+.5; - - modem_probe_samp_f("t_norm_rx_timing",&norm_rx_timing,1); - modem_probe_samp_f("t_rx_filt",rx_filt,(nsym+1)*Ts); - free(rx_filt); -} - -} // FreeDV - diff --git a/libfreedv/fmfsk.h b/libfreedv/fmfsk.h deleted file mode 100644 index 0f7645f89..000000000 --- a/libfreedv/fmfsk.h +++ /dev/null @@ -1,116 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: fmfsk.h - AUTHOR......: Brady O'Brien - DATE CREATED: 6 February 2016 - - C Implementation of 2FSK+Manchester over FM modulator/demodulator, based - on mancyfsk.m and fmfsk.m - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2016 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 . -*/ - -#ifndef __C2FMFSK_H -#define __C2FMFSK_H -#include -#include "codec2/comp.h" - -#include "modem_stats.h" - -#define FMFSK_SCALE 16383 - -namespace FreeDV -{ - -/* - * fm-me-2fsk state - */ -struct FMFSK{ - /* Static fmfsk parameters */ - int Rb; /* Manchester-encoded bitrate */ - int Rs; /* Raw modem symbol rate */ - int Fs; /* Sample rate */ - int Ts; /* Samples-per-symbol */ - int N; /* Sample processing buffer size */ - int nsym; /* Number of raw modem symbols processed per demod call */ - int nbit; /* Number of bits spit out per demod call */ - int nmem; /* Number of samples kept around between demod calls */ - - /* State kept by demod */ - int nin; /* Number of samples to be demod-ed the next cycle */ - int lodd; /* Last integrated sample for odd bitstream generation */ - float * oldsamps; /* Memory of old samples to make clock-offset-tolerance possible */ - - /* Stats generated by demod */ - float norm_rx_timing; /* RX Timing, used to calculate clock offset */ - int ppm; /* Clock offset in parts-per-million */ - float snr_mean; - - /* Modem stat structure */ - struct MODEM_STATS * stats; -}; - -/* - * Create a new fmfsk modem instance. - * - * int Fs - sample rate - * int Rb - non-manchester bitrate - * returns - new struct FMFSK on sucess, NULL on failure - */ -struct FMFSK * fmfsk_create(int Fs,int Rb); - -/* - * Destroys an fmfsk modem and deallocates memory - */ -void fmfsk_destroy(struct FMFSK *fmfsk); - -/* - * Deposit demod statistics into a MODEM_STATS struct - */ -void fmfsk_get_demod_stats(struct FMFSK *fmfsk,struct MODEM_STATS *stats); - -/* - * Returns the number of samples that must be fed to fmfsk_demod the next - * cycle - */ -uint32_t fmfsk_nin(struct FMFSK *fmfsk); - -/* - * Modulates nbit bits into N samples to be sent through an FM radio - * - * struct FSK *fsk - FSK config/state struct, set up by fsk_create - * float mod_out[] - Buffer for N samples of modulated FMFSK - * uint8_t tx_bits[] - Buffer containing Nbits unpacked bits - */ -void fmfsk_mod(struct FMFSK *fmfsk, float fmfsk_out[],uint8_t bits_in[]); - - -/* - * Demodulate some number of FMFSK samples. The number of samples to be - * demodulated can be found by calling fmfsk_nin(). - * - * struct FMFSK *fsk - FMFSK config/state struct, set up by fsk_create - * uint8_t rx_bits[] - Buffer for nbit unpacked bits to be written - * float fsk_in[] - nin samples of modualted FMFSK from an FM radio - */ -void fmfsk_demod(struct FMFSK *fmfsk, uint8_t rx_bits[],float fmfsk_in[]); - -} // FreeDV - -#endif diff --git a/libfreedv/freedv_api.cpp b/libfreedv/freedv_api.cpp deleted file mode 100644 index 649aef9bf..000000000 --- a/libfreedv/freedv_api.cpp +++ /dev/null @@ -1,2591 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: freedv_api.c - AUTHOR......: David Rowe - DATE CREATED: August 2014 - - Library of API functions that implement FreeDV "modes", useful for - embedding FreeDV in other programs. - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2014 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 -#include -#include -#include -#include - -#ifdef TT -#if defined(__APPLE__) -#include -#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) -#include -#else -#include -#endif /* __APPLE__ */ -#endif - -#include "fsk.h" -#include "fmfsk.h" -#include "codec2/codec2.h" -#include "codec2_fdmdv.h" -#include "fdmdv_internal.h" -#include "codec2/golay23.h" -#include "codec2/varicode.h" -#include "libfreedv.h" -#include "freedv_api_internal.h" -#include "freedv_vhf_framing.h" -#include "comp_prim.h" -#include "freedv_filter.h" - -#include "codec2_ofdm.h" -#include "ofdm_internal.h" -#include "mpdecode_core.h" -#include "gp_interleaver.h" -#include "interldpc.h" - -#define VERSION 12 /* The API version number. The first version - is 10. Increment if the API changes in a - way that would require changes by the API - user. */ -/* - * Version 10 Initial version August 2, 2015. - * Version 11 September 2015 - * Added: freedv_zero_total_bit_errors(), freedv_get_sync() - * Changed all input and output sample rates to 8000 sps. Rates for FREEDV_MODE_700 and 700B were 7500. - * Version 12 August 2018 - * Added OFDM configuration switch structure - */ - -/* experimentally derived fudge factors to normalise power across modes */ - -#define NORM_PWR_COHPSK 1.74 -#define NORM_PWR_FSK 0.193 -#define NORM_PWR_OFDM 1.00 - -namespace FreeDV -{ - -static struct OFDM_CONFIG *ofdm_config; - -static int ofdm_bitsperframe; -static int ofdm_nuwbits; -static int ofdm_ntxtbits; - -static const char *statemode[] = { - "search", - "trial", - "synced" -}; - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: freedv_open - AUTHOR......: David Rowe - DATE CREATED: 3 August 2014 - - Call this first to initialise. Returns NULL if initialisation fails - (e.g. out of memory or mode not supported). - -\*---------------------------------------------------------------------------*/ - -struct freedv *freedv_open(int mode) { - return freedv_open_advanced(mode, NULL); -} - -struct freedv *freedv_open_advanced(int mode, struct freedv_advanced *adv) { - struct freedv *f; - int Nc, codec2_mode, nbit, nbyte; - - if ((mode != FREEDV_MODE_1600) && (mode != FREEDV_MODE_700) && - (mode != FREEDV_MODE_700B) && (mode != FREEDV_MODE_2400A) && - (mode != FREEDV_MODE_2400B) && (mode != FREEDV_MODE_800XA) && - (mode != FREEDV_MODE_700C) && (mode != FREEDV_MODE_700D)) { - return nullptr; - } - - f = (struct freedv*) malloc(sizeof(struct freedv)); - - if (f == nullptr) { - return nullptr; - } - - f->mode = mode; - f->verbose = 0; - f->test_frames = f->smooth_symbols = 0; - f->freedv_put_error_pattern = nullptr; - f->error_pattern_callback_state = nullptr; - f->n_protocol_bits = 0; - f->frames = 0; - - /* Init states for this mode, and set up samples in/out -----------------------------------------*/ - - if (mode == FREEDV_MODE_1600) - { - f->snr_squelch_thresh = 2.0; - f->squelch_en = 1; - Nc = 16; - f->tx_sync_bit = 0; - codec2_mode = CODEC2_MODE_1300; - f->fdmdv = fdmdv_create(Nc); - - if (f->fdmdv == nullptr) - { - free(f); - return nullptr; - } - - golay23_init(); - f->nin = FDMDV_NOM_SAMPLES_PER_FRAME; - f->n_nom_modem_samples = 2*FDMDV_NOM_SAMPLES_PER_FRAME; - f->n_nat_modem_samples = f->n_nom_modem_samples; - f->n_max_modem_samples = FDMDV_NOM_SAMPLES_PER_FRAME+FDMDV_MAX_SAMPLES_PER_FRAME; - f->modem_sample_rate = FS; - nbit = fdmdv_bits_per_frame(f->fdmdv); - f->fdmdv_bits = (int*) malloc(nbit*sizeof(int)); - - if (f->fdmdv_bits == nullptr) { - return nullptr; - } - - nbit = 2*fdmdv_bits_per_frame(f->fdmdv); - f->tx_bits = (int*) malloc(nbit*sizeof(int)); - f->rx_bits = (int*) malloc(nbit*sizeof(int)); - - if ((f->tx_bits == nullptr) || (f->rx_bits == nullptr)) - { - if (f->tx_bits != nullptr) - { - free(f->tx_bits); - f->tx_bits = nullptr; - } - - if (f->rx_bits != nullptr) - { - free(f->rx_bits); - f->rx_bits = nullptr; - } - - return nullptr; - } - - f->evenframe = 0; - f->sz_error_pattern = fdmdv_error_pattern_size(f->fdmdv); - } - - if ((mode == FREEDV_MODE_700) || (mode == FREEDV_MODE_700B) || (mode == FREEDV_MODE_700C)) { - f->snr_squelch_thresh = 0.0; - f->squelch_en = 0; - switch(mode) { - case FREEDV_MODE_700: - codec2_mode = CODEC2_MODE_700; - break; - case FREEDV_MODE_700B: - codec2_mode = CODEC2_MODE_700B; - break; -#ifdef CODEC2_MODE_700C - case FREEDV_MODE_700C: - codec2_mode = CODEC2_MODE_700C; - break; - default: - codec2_mode = CODEC2_MODE_700C; - fprintf(stderr, "FreeDV::freedv_open_advanced: unknown mode default to FREEDV_MODE_700C"); -#else - default: - codec2_mode = CODEC2_MODE_700B; - fprintf(stderr, "FreeDV::freedv_open_advanced: unknown mode default to FREEDV_MODE_700B"); -#endif - } - - f->cohpsk = cohpsk_create(); - f->nin = COHPSK_NOM_SAMPLES_PER_FRAME; - f->n_nat_modem_samples = COHPSK_NOM_SAMPLES_PER_FRAME; // native modem samples as used by the modem - f->n_nom_modem_samples = f->n_nat_modem_samples * FS / COHPSK_FS; // number of samples after native samples are interpolated to 8000 sps - f->n_max_modem_samples = COHPSK_MAX_SAMPLES_PER_FRAME * FS / COHPSK_FS + 1; - f->modem_sample_rate = FS; /* note wierd sample rate tamed by interpolator */ - f->clip = 1; - nbit = COHPSK_BITS_PER_FRAME; - f->tx_bits = (int*) malloc(nbit*sizeof(int)); - if (f->tx_bits == NULL) - return NULL; - f->sz_error_pattern = cohpsk_error_pattern_size(); - } - -#ifdef CODEC2_MODE_700C - if (mode == FREEDV_MODE_700D) { - /* - TODO: - [ ] how to set up interleaver, prob init time option best, as many arrays depend on it - [ ] clip option? Haven't tried clipping OFDM waveform yet - [ ] support for uncoded and coded error patterns - */ - - f->snr_squelch_thresh = 0.0; - f->squelch_en = 0; - codec2_mode = CODEC2_MODE_700C; - - if ((ofdm_config = (struct OFDM_CONFIG *) calloc(1, sizeof (struct OFDM_CONFIG))) == NULL) { - if (f->tx_bits != NULL) { - free(f->tx_bits); - f->tx_bits = NULL; - } - if (f->rx_bits != NULL) { - free(f->rx_bits); - f->rx_bits = NULL; - } - return NULL; - } - - f->ofdm = ofdm_create(ofdm_config); - free(ofdm_config); - - /* Get a copy of the actual modem config */ - ofdm_config = ofdm_get_config_param(); - - ofdm_bitsperframe = ofdm_get_bits_per_frame(); - ofdm_nuwbits = (ofdm_config->ns - 1) * ofdm_config->bps - ofdm_config->txtbits; - ofdm_ntxtbits = ofdm_config->txtbits; - - f->ldpc = (struct LDPC*) malloc(sizeof(struct LDPC)); - - if (f->ldpc == NULL) { - return NULL; - } - - set_up_hra_112_112(f->ldpc, ofdm_config); - int coded_syms_per_frame = f->ldpc->coded_syms_per_frame; - - if (adv == NULL) { - f->interleave_frames = 1; - } else { - assert((adv->interleave_frames >= 0) && (adv->interleave_frames <= 16)); - f->interleave_frames = adv->interleave_frames; - } - - f->modem_frame_count_tx = f->modem_frame_count_rx = 0; - - f->codeword_symbols = (COMP*) malloc(sizeof(COMP)*f->interleave_frames*coded_syms_per_frame); - - if (f->codeword_symbols == NULL) {return NULL;} - - f->codeword_amps = (float*) malloc(sizeof(float)*f->interleave_frames*coded_syms_per_frame); - - if (f->codeword_amps == NULL) {free(f->codeword_symbols); return NULL;} - - for (int i=0; iinterleave_frames*coded_syms_per_frame; i++) { - f->codeword_symbols[i].real = 0.0; - f->codeword_symbols[i].imag = 0.0; - f->codeword_amps[i] = 0.0; - } - - f->nin = ofdm_get_samples_per_frame(); - f->n_nat_modem_samples = ofdm_get_samples_per_frame(); - f->n_nom_modem_samples = ofdm_get_samples_per_frame(); - f->n_max_modem_samples = ofdm_get_max_samples_per_frame(); - f->modem_sample_rate = ofdm_config->fs; - f->clip = 0; - - nbit = f->sz_error_pattern = ofdm_bitsperframe; - - f->tx_bits = NULL; /* not used for 700D */ - - if (f->interleave_frames > 1) { - /* only allocate this array for interleaver sizes > 1 to save memory on SM1000 port */ - f->mod_out = (COMP*) malloc(sizeof(COMP)*f->interleave_frames*f->n_nat_modem_samples); - if (f->mod_out == NULL) { - if (f->codeword_symbols != NULL) { free(f->codeword_symbols); } - return NULL; - } - - for (int i=0; iinterleave_frames*f->n_nat_modem_samples; i++) { - f->mod_out[i].real = 0.0; - f->mod_out[i].imag = 0.0; - } - } - -#ifndef __EMBEDDED__ - /* tx BPF on by default, can't see any reason we'd want this off */ - ofdm_set_tx_bpf(f->ofdm, 1); -#endif - } -#endif - - if ((mode == FREEDV_MODE_2400A) || (mode == FREEDV_MODE_2400B)) - { - /* Set up the C2 mode */ - codec2_mode = CODEC2_MODE_1300; - /* Set the number of protocol bits */ - f->n_protocol_bits = 20; - f->sz_error_pattern = 0; - f->ext_vco = 0; - } - - if (mode == FREEDV_MODE_2400A) - { - /* Create the framer|deframer */ - f->deframer = fvhff_create_deframer(FREEDV_VHF_FRAME_A, 0); - - if (f->deframer == nullptr) { - return nullptr; - } - - f->fsk = fsk_create_hbr(48000,1200,10,4,1200,1200); - - if (f->fsk == nullptr) - { - fvhff_destroy_deframer(f->deframer); - return nullptr; - } - - /* Note: fsk expects tx/rx bits as an array of uint8_ts, not ints */ - f->tx_bits = (int*) malloc(f->fsk->Nbits*sizeof(int)); - f->n_nom_modem_samples = f->fsk->N; - f->n_max_modem_samples = f->fsk->N + (f->fsk->Ts); - f->n_nat_modem_samples = f->fsk->N; - f->nin = fsk_nin(f->fsk); - f->modem_sample_rate = 48000; - f->modem_symbol_rate = 1200; - /* Malloc something to appease freedv_init and freedv_destroy */ - f->codec_bits = (int*) malloc(1*sizeof(int)); - } - - if (mode == FREEDV_MODE_2400B) - { - /* Create the framer|deframer */ - f->deframer = fvhff_create_deframer(FREEDV_VHF_FRAME_A, 1); - - if (f->deframer == nullptr) - { - if (f->codec_bits != nullptr) { - free(f->codec_bits); - } - - return nullptr; - } - - f->fmfsk = fmfsk_create(48000, 2400); - - if (f->fmfsk == nullptr) - { - fvhff_destroy_deframer(f->deframer); - return nullptr; - } - - /* Note: fsk expects tx/rx bits as an array of uint8_ts, not ints */ - f->tx_bits = (int*) malloc(f->fmfsk->nbit*sizeof(int)); - f->n_nom_modem_samples = f->fmfsk->N; - f->n_max_modem_samples = f->fmfsk->N + (f->fmfsk->Ts); - f->n_nat_modem_samples = f->fmfsk->N; - f->nin = fmfsk_nin(f->fmfsk); - f->modem_sample_rate = 48000; - /* Malloc something to appease freedv_init and freedv_destroy */ - f->codec_bits = (int*) malloc(1*sizeof(int)); - } - -#ifdef CODEC2_MODE_700C - if (mode == FREEDV_MODE_800XA) - { - /* Create the framer|deframer */ - f->deframer = fvhff_create_deframer(FREEDV_HF_FRAME_B, 0); - - if (f->deframer == nullptr) { - return nullptr; - } - - f->fsk = fsk_create_hbr(8000, 400, 10, 4, 800, 400); - fsk_set_nsym(f->fsk,32); - - if (f->fsk == nullptr) - { - fvhff_destroy_deframer(f->deframer); - return nullptr; - } - - /* Note: fsk expects tx/rx bits as an array of uint8_ts, not ints */ - f->tx_bits = (int*) malloc(f->fsk->Nbits*sizeof(int)); - f->n_nom_modem_samples = f->fsk->N; - f->n_max_modem_samples = f->fsk->N + (f->fsk->Ts); - f->n_nat_modem_samples = f->fsk->N; - f->nin = fsk_nin(f->fsk); - f->modem_sample_rate = 8000; - f->modem_symbol_rate = 400; - - /* Malloc something to appease freedv_init and freedv_destroy */ - f->codec_bits = (int*) malloc(1*sizeof(int)); - - f->n_protocol_bits = 0; - codec2_mode = CODEC2_MODE_700C; - fsk_stats_normalise_eye(f->fsk, 0); - f->sz_error_pattern = 0; - } -#endif - - /* Init test frame states */ - - f->test_frames_diversity = 1; - f->test_frame_sync_state = 0; - f->test_frame_sync_state_upper = 0; - f->total_bits = 0; - f->total_bit_errors = 0; - f->total_bits_coded = 0; - f->total_bit_errors_coded = 0; - - /* Init Codec 2 for this FreeDV mode ----------------------------------------------------*/ - - f->codec2 = codec2_create(codec2_mode); - if (f->codec2 == NULL) - return NULL; - - /* work out how many codec 2 frames per mode frame, and number of - bytes of storage for packed and unpacket bits. TODO: do we really - need to work in packed bits at all? It's messy, chars would probably - be OK.... */ - - if ((mode == FREEDV_MODE_1600) || (mode == FREEDV_MODE_2400A) || (mode == FREEDV_MODE_2400B)) { - f->n_speech_samples = codec2_samples_per_frame(f->codec2); - f->n_codec_bits = codec2_bits_per_frame(f->codec2); - nbit = f->n_codec_bits; - nbyte = (nbit + 7) / 8; - } else if (mode == FREEDV_MODE_800XA) { - f->n_speech_samples = 2*codec2_samples_per_frame(f->codec2); - f->n_codec_bits = codec2_bits_per_frame(f->codec2); - nbit = f->n_codec_bits; - nbyte = (nbit + 7) / 8; - nbyte = nbyte*2; - nbit = 8*nbyte; - f->n_codec_bits = nbit; - } else if ((mode == FREEDV_MODE_700) || (mode == FREEDV_MODE_700B) || (mode == FREEDV_MODE_700C)) { - f->n_speech_samples = 2*codec2_samples_per_frame(f->codec2); - f->n_codec_bits = 2*codec2_bits_per_frame(f->codec2); - nbit = f->n_codec_bits; - nbyte = 2*((codec2_bits_per_frame(f->codec2) + 7) / 8); - } else /* mode == FREEDV_MODE_700D */ { - - /* should be exactly an integer number ofCodec 2 frames in a OFDM modem frame */ - - assert((f->ldpc->data_bits_per_frame % codec2_bits_per_frame(f->codec2)) == 0); - - int Ncodec2frames = f->ldpc->data_bits_per_frame/codec2_bits_per_frame(f->codec2); - - f->n_speech_samples = Ncodec2frames*codec2_samples_per_frame(f->codec2); - f->n_codec_bits = f->interleave_frames*Ncodec2frames*codec2_bits_per_frame(f->codec2); - nbit = codec2_bits_per_frame(f->codec2); - nbyte = (nbit + 7) / 8; - nbyte = nbyte*Ncodec2frames*f->interleave_frames; - f->nbyte_packed_codec_bits = nbyte; - - //fprintf(stderr, "Ncodec2frames: %d n_speech_samples: %d n_codec_bits: %d nbit: %d nbyte: %d\n", - // Ncodec2frames, f->n_speech_samples, f->n_codec_bits, nbit, nbyte); - - f->packed_codec_bits_tx = (unsigned char*) malloc(nbyte*sizeof(char)); - if (f->packed_codec_bits_tx == NULL) return(NULL); - f->codec_bits = NULL; - } - - f->packed_codec_bits = (unsigned char*) malloc(nbyte*sizeof(char)); - if (f->packed_codec_bits == NULL) return(NULL); - - if (mode == FREEDV_MODE_1600) - f->codec_bits = (int*) malloc(nbit*sizeof(int)); - - if ((mode == FREEDV_MODE_700) || (mode == FREEDV_MODE_700B) || (mode == FREEDV_MODE_700C)) - f->codec_bits = (int*) malloc(COHPSK_BITS_PER_FRAME*sizeof(int)); - - /* Note: VHF Framer/deframer goes directly from packed codec/vc/proto bits to filled frame */ - - if (f->packed_codec_bits == NULL) { - if (f->codec_bits != NULL) {free(f->codec_bits); f->codec_bits = NULL; } - return NULL; - } - - /* Sample rate conversion for modes using COHPSK */ - - if ((mode == FREEDV_MODE_700) || (mode == FREEDV_MODE_700B) || (mode == FREEDV_MODE_700C) ) { - f->ptFilter7500to8000 = (struct quisk_cfFilter *) malloc(sizeof(struct quisk_cfFilter)); - f->ptFilter8000to7500 = (struct quisk_cfFilter *) malloc(sizeof(struct quisk_cfFilter)); - quisk_filt_cfInit(f->ptFilter8000to7500, quiskFilt120t480, sizeof(quiskFilt120t480)/sizeof(float)); - quisk_filt_cfInit(f->ptFilter7500to8000, quiskFilt120t480, sizeof(quiskFilt120t480)/sizeof(float)); - } else { - f->ptFilter7500to8000 = NULL; - f->ptFilter8000to7500 = NULL; - } - - /* Varicode low bit rate text states */ - - varicode_decode_init(&f->varicode_dec_states, 1); - f->nvaricode_bits = 0; - f->varicode_bit_index = 0; - f->freedv_get_next_tx_char = NULL; - f->freedv_put_next_rx_char = NULL; - f->freedv_put_next_proto = NULL; - f->freedv_get_next_proto = NULL; - f->total_bit_errors = 0; - - return f; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: freedv_close - AUTHOR......: David Rowe - DATE CREATED: 3 August 2014 - - Frees up memory. - -\*---------------------------------------------------------------------------*/ - -void freedv_close(struct freedv *freedv) { - assert(freedv != NULL); - - free(freedv->packed_codec_bits); - free(freedv->codec_bits); - free(freedv->tx_bits); - if (freedv->mode == FREEDV_MODE_1600) - fdmdv_destroy(freedv->fdmdv); - if ((freedv->mode == FREEDV_MODE_700) || (freedv->mode == FREEDV_MODE_700B) || (freedv->mode == FREEDV_MODE_700C)) - cohpsk_destroy(freedv->cohpsk); - if (freedv->mode == FREEDV_MODE_700D) { - free(freedv->packed_codec_bits_tx); - if (freedv->interleave_frames > 1) - free(freedv->mod_out); - free(freedv->codeword_symbols); - free(freedv->codeword_amps); - free(freedv->ldpc); - ofdm_destroy(freedv->ofdm); - } - if ((freedv->mode == FREEDV_MODE_2400A) || (freedv->mode == FREEDV_MODE_800XA)){ - fsk_destroy(freedv->fsk); - fvhff_destroy_deframer(freedv->deframer); - } - - if (freedv->mode == FREEDV_MODE_2400B){ - fmfsk_destroy(freedv->fmfsk); - fvhff_destroy_deframer(freedv->deframer); - } - - codec2_destroy(freedv->codec2); - if (freedv->ptFilter8000to7500) { - quisk_filt_destroy(freedv->ptFilter8000to7500); - free(freedv->ptFilter8000to7500); - freedv->ptFilter8000to7500 = NULL; - } - if (freedv->ptFilter7500to8000) { - quisk_filt_destroy(freedv->ptFilter7500to8000); - free(freedv->ptFilter7500to8000); - freedv->ptFilter7500to8000 = NULL; - } - free(freedv); -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: freedv_tx - AUTHOR......: David Rowe - DATE CREATED: 3 August 2014 - - Takes a frame of input speech samples, encodes and modulates them to - produce a frame of modem samples that can be sent to the - transmitter. See freedv_tx.c for an example. - - speech_in[] is sampled at 8000 Hz, and the user must supply a block - of exactly freedv_get_n_speech_samples(). The speech_in[] level - should be such that the peak speech level is between +/- 16384 and - +/- 32767. - - The FDM modem signal mod_out[] is sampled at 8000 Hz and is - freedv_get_n_nom_modem_samples() long. mod_out[] will be scaled - such that the peak level is just less than +/-32767. - - The complex-valued output can directly drive an I/Q modulator to - produce a single sideband signal. To generate the other sideband, - take the complex conjugate of mod_out[]. - - The FreeDV 1600 modem has a high crest factor (around 12dB), however - the energy and duration of the peaks is small. FreeDV 1600 is - usually operated at a "backoff" of 8dB. Adjust the power amplifier - drive so that the average power is 8dB less than the peak power of - the PA. For example, on a radio rated at 100W PEP for SSB, the - average FreeDV power is typically 20W. - - The FreeDV 700 modem has a crest factor of about 8dB (with - f->clip=1, the default), so if your PA can handle it, it can be - driven harder than FreeDV 1600. Caution - some PAs cannot handle a - high continuous power. A conservative level is 20W average for a - 100W PEP rated PA. - -\*---------------------------------------------------------------------------*/ - -/* real-valued short sample output, useful for going straight to DAC */ - -/* TX routines for 2400 FSK modes, after codec2 encoding */ -static void freedv_tx_fsk_voice(struct freedv *f, short mod_out[]) { - int i; - float *tx_float; /* To hold on to modulated samps from fsk/fmfsk */ - uint8_t vc_bits[2]; /* Varicode bits for 2400 framing */ - uint8_t proto_bits[3]; /* Prococol bits for 2400 framing */ - - /* Frame for 2400A/B */ - if(f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_2400B){ - /* Get varicode bits for TX and possibly ask for a new char */ - /* 2 bits per 2400A/B frame, so this has to be done twice */ - for(i=0;i<2;i++){ - if (f->nvaricode_bits) { - vc_bits[i] = f->tx_varicode_bits[f->varicode_bit_index++]; - f->nvaricode_bits--; - } - - if (f->nvaricode_bits == 0) { - /* get new char and encode */ - char s[2]; - if (f->freedv_get_next_tx_char != NULL) { - s[0] = (*f->freedv_get_next_tx_char)(f->callback_state); - f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, 1); - f->varicode_bit_index = 0; - } - } - } - - /* If the API user hasn't set up message callbacks, don't bother with varicode bits */ - if(f->freedv_get_next_proto != NULL){ - (*f->freedv_get_next_proto)(f->proto_callback_state,(char*)proto_bits); - fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),proto_bits,vc_bits); - }else if(f->freedv_get_next_tx_char != NULL){ - fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,vc_bits); - }else { - fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,NULL); - } - /* Frame for 800XA */ - }else if(f->mode == FREEDV_MODE_800XA){ - fvhff_frame_bits(FREEDV_HF_FRAME_B,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,NULL); - } - - /* Allocate floating point buffer for FSK mod */ - tx_float = (float*) malloc(sizeof(float)*f->n_nom_modem_samples); - - /* do 4fsk mod */ - if(f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_800XA){ - if (f->ext_vco) { - fsk_mod_ext_vco(f->fsk,tx_float,(uint8_t*)(f->tx_bits)); - for(i=0; in_nom_modem_samples; i++){ - mod_out[i] = (short)tx_float[i]; - } - } - else { - fsk_mod(f->fsk,tx_float,(uint8_t*)(f->tx_bits)); - /* Convert float samps to short */ - for(i=0; in_nom_modem_samples; i++){ - mod_out[i] = (short)(tx_float[i]*FSK_SCALE*NORM_PWR_FSK); - } - } - /* do me-fsk mod */ - }else if(f->mode == FREEDV_MODE_2400B){ - fmfsk_mod(f->fmfsk,tx_float,(uint8_t*)(f->tx_bits)); - /* Convert float samps to short */ - for(i=0; in_nom_modem_samples; i++){ - mod_out[i] = (short)(tx_float[i]*FMFSK_SCALE); - } - } - - free(tx_float); -} - -/* TX routines for 2400 FSK modes, after codec2 encoding */ -static void freedv_comptx_fsk_voice(struct freedv *f, COMP mod_out[]) { - int i; - float *tx_float; /* To hold on to modulated samps from fsk/fmfsk */ - uint8_t vc_bits[2]; /* Varicode bits for 2400 framing */ - uint8_t proto_bits[3]; /* Prococol bits for 2400 framing */ - - /* Frame for 2400A/B */ - if(f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_2400B){ - /* Get varicode bits for TX and possibly ask for a new char */ - /* 2 bits per 2400A/B frame, so this has to be done twice */ - for(i=0;i<2;i++){ - if (f->nvaricode_bits) { - vc_bits[i] = f->tx_varicode_bits[f->varicode_bit_index++]; - f->nvaricode_bits--; - } - - if (f->nvaricode_bits == 0) { - /* get new char and encode */ - char s[2]; - if (f->freedv_get_next_tx_char != NULL) { - s[0] = (*f->freedv_get_next_tx_char)(f->callback_state); - f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, 1); - f->varicode_bit_index = 0; - } - } - } - - /* If the API user hasn't set up message callbacks, don't bother with varicode bits */ - if(f->freedv_get_next_proto != NULL){ - (*f->freedv_get_next_proto)(f->proto_callback_state,(char*)proto_bits); - fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),proto_bits,vc_bits); - }else if(f->freedv_get_next_tx_char != NULL){ - fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,vc_bits); - }else { - fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,NULL); - } - /* Frame for 800XA */ - }else if(f->mode == FREEDV_MODE_800XA){ - fvhff_frame_bits(FREEDV_HF_FRAME_B,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,NULL); - } - - /* Allocate floating point buffer for FSK mod */ - tx_float = (float*) malloc(sizeof(float)*f->n_nom_modem_samples); - - /* do 4fsk mod */ - if(f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_800XA){ - fsk_mod_c(f->fsk,mod_out,(uint8_t*)(f->tx_bits)); - /* Convert float samps to short */ - for(i=0; in_nom_modem_samples; i++){ - mod_out[i] = fcmult(NORM_PWR_FSK,mod_out[i]); - } - /* do me-fsk mod */ - }else if(f->mode == FREEDV_MODE_2400B){ - fmfsk_mod(f->fmfsk,tx_float,(uint8_t*)(f->tx_bits)); - /* Convert float samps to short */ - for(i=0; in_nom_modem_samples; i++){ - mod_out[i].real = (tx_float[i]); - } - } - - free(tx_float); -} - - -/* TX routines for 2400 FSK modes, data channel */ -static void freedv_tx_fsk_data(struct freedv *f, short mod_out[]) { - int i; - float *tx_float; /* To hold on to modulated samps from fsk/fmfsk */ - - if (f->mode != FREEDV_MODE_800XA) - fvhff_frame_data_bits(f->deframer, FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits)); - else - fvhff_frame_data_bits(f->deframer, FREEDV_HF_FRAME_B,(uint8_t*)(f->tx_bits)); - - /* Allocate floating point buffer for FSK mod */ - tx_float = (float*) malloc(sizeof(float)*f->n_nom_modem_samples); - - /* do 4fsk mod */ - if(f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_800XA){ - fsk_mod(f->fsk,tx_float,(uint8_t*)(f->tx_bits)); - /* Convert float samps to short */ - for(i=0; in_nom_modem_samples; i++){ - mod_out[i] = (short)(tx_float[i]*FSK_SCALE); - } - /* do me-fsk mod */ - }else if(f->mode == FREEDV_MODE_2400B){ - fmfsk_mod(f->fmfsk,tx_float,(uint8_t*)(f->tx_bits)); - /* Convert float samps to short */ - for(i=0; in_nom_modem_samples; i++){ - mod_out[i] = (short)(tx_float[i]*FMFSK_SCALE); - } - } - - free(tx_float); -} - -void freedv_tx(struct freedv *f, short mod_out[], short speech_in[]) { - assert(f != NULL); - COMP *tx_fdm = new COMP[f->n_nom_modem_samples]; - int i; - assert((f->mode == FREEDV_MODE_1600) || (f->mode == FREEDV_MODE_700) || - (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C) || - (f->mode == FREEDV_MODE_700D) || - (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) || - (f->mode == FREEDV_MODE_800XA)); - - /* FSK and MEFSK/FMFSK modems work only on real samples. It's simpler to just - * stick them in the real sample tx/rx functions than to add a comp->real converter - * to comptx */ - - if ((f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) || (f->mode == FREEDV_MODE_800XA)){ - /* 800XA has two codec frames per modem frame */ - if(f->mode == FREEDV_MODE_800XA){ - codec2_encode(f->codec2, &f->packed_codec_bits[0], &speech_in[ 0]); - codec2_encode(f->codec2, &f->packed_codec_bits[4], &speech_in[320]); - }else{ - codec2_encode(f->codec2, f->packed_codec_bits, speech_in); - } - freedv_tx_fsk_voice(f, mod_out); - } else{ - freedv_comptx(f, tx_fdm, speech_in); - for(i=0; in_nom_modem_samples; i++) - mod_out[i] = tx_fdm[i].real; - } - - delete[] tx_fdm; -} - -/* complex valued output, useful for suitable for single sided freq shifting */ - -static void freedv_comptx_fdmdv_1600(struct freedv *f, COMP mod_out[]) { - int bit, byte, i, j; - int bits_per_codec_frame, bits_per_modem_frame; - int data, codeword1, data_flag_index; - COMP *tx_fdm = new COMP[f->n_nat_modem_samples]; - - bits_per_codec_frame = codec2_bits_per_frame(f->codec2); - bits_per_modem_frame = fdmdv_bits_per_frame(f->fdmdv); - - /* unpack bits, MSB first */ - - bit = 7; byte = 0; - for(i=0; icodec_bits[i] = (f->packed_codec_bits[byte] >> bit) & 0x1; - bit--; - if (bit < 0) { - bit = 7; - byte++; - } - } - - // spare bit in frame that codec defines. Use this 1 - // bit/frame to send txt messages - - data_flag_index = codec2_get_spare_bit_index(f->codec2); - - if (f->nvaricode_bits) { - f->codec_bits[data_flag_index] = f->tx_varicode_bits[f->varicode_bit_index++]; - f->nvaricode_bits--; - } - - if (f->nvaricode_bits == 0) { - /* get new char and encode */ - char s[2]; - if (f->freedv_get_next_tx_char != NULL) { - s[0] = (*f->freedv_get_next_tx_char)(f->callback_state); - f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, 1); - f->varicode_bit_index = 0; - } - } - - /* Protect first 12 out of first 16 excitation bits with (23,12) Golay Code: - - 0,1,2,3: v[0]..v[1] - 4,5,6,7: MSB of pitch - 11,12,13,14: MSB of energy - - */ - - data = 0; - for(i=0; i<8; i++) { - data <<= 1; - data |= f->codec_bits[i]; - } - for(i=11; i<15; i++) { - data <<= 1; - data |= f->codec_bits[i]; - } - codeword1 = golay23_encode(data); - - /* now pack output frame with parity bits at end to make them - as far apart as possible from the data they protect. Parity - bits are LSB of the Golay codeword */ - - for(i=0; itx_bits[i] = f->codec_bits[i]; - for(j=0; itx_bits[i] = (codeword1 >> (10-j)) & 0x1; - } - f->tx_bits[i] = 0; /* spare bit */ - - /* optionally overwrite with test frames */ - - if (f->test_frames) { - fdmdv_get_test_bits(f->fdmdv, f->tx_bits); - fdmdv_get_test_bits(f->fdmdv, &f->tx_bits[bits_per_modem_frame]); - //fprintf(stderr, "test frames on tx\n"); - } - - /* modulate even and odd frames */ - - fdmdv_mod(f->fdmdv, tx_fdm, f->tx_bits, &f->tx_sync_bit); - assert(f->tx_sync_bit == 1); - - fdmdv_mod(f->fdmdv, &tx_fdm[FDMDV_NOM_SAMPLES_PER_FRAME], &f->tx_bits[bits_per_modem_frame], &f->tx_sync_bit); - assert(f->tx_sync_bit == 0); - - assert(2*FDMDV_NOM_SAMPLES_PER_FRAME == f->n_nom_modem_samples); - - for(i=0; in_nom_modem_samples; i++) - mod_out[i] = fcmult(FDMDV_SCALE, tx_fdm[i]); - - delete[] tx_fdm; -} - -static void freedv_comptx_700(struct freedv *f, COMP mod_out[]) { - int bit, byte, i, j, k; - int bits_per_codec_frame, bits_per_modem_frame; - int data_flag_index, nspare; - COMP *tx_fdm = new COMP[f->n_nat_modem_samples]; - - bits_per_codec_frame = codec2_bits_per_frame(f->codec2); - bits_per_modem_frame = COHPSK_BITS_PER_FRAME; - - byte = 0; - for (j=0; jcodec_bits[j+i] = (f->packed_codec_bits[byte] >> bit) & 0x1; - bit--; - if (bit < 0) { - bit = 7; - byte++; - } - } - if (bit != 7) - byte++; - - // spare bits in frame that codec defines. Use these spare - // bits/frame to send txt messages - - switch(f->mode) { - case FREEDV_MODE_700: - nspare = 2; - break; - case FREEDV_MODE_700B: - nspare = 1; // Just one spare bit for FREEDV_MODE_700B - break; - case FREEDV_MODE_700C: - nspare = 0; // and no spare bits for 700C atm - break; - default: - nspare = 0; - fprintf(stderr, "FreeDV::freedv_comptx_700: unknown mode default to nspare = 0"); - } - - data_flag_index = codec2_get_spare_bit_index(f->codec2); - - for(k=0; knvaricode_bits) { - f->codec_bits[j+data_flag_index+k] = f->tx_varicode_bits[f->varicode_bit_index++]; - //fprintf(stderr, "%d %d\n", j+data_flag_index+k, f->codec_bits[j+data_flag_index+k]); - f->nvaricode_bits--; - } - if (f->nvaricode_bits == 0) { - /* get new char and encode */ - char s[2]; - if (f->freedv_get_next_tx_char != NULL) { - s[0] = (*f->freedv_get_next_tx_char)(f->callback_state); - f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, 1); - f->varicode_bit_index = 0; - } - } - } - } - /* optionally ovwerwrite the codec bits with test frames */ - - if (f->test_frames) { - cohpsk_get_test_bits(f->cohpsk, f->codec_bits); - } - - /* cohpsk modulator */ - - cohpsk_mod(f->cohpsk, tx_fdm, f->codec_bits, COHPSK_BITS_PER_FRAME); - if (f->clip) - cohpsk_clip(tx_fdm, COHPSK_CLIP, COHPSK_NOM_SAMPLES_PER_FRAME); - for(i=0; in_nat_modem_samples; i++) - mod_out[i] = fcmult(FDMDV_SCALE*NORM_PWR_COHPSK, tx_fdm[i]); - i = quisk_cfInterpDecim((std::complex *)mod_out, f->n_nat_modem_samples, f->ptFilter7500to8000, 16, 15); - //assert(i == f->n_nom_modem_samples); - // Caution: assert fails if f->n_nat_modem_samples * 16.0 / 15.0 is not an integer - - delete[] tx_fdm; - -} - -/* - Ok so when interleaved, we take the interleaver length of input samples, - and output that many modem samples, e.g. for interleaver of length 4: - - record input speech 1234 - freedv tx | - play modem sig 1234 - record modem sig 1234 - freedv_rx | - play output speech 1234 - time axis --------->123456789012----> - - So a sample of input speech at time 1 is ouput at time 9. We assume - the freedv_tx and freedv_rx and propogation time over channel (from - when a modem signal is played at the HF tx to when it is recorded at - the HF rx) is zero. - - The freedv tx interface ouputs n_nom_modem_samples, which a single - OFDM modem frame, 112 payload bits or 4 speech codec frames. So - this function must always have 1280 speech samples as input, and - 1280 modem samples as output, regradless of interleaver_frames. For - interleaver_frames > 1, we need to buffer samples. -*/ - -static void freedv_comptx_700d(struct freedv *f, COMP mod_out[]) { - int bit, byte, i, j, k; - int nspare; - - int data_bits_per_frame = f->ldpc->data_bits_per_frame; - int bits_per_interleaved_frame = f->interleave_frames*data_bits_per_frame; - uint8_t *tx_bits = new uint8_t[bits_per_interleaved_frame]; - int bits_per_codec_frame = codec2_bits_per_frame(f->codec2); - - byte = 0; - for (j=0; jpacked_codec_bits_tx[byte] >> bit) & 0x1; - bit--; - if (bit < 0) { - bit = 7; - byte++; - } - } - if (bit != 7) - byte++; - } - - assert(byte <= f->nbyte_packed_codec_bits); - - // Generate Varicode txt bits. Txt bits in OFDM frame come just - // after Unique Word (UW). Txt bits aren't protected by FEC, and need to be - // added to each frame after interleaver as done it's thing - - nspare = ofdm_ntxtbits*f->interleave_frames; - uint8_t *txt_bits = new uint8_t[nspare]; - - for(k=0; knvaricode_bits == 0) { - /* get new char and encode */ - char s[2]; - if (f->freedv_get_next_tx_char != NULL) { - s[0] = (*f->freedv_get_next_tx_char)(f->callback_state); - f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, 1); - f->varicode_bit_index = 0; - } - } - if (f->nvaricode_bits) { - txt_bits[k] = f->tx_varicode_bits[f->varicode_bit_index++]; - f->nvaricode_bits--; - } - } - - /* optionally replace codec payload bits with test frames known to rx */ - - if (f->test_frames) { - uint8_t *payload_data_bits = new uint8_t[data_bits_per_frame]; - ofdm_generate_payload_data_bits(payload_data_bits, data_bits_per_frame); - - for (j=0; jinterleave_frames; j++) { - for(i=0; i *tx_sams = new std::complex[f->interleave_frames*f->n_nat_modem_samples]; - COMP asam; - - ofdm_ldpc_interleave_tx(f->ofdm, f->ldpc, tx_sams, tx_bits, txt_bits, f->interleave_frames, ofdm_config); - - for(i=0; iinterleave_frames*f->n_nat_modem_samples; i++) { - asam.real = tx_sams[i].real(); - asam.imag = tx_sams[i].imag(); - mod_out[i] = fcmult(OFDM_AMP_SCALE*NORM_PWR_OFDM, asam); - } - - if (f->clip) { - //fprintf(stderr, "clip "); - cohpsk_clip(mod_out, OFDM_CLIP, f->interleave_frames*f->n_nat_modem_samples); - } - - delete[] tx_sams; - delete[] txt_bits; - delete[] tx_bits; -} - - - -void freedv_comptx(struct freedv *f, COMP mod_out[], short speech_in[]) { - assert(f != NULL); - - assert((f->mode == FREEDV_MODE_1600) || (f->mode == FREEDV_MODE_700) || - (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C) || - (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) || - (f->mode == FREEDV_MODE_700D)); - - if (f->mode == FREEDV_MODE_1600) { - codec2_encode(f->codec2, f->packed_codec_bits, speech_in); - freedv_comptx_fdmdv_1600(f, mod_out); - } - - - int bits_per_codec_frame = codec2_bits_per_frame(f->codec2); - int bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8; - int i,j; - - /* all these modes need to pack a bunch of codec frames into one modem frame */ - - if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C)) { - int codec_frames = f->n_codec_bits / bits_per_codec_frame; - - for (j=0; jcodec2, f->packed_codec_bits + j * bytes_per_codec_frame, speech_in); - speech_in += codec2_samples_per_frame(f->codec2); - } - freedv_comptx_700(f, mod_out); - } - - /* special treatment due to interleaver */ - - if (f->mode == FREEDV_MODE_700D) { - int data_bits_per_frame = f->ldpc->data_bits_per_frame; - int codec_frames = data_bits_per_frame / bits_per_codec_frame; - - //fprintf(stderr, "modem_frame_count_tx: %d dec_frames: %d bytes offset: %d\n", - // f->modem_frame_count_tx, codec_frames, (f->modem_frame_count_tx*codec_frames)*bytes_per_codec_frame); - - /* buffer up bits until we get enough encoded bits for interleaver */ - - for (j=0; jcodec2, f->packed_codec_bits_tx + (f->modem_frame_count_tx*codec_frames+j)*bytes_per_codec_frame, speech_in); - speech_in += codec2_samples_per_frame(f->codec2); - } - - - /* Only use extra local buffer if needed for interleave > 1 */ - if (f->interleave_frames == 1) { - freedv_comptx_700d(f, mod_out); - } else { - /* call modulate function when we have enough frames to run interleaver */ - assert((f->modem_frame_count_tx >= 0) && - (f->modem_frame_count_tx < f->interleave_frames)); - f->modem_frame_count_tx++; - if (f->modem_frame_count_tx == f->interleave_frames) { - freedv_comptx_700d(f, f->mod_out); - //fprintf(stderr, " calling freedv_comptx_700d()\n"); - f->modem_frame_count_tx = 0; - } - /* output n_nom_modem_samples at a time from modulated buffer */ - for(i=0; in_nat_modem_samples; i++) { - mod_out[i] = - f->mod_out[f->modem_frame_count_tx * f->n_nat_modem_samples+i]; - } - } - - } - - /* 2400 A and B are handled by the real-mode TX */ - if((f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B)){ - codec2_encode(f->codec2, f->packed_codec_bits, speech_in); - freedv_comptx_fsk_voice(f,mod_out); - } -} - -void freedv_codectx(struct freedv *f, short mod_out[], unsigned char *packed_codec_bits) { - assert(f != NULL); - COMP *tx_fdm = new COMP[f->n_nom_modem_samples]; - int bits_per_codec_frame; - int bytes_per_codec_frame; - int codec_frames; - int i; - bits_per_codec_frame = codec2_bits_per_frame(f->codec2); - bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8; - codec_frames = f->n_codec_bits / bits_per_codec_frame; - - memcpy(f->packed_codec_bits, packed_codec_bits, bytes_per_codec_frame * codec_frames); - - switch(f->mode) { - case FREEDV_MODE_1600: - freedv_comptx_fdmdv_1600(f, tx_fdm); - break; - case FREEDV_MODE_700: - case FREEDV_MODE_700B: - case FREEDV_MODE_700C: - freedv_comptx_700(f, tx_fdm); - break; - case FREEDV_MODE_700D: { - /* special treatment due to interleaver */ - int data_bits_per_frame = f->ldpc->data_bits_per_frame; - int codec_frames = data_bits_per_frame / bits_per_codec_frame; - int j; - - /* buffer up bits until we get enough encoded bits for interleaver */ - - for (j=0; jpacked_codec_bits_tx + (f->modem_frame_count_tx*codec_frames+j)*bytes_per_codec_frame, packed_codec_bits, bytes_per_codec_frame); - packed_codec_bits += bytes_per_codec_frame; - } - - /* call modulate function when we have enough frames to run interleaver */ - - assert((f->modem_frame_count_tx >= 0) && (f->modem_frame_count_tx < f->interleave_frames)); - f->modem_frame_count_tx++; - if (f->modem_frame_count_tx == f->interleave_frames) { - freedv_comptx_700d(f, f->mod_out); - f->modem_frame_count_tx = 0; - } - - /* output n_nom_modem_samples at a time from modulated buffer */ - for(i=0; in_nat_modem_samples; i++) { - mod_out[i] = f->mod_out[f->modem_frame_count_tx*f->n_nat_modem_samples+i].real; - } - - return; /* output is already real */ - } - case FREEDV_MODE_2400A: - case FREEDV_MODE_2400B: - case FREEDV_MODE_800XA: - freedv_tx_fsk_voice(f, mod_out); - return; /* output is already real */ - } - /* convert complex to real */ - for(i=0; in_nom_modem_samples; i++) - mod_out[i] = tx_fdm[i].real; - - delete[] tx_fdm; -} - -void freedv_datatx (struct freedv *f, short mod_out[]){ - assert(f != NULL); - if (f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_2400B || f->mode == FREEDV_MODE_800XA) { - freedv_tx_fsk_data(f, mod_out); - } -} - -int freedv_data_ntxframes (struct freedv *f){ - assert(f != NULL); - if (f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_2400B) { - if (f->deframer->fdc) - return freedv_data_get_n_tx_frames(f->deframer->fdc, 8); - } else if (f->mode == FREEDV_MODE_800XA) { - if (f->deframer->fdc) - return freedv_data_get_n_tx_frames(f->deframer->fdc, 6); - } - return 0; -} - -int freedv_nin(struct freedv *f) { - if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C)) - // For mode 700, the input rate is 8000 sps, but the modem rate is 7500 sps - // For mode 700, we request a larger number of Rx samples that will be decimated to f->nin samples - return (16 * f->nin + f->ptFilter8000to7500->decim_index) / 15; - else - return f->nin; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: freedv_rx - AUTHOR......: David Rowe - DATE CREATED: 3 August 2014 - - Takes a frame of samples from the radio receiver, demodulates and - decodes them, producing a frame of decoded speech samples. See - freedv_rx.c for an example. - - demod_in[] is a block of received samples sampled at 8000 Hz. - To account for difference in the transmit and receive sample clock - frequencies, the number of demod_in[] samples is time varying. You - MUST call freedv_nin() BEFORE each call to freedv_rx() and pass - exactly that many samples to this function. - - To help set your buffer sizes, The maximum value of freedv_nin() is - freedv_get_n_max_modem_samples(). - - freedv_rx() returns the number of output speech samples available in - speech_out[], which is sampled at 8000 Hz. You should ALWAYS check - the return value of freedv_rx(), and read EXACTLY that number of - speech samples from speech_out[]. - - 1600 and 700D mode: When out of sync, the number of output speech - samples returned will be freedv_nin(). When in sync to a valid - FreeDV 1600 signal, the number of output speech samples will - alternate between freedv_get_n_speech_samples() and 0. - - 700 .. 700C modes: The number of output speech samples returned will - always be freedv_get_n_speech_samples(), regardless of sync. - - The peak level of demod_in[] is not critical, as the demod works - well over a wide range of amplitude scaling. However avoid clipping - (overload, or samples pinned to +/- 32767). speech_out[] will peak - at just less than +/-32767. - - When out of sync, this function echoes the demod_in[] samples to - speech_out[]. This allows the user to listen to the channel, which - is useful for tuning FreeDV signals or reception of non-FreeDV - signals. Setting the squelch with freedv_set_squelch_en(1) will - return zero-valued samples instead. - -\*---------------------------------------------------------------------------*/ - - -// short version - -int freedv_rx(struct freedv *f, short speech_out[], short demod_in[]) { - assert(f != NULL); - int i; - int nin = freedv_nin(f); - - assert(nin <= f->n_max_modem_samples); - - /* FSK RX happens in real floats, so convert to those and call their demod here */ - if( (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) || (f->mode == FREEDV_MODE_800XA) ){ - float *rx_float = new float[f->n_max_modem_samples]; - for(i=0; imode == FREEDV_MODE_1600) || (f->mode == FREEDV_MODE_700) || - (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C)) { - - float gain = 1.0; - - /* FDM RX happens with complex samps, so do that */ - COMP *rx_fdm = new COMP[f->n_max_modem_samples]; - for(i=0; imode == FREEDV_MODE_700D) { - float gain = 2.0; /* keep levels the same as Octave simulations and C unit tests for real signals */ - return freedv_shortrx(f, speech_out, demod_in, gain); - } - - return 0; /* should never get here */ -} - - -// float input samples version -int freedv_comprx_fsk(struct freedv *f, COMP demod_in[], int *valid) { - /* Varicode and protocol bits */ - uint8_t vc_bits[2]; - uint8_t proto_bits[3]; - short vc_bit; - int i; - int n_ascii; - char ascii_out; - - if(f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_800XA){ - fsk_demod(f->fsk,(uint8_t*)f->tx_bits,demod_in); - f->nin = fsk_nin(f->fsk); - float EbNodB = f->fsk->stats->snr_est; /* fsk demod actually estimates Eb/No */ - f->snr_est = EbNodB + 10.0*log10f(800.0/3000.0); /* so convert to SNR Rb=800, noise B=3000 */ - //fprintf(stderr," %f %f\n", EbNodB, f->snr_est); - } else{ - /* 2400B needs real input samples */ - int n = fmfsk_nin(f->fmfsk); - float *demod_in_float = new float[n]; - for(i=0; ifmfsk,(uint8_t*)f->tx_bits,demod_in_float); - delete[] demod_in_float; - f->nin = fmfsk_nin(f->fmfsk); - } - - if(fvhff_deframe_bits(f->deframer,f->packed_codec_bits,proto_bits,vc_bits,(uint8_t*)f->tx_bits)){ - /* Decode varicode text */ - for(i=0; i<2; i++){ - /* Note: deframe_bits spits out bits in uint8_ts while varicode_decode expects shorts */ - vc_bit = vc_bits[i]; - n_ascii = varicode_decode(&f->varicode_dec_states, &ascii_out, &vc_bit, 1, 1); - if (n_ascii && (f->freedv_put_next_rx_char != NULL)) { - (*f->freedv_put_next_rx_char)(f->callback_state, ascii_out); - } - } - /* Pass proto bits on down if callback is present */ - if( f->freedv_put_next_proto != NULL){ - (*f->freedv_put_next_proto)(f->proto_callback_state,(char*)proto_bits); - } - *valid = 1; - - /* squelch if if sync but SNR too low */ - if (f->squelch_en && (f->snr_est < f->snr_squelch_thresh)) { - *valid = 0; - } - } else { - /* squelch if out of sync, or echo input of squelch off */ - if (f->squelch_en) - *valid = 0; - else - *valid = -1; - } - f->sync = f->deframer->state; - f->stats.sync = f->deframer->state; - - return f->n_speech_samples; -} - -int freedv_floatrx(struct freedv *f, short speech_out[], float demod_in[]) { - assert(f != NULL); - int i; - int nin = freedv_nin(f); - - assert(nin <= f->n_max_modem_samples); - - COMP *rx_fdm = new COMP[f->n_max_modem_samples]; - for(i=0; icodec2); - bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8; - nout = f->n_speech_samples; - - COMP *ademod_in = new COMP[f->nin]; - for(i=0; inin; i++) - ademod_in[i] = fcmult(1.0/FDMDV_SCALE, demod_in[i]); - - bits_per_fdmdv_frame = fdmdv_bits_per_frame(f->fdmdv); - - nin_prev = f->nin; - fdmdv_demod(f->fdmdv, f->fdmdv_bits, &reliable_sync_bit, ademod_in, &f->nin); - fdmdv_get_demod_stats(f->fdmdv, &f->stats); - f->sync = f->fdmdv->sync; - f->snr_est = f->stats.snr_est; - - if (reliable_sync_bit == 1) { - f->evenframe = 1; - } - - if (f->stats.sync) { - if (f->evenframe == 0) { - memcpy(f->rx_bits, f->fdmdv_bits, bits_per_fdmdv_frame*sizeof(int)); - nout = 0; - *valid = 0; - } - else { - memcpy(&f->rx_bits[bits_per_fdmdv_frame], f->fdmdv_bits, bits_per_fdmdv_frame*sizeof(int)); - - if (f->test_frames == 0) { - recd_codeword = 0; - for(i=0; i<8; i++) { - recd_codeword <<= 1; - recd_codeword |= (f->rx_bits[i] & 0x1); - } - for(i=11; i<15; i++) { - recd_codeword <<= 1; - recd_codeword |= (f->rx_bits[i] & 0x1); - } - for(i=bits_per_codec_frame; irx_bits[i] & 0x1); - } - codeword1 = golay23_decode(recd_codeword); - f->total_bit_errors += golay23_count_errors(recd_codeword, codeword1); - f->total_bits += 23; - - //codeword1 = recd_codeword; - //fprintf(stderr, "received codeword1: 0x%x decoded codeword1: 0x%x\n", recd_codeword, codeword1); - - for(i=0; icodec_bits[i] = f->rx_bits[i]; - - for(i=0; i<8; i++) { - f->codec_bits[i] = (codeword1 >> (22-i)) & 0x1; - } - for(i=8,j=11; i<12; i++,j++) { - f->codec_bits[j] = (codeword1 >> (22-i)) & 0x1; - } - - // extract txt msg data bit ------------------------------------------------------------ - - data_flag_index = codec2_get_spare_bit_index(f->codec2); - abit[0] = f->codec_bits[data_flag_index]; - - n_ascii = varicode_decode(&f->varicode_dec_states, &ascii_out, abit, 1, 1); - if (n_ascii && (f->freedv_put_next_rx_char != NULL)) { - (*f->freedv_put_next_rx_char)(f->callback_state, ascii_out); - } - - // reconstruct missing bit we steal for data bit and decode speech - - codec2_rebuild_spare_bit(f->codec2, f->codec_bits); - - // pack bits, MSB received first - - bit = 7; - byte = 0; - memset(f->packed_codec_bits, 0, bytes_per_codec_frame); - for(i=0; ipacked_codec_bits[byte] |= (f->codec_bits[i] << bit); - bit--; - if(bit < 0) { - bit = 7; - byte++; - } - } - *valid = 1; - } - else { - int test_frame_sync, bit_errors, ntest_bits, k; - short *error_pattern = new short[fdmdv_error_pattern_size(f->fdmdv)]; - - for(k=0; k<2; k++) { - /* test frames, so lets sync up to the test frames and count any errors */ - - fdmdv_put_test_bits(f->fdmdv, &test_frame_sync, error_pattern, &bit_errors, &ntest_bits, &f->rx_bits[k*bits_per_fdmdv_frame]); - - if (test_frame_sync == 1) { - f->test_frame_sync_state = 1; - f->test_frame_count = 0; - } - - if (f->test_frame_sync_state) { - if (f->test_frame_count == 0) { - f->total_bit_errors += bit_errors; - f->total_bits += ntest_bits; - if (f->freedv_put_error_pattern != NULL) { - (*f->freedv_put_error_pattern)(f->error_pattern_callback_state, error_pattern, fdmdv_error_pattern_size(f->fdmdv)); - } - } - f->test_frame_count++; - if (f->test_frame_count == 4) - f->test_frame_count = 0; - } - - //fprintf(stderr, "test_frame_sync: %d test_frame_sync_state: %d bit_errors: %d ntest_bits: %d\n", - // test_frame_sync, f->test_frame_sync_state, bit_errors, ntest_bits); - } - - delete[] error_pattern; - } - - - /* squelch if beneath SNR threshold or test frames enabled */ - - if ((f->squelch_en && (f->stats.snr_est < f->snr_squelch_thresh)) || f->test_frames) { - //fprintf(stderr,"squelch %f %f !\n", f->stats.snr_est, f->snr_squelch_thresh); - *valid = 0; - } - - nout = f->n_speech_samples; - - } - - /* note this freewheels if reliable sync dissapears on bad channels */ - - if (f->evenframe) - f->evenframe = 0; - else - f->evenframe = 1; - //fprintf(stderr,"%d\n", f->evenframe); - - } /* if (sync) .... */ - else { - /* if not in sync pass through analog samples */ - /* this lets us "hear" whats going on, e.g. during tuning */ - - //fprintf(stderr, "out of sync\n"); - - if (f->squelch_en == 0) { - *valid = -1; - } - else { - *valid = 0; - } - //fprintf(stderr, "%d %d %d\n", nin_prev, speech_out[0], speech_out[nin_prev-1]); - nout = nin_prev; - } - delete[] ademod_in; - return nout; -} - -static int freedv_comprx_700(struct freedv *f, COMP demod_in_8kHz[], int *valid) { - int bits_per_codec_frame, bytes_per_codec_frame; - int i, j, bit, byte, nout, k; - int data_flag_index, n_ascii, nspare; - short abit[1]; - char ascii_out; - float rx_bits[COHPSK_BITS_PER_FRAME]; /* soft decn rx bits */ - int sync; - int frames; - - bits_per_codec_frame = codec2_bits_per_frame(f->codec2); - bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8; - frames = f->n_codec_bits / bits_per_codec_frame; - nout = f->n_speech_samples; - - // echo samples back out as default (say if sync not found) - *valid = -1; - - // quisk_cfInterpDecim() modifies input data so lets make a copy just in case there - // is no sync and we need to echo inout to output - - COMP *demod_in = new COMP[freedv_nin(f)]; - for(i=0; i *)demod_in, freedv_nin(f), f->ptFilter8000to7500, 15, 16); - //if (i != f->nin) - // printf("freedv_comprx decimation: input %d output %d\n", freedv_nin(f), i); - - for(i=0; inin; i++) - demod_in[i] = fcmult(1.0/FDMDV_SCALE, demod_in[i]); - - cohpsk_demod(f->cohpsk, rx_bits, &sync, demod_in, &f->nin); - - f->sync = sync; - cohpsk_get_demod_stats(f->cohpsk, &f->stats); - f->snr_est = f->stats.snr_est; - - memset(f->packed_codec_bits, 0, bytes_per_codec_frame * frames); - - if (sync) { - - if (f->test_frames == 0) { - data_flag_index = codec2_get_spare_bit_index(f->codec2); - - /* optional smoothing of codec symbols */ - - if (f->smooth_symbols) { - - for(i=0; imode) { - case FREEDV_MODE_700: - nspare = 2; - break; - case FREEDV_MODE_700B: - nspare = 1; // Just one spare bit for FREEDV_MODE_700B - break; - case FREEDV_MODE_700C: - nspare = 0; // and no spare bits for 700C atm - break; - default: - nspare = 0; - fprintf(stderr, "FreeDV::freedv_comprx_700: unknown mode default to nspare = 0"); - } - - for(k=0; kvaricode_dec_states, &ascii_out, abit, 1, 1); - if (n_ascii && (f->freedv_put_next_rx_char != NULL)) { - (*f->freedv_put_next_rx_char)(f->callback_state, ascii_out); - } - } - - /* pack bits, MSB received first */ - - bit = 7; - for(i=0; ipacked_codec_bits[byte] |= ((rx_bits[j+i] < 0.0) << bit); - bit--; - if (bit < 0) { - bit = 7; - byte++; - } - } - if (bit != 7) - byte++; - - if (f->squelch_en && (f->stats.snr_est < f->snr_squelch_thresh)) { - *valid = 0; - } - *valid = 1; - } - nout = f->n_speech_samples; - } - else { - //fprintf(stderr, " freedv_api: f->test_frames_diversity: %d\n", f->test_frames_diversity); - - if (f->test_frames_diversity) { - /* normal operation - error pattern on frame after diveristy combination */ - short error_pattern[COHPSK_BITS_PER_FRAME]; - int bit_errors; - - /* test data, lets see if we can sync to the test data sequence */ - - char rx_bits_char[COHPSK_BITS_PER_FRAME]; - for(i=0; icohpsk, &f->test_frame_sync_state, error_pattern, &bit_errors, rx_bits_char, 0); - if (f->test_frame_sync_state) { - f->total_bit_errors += bit_errors; - f->total_bits += COHPSK_BITS_PER_FRAME; - if (f->freedv_put_error_pattern != NULL) { - (*f->freedv_put_error_pattern)(f->error_pattern_callback_state, error_pattern, COHPSK_BITS_PER_FRAME); - } - } - } - else { - /* calculate error pattern on uncombined carriers - test mode to spot any carrier specific issues like - tx passband filtering */ - - short error_pattern[2*COHPSK_BITS_PER_FRAME]; - char rx_bits_char[COHPSK_BITS_PER_FRAME]; - int bit_errors_lower, bit_errors_upper; - - /* lower group of carriers */ - - float *rx_bits_lower = cohpsk_get_rx_bits_lower(f->cohpsk); - for(i=0; icohpsk, &f->test_frame_sync_state, error_pattern, &bit_errors_lower, rx_bits_char, 0); - - /* upper group of carriers */ - - float *rx_bits_upper = cohpsk_get_rx_bits_upper(f->cohpsk); - for(i=0; icohpsk, &f->test_frame_sync_state_upper, &error_pattern[COHPSK_BITS_PER_FRAME], &bit_errors_upper, rx_bits_char, 1); - // fprintf(stderr, " freedv_api: f->test_frame_sync_state: %d f->test_frame_sync_state_upper: %d\n", - // f->test_frame_sync_state, f->test_frame_sync_state_upper); - - /* combine total errors and call callback */ - - if (f->test_frame_sync_state && f->test_frame_sync_state_upper) { - f->total_bit_errors += bit_errors_lower + bit_errors_upper; - f->total_bits += 2*COHPSK_BITS_PER_FRAME; - if (f->freedv_put_error_pattern != NULL) { - (*f->freedv_put_error_pattern)(f->error_pattern_callback_state, error_pattern, 2*COHPSK_BITS_PER_FRAME); - } - } - - } - - *valid = 0; - nout = f->n_speech_samples; - } - - } - - /* no valid FreeDV signal - squelch output */ - - if (sync == 0) { - nout = freedv_nin(f); - if (f->squelch_en) { - *valid = 0; - } - } - delete[] demod_in; - return nout; -} - -/* - TODO: - [X] in testframe mode count coded and uncoded errors - [X] freedv getter for modem and interleaver sync - [X] rms level the same as fdmdv - [X] way to stay in sync and not resync automatically - [X] SNR est, maybe from pilots, cohpsk have an example? - [X] work out how to handle return of multiple interleaved frames over time - [ ] error pattern support? - [ ] deal with out of sync returning nin samples, listening to analog audio when out of sync -*/ - -static int freedv_comprx_700d(struct freedv *f, short demod_in_8kHz[], float gain, int *valid) { - int bits_per_codec_frame, bytes_per_codec_frame; - int i, j, bit, byte, nout, k; - int n_ascii; - char ascii_out; - int frames; - struct OFDM *ofdm = f->ofdm; - struct LDPC *ldpc = f->ldpc; - - int data_bits_per_frame = ldpc->data_bits_per_frame; - int coded_bits_per_frame = ldpc->coded_bits_per_frame; - int coded_syms_per_frame = ldpc->coded_syms_per_frame; - int interleave_frames = f->interleave_frames; - COMP *codeword_symbols = f->codeword_symbols; - float *codeword_amps = f->codeword_amps; - int *rx_bits = new int[ofdm_bitsperframe]; - short *txt_bits = new short[ofdm_ntxtbits]; - COMP *payload_syms = new COMP[coded_syms_per_frame]; - float *payload_amps = new float[coded_syms_per_frame]; - - bits_per_codec_frame = codec2_bits_per_frame(f->codec2); - bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8; - frames = f->n_codec_bits / bits_per_codec_frame; - - // pass through is too noisey .... - //nout = f->n_speech_samples; - nout = 0; - - int Nerrs_raw = 0; - int Nerrs_coded = 0; - int iter = 0; - int parityCheckCount = 0; - uint8_t *rx_uw = new uint8_t[ofdm_nuwbits]; - - float new_gain = gain / OFDM_AMP_SCALE; - - /* echo samples back out as default (say if sync not found) */ - - *valid = 1; - f->sync = f->stats.sync = 0; - - /* TODO estimate this properly from signal */ - - float EsNo = 3.0; - - /* looking for modem sync */ - - if (ofdm->sync_state == search) { - ofdm_sync_search_shorts(f->ofdm, demod_in_8kHz, new_gain); - } - - /* OK modem is in sync */ - - if ((ofdm->sync_state == synced) || (ofdm->sync_state == trial)) - { - ofdm_demod_shorts(ofdm, rx_bits, demod_in_8kHz, new_gain); - ofdm_disassemble_modem_frame(ofdm, rx_uw, payload_syms, payload_amps, txt_bits); - - f->sync = 1; - ofdm_get_demod_stats(f->ofdm, &f->stats); - f->snr_est = f->stats.snr_est; - - assert((ofdm_nuwbits+ofdm_ntxtbits+coded_bits_per_frame) == ofdm_bitsperframe); - - /* now we need to buffer for de-interleaving -------------------------------------*/ - - /* shift interleaved symbol buffers to make room for new symbols */ - - for(i=0, j=coded_syms_per_frame; jsync_state_interleaver == synced) && (ofdm->frame_count_interleaver == interleave_frames)) { - ofdm->frame_count_interleaver = 0; - - if (f->test_frames) { - int *tmp = new int[interleave_frames]; - Nerrs_raw = count_uncoded_errors(ldpc, ofdm_config, tmp, interleave_frames, codeword_symbols_de); - f->total_bit_errors += Nerrs_raw; - f->total_bits += ofdm_bitsperframe*interleave_frames; - delete[] tmp; - } - - memset(f->packed_codec_bits, 0, bytes_per_codec_frame * frames); - byte = 0; f->modem_frame_count_rx = 0; - - for (j=0; jmean_amp, coded_syms_per_frame); - iter = run_ldpc_decoder(ldpc, out_char, llr, &parityCheckCount); - - if (f->test_frames) { - uint8_t *payload_data_bits = new uint8_t[data_bits_per_frame]; - ofdm_generate_payload_data_bits(payload_data_bits, data_bits_per_frame); - Nerrs_coded = count_errors(payload_data_bits, out_char, data_bits_per_frame); - f->total_bit_errors_coded += Nerrs_coded; - f->total_bits_coded += data_bits_per_frame; - delete[] payload_data_bits; - } else { - - /* a frame of valid Codec 2 bits, pack into Codec 2 frame */ - - for (i=0; ipacked_codec_bits[byte] |= (out_char[i+k] << bit); - bit--; - if (bit < 0) { - bit = 7; - byte++; - } - } - if (bit != 7) - byte++; - } - - } - } /* for interleave frames ... */ - - /* make sure we don't overrun packed byte array */ - - assert(byte <= f->nbyte_packed_codec_bits); - - nout = f->n_speech_samples; - - if (f->squelch_en && (f->stats.snr_est < f->snr_squelch_thresh)) { - *valid = 0; - } - - } /* if interleaver synced ..... */ - - /* If modem is synced we can decode txt bits */ - - for(k=0; kvaricode_dec_states, &ascii_out, &txt_bits[k], 1, 1); - if (n_ascii && (f->freedv_put_next_rx_char != NULL)) { - (*f->freedv_put_next_rx_char)(f->callback_state, ascii_out); - } - } - - /* estimate uncoded BER from UW. Coded bit errors could - probably be estimated as half of all failed LDPC parity - checks */ - - for(i=0; itx_uw[i]) { - f->total_bit_errors++; - } - } - f->total_bits += ofdm_nuwbits; - - delete[] out_char; - delete[] llr; - delete[] codeword_amps_de; - delete[] codeword_symbols_de; - } /* if modem synced .... */ - else - { - *valid = -1; - } - - /* iterate state machine and update nin for next call */ - - f->nin = ofdm_get_nin(ofdm); - //fprintf(stderr, "nin: %d\n", ofdm_get_nin(ofdm)); - ofdm_sync_state_machine(ofdm, rx_uw); - - if (f->verbose && (ofdm->last_sync_state == search)) { - fprintf(stderr, "%3d st: %-6s euw: %2d %1d f: %5.1f ist: %-6s %2d eraw: %3d ecdd: %3d iter: %3d pcc: %3d vld: %d, nout: %4d\n", - f->frames++, statemode[ofdm->last_sync_state], ofdm->uw_errors, ofdm->sync_counter, - (double)ofdm->foff_est_hz, - statemode[ofdm->last_sync_state_interleaver], ofdm->frame_count_interleaver, - Nerrs_raw, Nerrs_coded, iter, parityCheckCount, *valid, nout); - } - - /* no valid FreeDV signal - squelch output */ - - bool sync = ((ofdm->sync_state == synced) || (ofdm->sync_state == trial)); - if (sync == false) { - if (f->squelch_en == true) { - *valid = 0; - } - //f->snr_est = 0.0; - } - - //fprintf(stderr, "sync: %d valid: %d snr: %3.2f\n", f->sync, *valid, f->snr_est); - - delete[] rx_uw; - delete[] payload_amps; - delete[] payload_syms; - delete[] txt_bits; - delete[] rx_bits; - return nout; -} - -/* Original version for all but 700D */ -int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) { - assert(f != NULL); - int bits_per_codec_frame, bytes_per_codec_frame; - int i, nout = 0; - int valid = 0; - - assert(f->nin <= f->n_max_modem_samples); - - bits_per_codec_frame = codec2_bits_per_frame(f->codec2); - bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8; - - if (f->mode == FREEDV_MODE_1600) { - nout = freedv_comprx_fdmdv_1600(f, demod_in, &valid); - } - if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C)) { - nout = freedv_comprx_700(f, demod_in, &valid); - } - - if( (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) || (f->mode == FREEDV_MODE_800XA)){ - nout = freedv_comprx_fsk(f, demod_in, &valid); - } - - if (valid == 0) { - //fprintf(stderr, "squelch nout: %d\n", nout); - - /* squelch */ - - for (i = 0; i < nout; i++) - speech_out[i] = 0; - } - else if (valid < 0) { - /* we havent got sync so play audio from radio. This might - not work for all modes due to nin bouncing about */ - for (i = 0; i < nout; i++) - speech_out[i] = demod_in[i].real; - } - else { - /* decoded audio to play */ - - int frames = f->n_codec_bits / bits_per_codec_frame; - //fprintf(stderr, "frames: %d\n", frames); - for (i = 0; i < frames; i++) { - codec2_decode(f->codec2, speech_out, f->packed_codec_bits + i * bytes_per_codec_frame); - speech_out += codec2_samples_per_frame(f->codec2); - } - } - - //fprintf(stderr,"freedv_nin(f): %d nout: %d valid: %d\n", freedv_nin(f), nout, valid); - return nout; -} - -/* 700D version */ -int freedv_shortrx(struct freedv *f, short speech_out[], short demod_in[], float gain) { - assert(f != NULL); - int bits_per_codec_frame, bytes_per_codec_frame; - int i, nout = 0; - int valid = 0; - - assert(f->nin <= f->n_max_modem_samples); - - bits_per_codec_frame = codec2_bits_per_frame(f->codec2); - bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8; - - if (f->mode == FREEDV_MODE_700D) { - nout = freedv_comprx_700d(f, demod_in, gain, &valid); - } - - if (valid == 0) { - //fprintf(stderr, "squelch nout: %d\n", nout); - - /* squelch */ - - for (i = 0; i < nout; i++) - speech_out[i] = 0; - } - else if (valid < 0) { - /* we havent got sync so play audio from radio. This might - not work for all modes due to nin bouncing about */ - for (i = 0; i < nout; i++) - speech_out[i] = demod_in[i]; - } - else { - /* decoded audio to play */ - - int data_bits_per_frame = f->ldpc->data_bits_per_frame; - int frames = data_bits_per_frame/bits_per_codec_frame; - - nout = 0; - if (f->modem_frame_count_rx < f->interleave_frames) { - nout = f->n_speech_samples; - //fprintf(stderr, "modem_frame_count_rx: %d nout: %d\n", f->modem_frame_count_rx, nout); - for (i = 0; i < frames; i++) { - codec2_decode(f->codec2, speech_out, f->packed_codec_bits + (i + frames*f->modem_frame_count_rx)* bytes_per_codec_frame); - speech_out += codec2_samples_per_frame(f->codec2); - } - f->modem_frame_count_rx++; - } - } - - return nout; -} - - -int freedv_codecrx(struct freedv *f, unsigned char *packed_codec_bits, short demod_in[]) -{ - assert(f != NULL); - int i; - int nin = freedv_nin(f); - int valid; - int ret = 0; - int bits_per_codec_frame = codec2_bits_per_frame(f->codec2); - - assert(nin <= f->n_max_modem_samples); - - if (f->mode != FREEDV_MODE_700D) { - COMP *rx_fdm = new COMP[f->n_max_modem_samples]; - - for(i=0; imode == FREEDV_MODE_1600) { - freedv_comprx_fdmdv_1600(f, rx_fdm, &valid); - } - - if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C)) { - freedv_comprx_700(f, rx_fdm, &valid); - } - - if( (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) || (f->mode == FREEDV_MODE_800XA)){ - freedv_comprx_fsk(f, rx_fdm, &valid); - } - - delete[] rx_fdm; - } - - int bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8; - - if (f->mode == FREEDV_MODE_700D) { - freedv_comprx_700d(f, demod_in, 1.0, &valid); - - int data_bits_per_frame = f->ldpc->data_bits_per_frame; - int frames = data_bits_per_frame/bits_per_codec_frame; - - if (valid == 1 && f->modem_frame_count_rx < f->interleave_frames) { - for (i = 0; i < frames; i++) { - memcpy(packed_codec_bits, f->packed_codec_bits + (i + frames*f->modem_frame_count_rx)* bytes_per_codec_frame, bytes_per_codec_frame); - packed_codec_bits += bytes_per_codec_frame; - ret += bytes_per_codec_frame; - } - f->modem_frame_count_rx++; - } - return ret; - } - - if (valid == 1) { - int codec_frames = f->n_codec_bits / bits_per_codec_frame; - - memcpy(packed_codec_bits, f->packed_codec_bits, bytes_per_codec_frame * codec_frames); - ret = bytes_per_codec_frame * codec_frames; - } - - return ret; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: freedv_get_version - AUTHOR......: Jim Ahlstrom - DATE CREATED: 28 July 2015 - - Return the version of the FreeDV API. This is meant to help API users determine when - incompatible changes have occurred. - -\*---------------------------------------------------------------------------*/ - -int freedv_get_version(void) -{ - return VERSION; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: freedv_set_callback_txt - AUTHOR......: Jim Ahlstrom - DATE CREATED: 28 July 2015 - - Set the callback functions and the callback state pointer that will be used - for the aux txt channel. The freedv_callback_rx is a function pointer that - will be called to return received characters. The freedv_callback_tx is a - function pointer that will be called to send transmitted characters. The callback - state is a user-defined void pointer that will be passed to the callback functions. - Any or all can be NULL, and the default is all NULL. - The function signatures are: - void receive_char(void *callback_state, char c); - char transmit_char(void *callback_state); - -\*---------------------------------------------------------------------------*/ - -void freedv_set_callback_txt(struct freedv *f, freedv_callback_rx rx, freedv_callback_tx tx, void *state) -{ - if (f->mode != FREEDV_MODE_800XA) { - f->freedv_put_next_rx_char = rx; - f->freedv_get_next_tx_char = tx; - f->callback_state = state; - } -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: freedv_set_callback_protocol - AUTHOR......: Brady OBrien - DATE CREATED: 21 February 2016 - - Set the callback functions and callback pointer that will be used for the - protocol data channel. freedv_callback_protorx will be called when a frame - containing protocol data arrives. freedv_callback_prototx will be called - when a frame containing protocol information is being generated. Protocol - information is intended to be used to develop protocols and fancy features - atop VHF freedv, much like those present in DMR. - Protocol bits are to be passed in an msb-first char array - The number of protocol bits are findable with freedv_get_protocol_bits -\*---------------------------------------------------------------------------*/ - -void freedv_set_callback_protocol(struct freedv *f, freedv_callback_protorx rx, freedv_callback_prototx tx, void *callback_state){ - if (f->mode != FREEDV_MODE_800XA) { - f->freedv_put_next_proto = rx; - f->freedv_get_next_proto = tx; - f->proto_callback_state = callback_state; - } -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: freedv_set_callback_datarx / freedv_set_callback_datatx - AUTHOR......: Jeroen Vreeken - DATE CREATED: 04 March 2016 - - Set the callback functions and callback pointer that will be used for the - data channel. freedv_callback_datarx will be called when a packet has been - successfully received. freedv_callback_data_tx will be called when - transmission of a new packet can begin. - If the returned size of the datatx callback is zero the data frame is still - generated, but will contain only a header update. -\*---------------------------------------------------------------------------*/ -void freedv_set_callback_data(struct freedv *f, freedv_callback_datarx datarx, freedv_callback_datatx datatx, void *callback_state) { - if ((f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) || (f->mode == FREEDV_MODE_800XA)){ - if (!f->deframer->fdc) - f->deframer->fdc = freedv_data_channel_create(); - if (!f->deframer->fdc) - return; - - freedv_data_set_cb_rx(f->deframer->fdc, datarx, callback_state); - freedv_data_set_cb_tx(f->deframer->fdc, datatx, callback_state); - } -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: freedv_set_data_header - AUTHOR......: Jeroen Vreeken - DATE CREATED: 04 March 2016 - - Set the data header for the data channel. - Header compression will be used whenever packets from this header are sent. - The header will also be used for fill packets when a data frame is requested - without a packet available. -\*---------------------------------------------------------------------------*/ -void freedv_set_data_header(struct freedv *f, unsigned char *header) -{ - if ((f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) || (f->mode == FREEDV_MODE_800XA)){ - if (!f->deframer->fdc) - f->deframer->fdc = freedv_data_channel_create(); - if (!f->deframer->fdc) - return; - - freedv_data_set_header(f->deframer->fdc, header); - } -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: freedv_get_modem_stats - AUTHOR......: Jim Ahlstrom - DATE CREATED: 28 July 2015 - - Return data from the modem. The arguments are pointers to the data items. The - pointers can be NULL if the data item is not wanted. - -\*---------------------------------------------------------------------------*/ - -void freedv_get_modem_stats(struct freedv *f, int *sync, float *snr_est) -{ - if (f->mode == FREEDV_MODE_1600) - fdmdv_get_demod_stats(f->fdmdv, &f->stats); - if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C)) - cohpsk_get_demod_stats(f->cohpsk, &f->stats); - if (f->mode == FREEDV_MODE_700D) { - ofdm_get_demod_stats(f->ofdm, &f->stats); - } - if (f->mode == FREEDV_MODE_2400B) { - fmfsk_get_demod_stats(f->fmfsk, &f->stats); - } - if (sync) *sync = f->stats.sync; - if (snr_est) *snr_est = f->stats.snr_est; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTIONS...: freedv_set_* - AUTHOR......: Jim Ahlstrom - DATE CREATED: 28 July 2015 - - Set some parameters used by FreeDV. It is possible to write a macro using ## for - this, but I wasn't sure it would be 100% portable. - -\*---------------------------------------------------------------------------*/ - -// Set integers -void freedv_set_test_frames (struct freedv *f, int val) {f->test_frames = val;} -void freedv_set_test_frames_diversity (struct freedv *f, int val) {f->test_frames_diversity = val;} -void freedv_set_squelch_en (struct freedv *f, int val) {f->squelch_en = val;} -void freedv_set_total_bit_errors (struct freedv *f, int val) {f->total_bit_errors = val;} -void freedv_set_total_bits (struct freedv *f, int val) {f->total_bits = val;} -void freedv_set_total_bit_errors_coded (struct freedv *f, int val) {f->total_bit_errors_coded = val;} -void freedv_set_total_bits_coded (struct freedv *f, int val) {f->total_bits_coded = val;} -void freedv_set_clip (struct freedv *f, int val) {f->clip = val;} -void freedv_set_varicode_code_num (struct freedv *f, int val) {varicode_set_code_num(&f->varicode_dec_states, val);} -void freedv_set_ext_vco (struct freedv *f, int val) {f->ext_vco = val;} - - -/* Band Pass Filter to cleanup OFDM tx waveform, only supported by FreeDV 700D */ - -void freedv_set_tx_bpf(struct freedv *f, int val) { - if (f->mode == FREEDV_MODE_700D) { - ofdm_set_tx_bpf(f->ofdm, val); - } -} - - -void freedv_set_verbose(struct freedv *f, int verbosity) { - f->verbose = verbosity; - if (f->mode == FREEDV_MODE_700D) { - ofdm_set_verbose(f->ofdm, f->verbose); - } -} - -// Set floats -void freedv_set_snr_squelch_thresh (struct freedv *f, float val) {f->snr_squelch_thresh = val;} - -void freedv_set_callback_error_pattern (struct freedv *f, freedv_calback_error_pattern cb, void *state) -{ - f->freedv_put_error_pattern = cb; - f->error_pattern_callback_state = state; -} - -void freedv_set_carrier_ampl(struct freedv *freedv, int c, float ampl) { - assert(freedv->mode == FREEDV_MODE_700C); - cohpsk_set_carrier_ampl(freedv->cohpsk, c, ampl); -} - -/*---------------------------------------------------------------------------*\ - - FUNCTIONS...: freedv_set_alt_modem_samp_rate - AUTHOR......: Brady O'Brien - DATE CREATED: 25 June 2016 - - Attempt to set the alternative sample rate on the modem side of the api. Only - a few alternative sample rates are supported. Please see below. - - 2400A - 48000, 96000 - 2400B - 48000, 96000 - - TODO: Implement 2400B rate changing, allow other rate changing. - - -\*---------------------------------------------------------------------------*/ - -int freedv_set_alt_modem_samp_rate(struct freedv *f, int samp_rate) -{ - if (f->mode == FREEDV_MODE_2400A) - { - if (samp_rate == 24000 || samp_rate == 48000 || samp_rate == 96000) - { - fsk_destroy(f->fsk); - f->fsk = fsk_create_hbr(samp_rate, 1200, 10, 4, 1200, 1200); - - free(f->tx_bits); - /* Note: fsk expects tx/rx bits as an array of uint8_ts, not ints */ - f->tx_bits = (int*) malloc(f->fsk->Nbits*sizeof(int)); - - f->n_nom_modem_samples = f->fsk->N; - f->n_max_modem_samples = f->fsk->N + (f->fsk->Ts); - f->n_nat_modem_samples = f->fsk->N; - f->nin = fsk_nin(f->fsk); - f->modem_sample_rate = samp_rate; - return 0; - } - else - { - return -1; - } - } - else if (f->mode == FREEDV_MODE_2400B) - { - if (samp_rate == 48000 || samp_rate == 96000) { - return -1; - } else { - return -1; - } - } - - return -1; -} - - -/*---------------------------------------------------------------------------* \ - - FUNCTIONS...: freedv_set_sync - AUTHOR......: David Rowe - DATE CREATED: May 2018 - - Extended control of sync state machines, especially for FreeDV 700D. - This mode is required to acquire sync up at very low SNRS. This is - difficult to implement, for example we may get a false sync, or the - state machine may fall out of sync by mistake during a long fade. - - So with this API call we allow some operator assistance. - - Ensure this is called inthe same thread as freedv_rx(). - -\*---------------------------------------------------------------------------*/ - -void freedv_set_sync(struct freedv *freedv, Sync sync_cmd) { - assert (freedv != NULL); - - if (freedv->mode == FREEDV_MODE_700D) { - ofdm_set_sync(freedv->ofdm, sync_cmd); - } - -} - -struct FSK * freedv_get_fsk(struct freedv *f){ - return f->fsk; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTIONS...: freedv_get_* - AUTHOR......: Jim Ahlstrom - DATE CREATED: 28 July 2015 - - Get some parameters from FreeDV. It is possible to write a macro using ## for - this, but I wasn't sure it would be 100% portable. - -\*---------------------------------------------------------------------------*/ - -// Get integers -int freedv_get_protocol_bits (struct freedv *f) {return f->n_protocol_bits;} -int freedv_get_mode (struct freedv *f) {return f->mode;} -int freedv_get_test_frames (struct freedv *f) {return f->test_frames;} -int freedv_get_n_speech_samples (struct freedv *f) {return f->n_speech_samples;} -int freedv_get_modem_sample_rate (struct freedv *f) {return f->modem_sample_rate;} -int freedv_get_modem_symbol_rate (struct freedv *f) {return f->modem_symbol_rate;} -int freedv_get_n_max_modem_samples (struct freedv *f) {return f->n_max_modem_samples;} -int freedv_get_n_nom_modem_samples (struct freedv *f) {return f->n_nom_modem_samples;} -int freedv_get_total_bits (struct freedv *f) {return f->total_bits;} -int freedv_get_total_bit_errors (struct freedv *f) {return f->total_bit_errors;} -int freedv_get_total_bits_coded (struct freedv *f) {return f->total_bits_coded;} -int freedv_get_total_bit_errors_coded (struct freedv *f) {return f->total_bit_errors_coded;} -int freedv_get_sync (struct freedv *f) {return f->stats.sync;} - -int freedv_get_sync_interleaver(struct freedv *f) { - if (f->mode == FREEDV_MODE_700D) { - return f->ofdm->sync_state_interleaver == synced; - } - - return 0; -} - -int freedv_get_sz_error_pattern(struct freedv *f) -{ - if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C)) { - /* if diversity disabled callback sends error pattern for upper and lower carriers */ - return f->sz_error_pattern * (2 - f->test_frames_diversity); - } - else { - return f->sz_error_pattern; - } -} - -// Get floats - -struct CODEC2 *freedv_get_codec2 (struct freedv *f){return f->codec2;} -int freedv_get_n_codec_bits (struct freedv *f){return f->n_codec_bits;} - -// Get modem status - -void freedv_get_modem_extended_stats(struct freedv *f, struct MODEM_STATS *stats) -{ - if (f->mode == FREEDV_MODE_1600) - fdmdv_get_demod_stats(f->fdmdv, stats); - - if ((f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_800XA)) { - fsk_get_demod_stats(f->fsk, stats); - float EbNodB = stats->snr_est; /* fsk demod actually estimates Eb/No */ - stats->snr_est = EbNodB + 10.0*log10f(800.0/3000.0); /* so convert to SNR Rb=800, noise B=3000 */ - } - - if (f->mode == FREEDV_MODE_2400B) { - fmfsk_get_demod_stats(f->fmfsk, stats); - } - - if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C)) { - cohpsk_get_demod_stats(f->cohpsk, stats); - } - - if (f->mode == FREEDV_MODE_700D) { - ofdm_get_demod_stats(f->ofdm, stats); - } - -} - -} // FreeDV - diff --git a/libfreedv/freedv_api_internal.h b/libfreedv/freedv_api_internal.h deleted file mode 100644 index 17a8bc4da..000000000 --- a/libfreedv/freedv_api_internal.h +++ /dev/null @@ -1,154 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: freedv_api_internal.h - AUTHOR......: David Rowe - DATE CREATED: August 2014 - - This declares the structure freedv. A pointer to this structure is - returned by the FreeDV API freedv_open() function. The pointer is used - by the other FreeDV API functions declared in freedv_api.h. This - structure is intended to be internal to the FreeDV API. The public - functions are declared in freedv_api.h. Changes to this structure - are expected. Changes (except additions) to freedv_api.h are - discouraged. - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2014 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 . -*/ - -#ifndef __FREEDV_API_INTERNAL__ -#define __FREEDV_API_INTERNAL__ - -#include "codec2/varicode.h" -#include "fsk.h" -#include "fmfsk.h" -#include "codec2_cohpsk.h" -#include "codec2_fdmdv.h" - -namespace FreeDV -{ - -struct freedv { - int mode; - - /* states for various modems we support */ - - struct CODEC2 *codec2; - struct FDMDV *fdmdv; - struct COHPSK *cohpsk; - struct FSK *fsk; - struct FMFSK *fmfsk; - struct OFDM *ofdm; - struct LDPC *ldpc; - struct MODEM_STATS stats; - - struct freedv_vhf_deframer * deframer; // Extracts frames from VHF stream - - struct quisk_cfFilter * ptFilter7500to8000; // Filters to change to/from 7500 and 8000 sps for 700 .... 700C - struct quisk_cfFilter * ptFilter8000to7500; - - int n_speech_samples; // number of speech samples we need for each freedv_tx() call - // num of speech samples output by freedv_rx() call - int n_nom_modem_samples; // size of tx and most rx modem sample buffers - int n_max_modem_samples; // make your rx modem sample buffers this big - int n_nat_modem_samples; // tx modem sample block length as used by the modem before interpolation to output - // usually the same as n_nom_modem_samples, except for 700..700C - int modem_sample_rate; // Caller is responsible for meeting this - int modem_symbol_rate; // Useful for ext_vco operation on 2400A and 800XA - int clip; // non-zero for cohpsk modem output clipping for low PAPR - - unsigned char *packed_codec_bits; - unsigned char *packed_codec_bits_tx; // for 700D we separate packed bits to maintain state due to interleaving - int nbyte_packed_codec_bits; // keep track of size of above arrays in 700D - int *codec_bits; - int *tx_bits; - int *fdmdv_bits; - int *rx_bits; - int n_codec_bits; // number of codec bits in a frame - - int tx_sync_bit; - int smooth_symbols; - int frames; - - /* test frame states -------------------------------------------------------------------------*/ - - int *ptest_bits_coh; - int *ptest_bits_coh_end; - - int test_frames; // set this baby for 1 to tx/rx test frames to look at bit error stats - int test_frames_diversity; // 1 -> used combined carriers for error counting on 700 waveforms - int test_frame_sync_state; - int test_frame_sync_state_upper; // when test_frames_diveristy==0 we need extra states for upper carriers - int test_frame_count; - int total_bits; - int total_bit_errors; - int total_bits_coded; - int total_bit_errors_coded; - int sz_error_pattern; - - /* optional user defined function to pass error pattern when a test frame is received */ - - void *error_pattern_callback_state; - void (*freedv_put_error_pattern)(void *error_pattern_callback_state, short error_pattern[], int sz_error_pattern); - - /* Misc ---------------------------------------------------------------------------------------------*/ - - int sync; - int evenframe; - float snr_est; - float snr_squelch_thresh; - int squelch_en; - int nin; - int verbose; - int ext_vco; /* 2400A/800XA use external VCO flag */ - - /* Varicode txt channel states ----------------------------------------------------------------------*/ - - struct VARICODE_DEC varicode_dec_states; - short tx_varicode_bits[VARICODE_MAX_BITS]; - int nvaricode_bits; - int varicode_bit_index; - - /* interleaved LDPC OFDM states ---------------------------------------------------------------------*/ - - int interleave_frames; // number of OFDM modem frames in interleaver, e.g. 1,2,4,8,16 - COMP *codeword_symbols; - float *codeword_amps; - int modem_frame_count_tx; // modem frame counter for tx side - int modem_frame_count_rx; // modem frame counter for rx side - COMP *mod_out; // output buffer of intereaved frames - - /* user defined function ptrs to produce and consume ASCII - characters using aux txt channel */ - - char (*freedv_get_next_tx_char)(void *callback_state); - void (*freedv_put_next_rx_char)(void *callback_state, char c); - void *callback_state; - - /* user defined functions to produce and consume protocol bits */ - /* Protocol bits are packed MSB-first */ - void (*freedv_put_next_proto)(void *callback_state, char *proto_bits_packed); - void (*freedv_get_next_proto)(void *callback_state, char *proto_bits_packed); - void *proto_callback_state; - int n_protocol_bits; -}; - -} // FreeDV - -#endif - diff --git a/libfreedv/freedv_data_channel.cpp b/libfreedv/freedv_data_channel.cpp deleted file mode 100644 index e305de507..000000000 --- a/libfreedv/freedv_data_channel.cpp +++ /dev/null @@ -1,353 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: freedv_data_channel.c - AUTHOR......: Jeroen Vreeken - DATE CREATED: 03 March 2016 - - Data channel for ethernet like packets in freedv VHF frames. - Currently designed for- - * 2 control bits per frame - * 4 byte counter bits per frame - * 64 bits of data per frame -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2016 Jeroen Vreeken - - 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 "freedv_data_channel.h" - -#include -#include -#include - -namespace FreeDV -{ - -static unsigned char fdc_header_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - -/* CCIT CRC table (0x1201 polynomal) */ -static unsigned short fdc_crc_table[256] = { - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -}; - -static unsigned short fdc_crc(unsigned char *buffer, std::size_t len) -{ - unsigned short crc = 0xffff; - std::size_t i; - - for (i = 0; i < len; i++, buffer++) { - crc = (crc >> 8) ^ fdc_crc_table[(crc ^ *buffer) & 0xff]; - } - - return crc ^ 0xffff; -} - -/* CRC4 0x03 polynomal */ -static unsigned char fdc_crc4(unsigned char *buffer, std::size_t len) -{ - unsigned char crc = 0x0f; - std::size_t i; - - for (i = 0; i < len; i++, buffer++) - { - int shift; - - for (shift = 7; shift >= 0; shift--) - { - crc <<= 1; - - if ((*buffer >> shift) & 0x1) { - crc |= 1; - } - - if (crc & 0x10) { - crc ^= 0x03; - } - } - } - - return crc & 0x0f; -} - -struct freedv_data_channel *freedv_data_channel_create(void) -{ - struct freedv_data_channel *fdc; - - fdc = (freedv_data_channel*) malloc(sizeof(struct freedv_data_channel)); - if (!fdc) - return nullptr; - - fdc->cb_rx = nullptr; - fdc->cb_tx = nullptr; - fdc->packet_tx_size = 0; - - freedv_data_set_header(fdc, fdc_header_bcast); - - memcpy(fdc->rx_header, fdc->tx_header, 8); - - return fdc; -} - -void freedv_data_channel_destroy(struct freedv_data_channel *fdc) -{ - free(fdc); -} - - -void freedv_data_set_cb_rx(struct freedv_data_channel *fdc, freedv_data_callback_rx cb, void *state) -{ - fdc->cb_rx = cb; - fdc->cb_rx_state = state; -} - -void freedv_data_set_cb_tx(struct freedv_data_channel *fdc, freedv_data_callback_tx cb, void *state) -{ - fdc->cb_tx = cb; - fdc->cb_tx_state = state; -} - -void freedv_data_channel_rx_frame(struct freedv_data_channel *fdc, unsigned char *data, std::size_t size, int from_bit, int bcast_bit, int crc_bit, int end_bits) -{ - int copy_bits; - - if (end_bits) { - copy_bits = end_bits; - } else { - copy_bits = size; - } - - /* New packet? */ - if (fdc->packet_rx_cnt == 0) - { - /* Does the packet have a compressed from field? */ - if (from_bit) { - /* Compressed from: take the previously received header */ - memcpy(fdc->packet_rx + fdc->packet_rx_cnt, fdc->rx_header, 6); - fdc->packet_rx_cnt += 6; - } - - if (bcast_bit) - { - if (!from_bit) - { - /* Copy from header and modify size and end_bits accordingly */ - memcpy(fdc->packet_rx + fdc->packet_rx_cnt, data, 6); - fdc->packet_rx_cnt += 6; - copy_bits -= 6; - - if (copy_bits < 0) { - copy_bits = 0; - } - - data += 6; - } - /* Compressed to: fill in broadcast address */ - memcpy(fdc->packet_rx + fdc->packet_rx_cnt, fdc_header_bcast, sizeof(fdc_header_bcast)); - fdc->packet_rx_cnt += 6; - } - - if (crc_bit) - { - unsigned char calc_crc = fdc_crc4(data, size); - - if (calc_crc == end_bits) - { - /* It is a single header field, remember it for later */ - memcpy(fdc->packet_rx + 6, data, 6); - memcpy(fdc->packet_rx, fdc_header_bcast, 6); - - if (fdc->cb_rx) { - fdc->cb_rx(fdc->cb_rx_state, fdc->packet_rx, 12); - } - } - - fdc->packet_rx_cnt = 0; - return; - } - } - - if (fdc->packet_rx_cnt + copy_bits >= FREEDV_DATA_CHANNEL_PACKET_MAX) - { - // Something went wrong... this can not be a real packet - fdc->packet_rx_cnt = 0; - return; - } - else if (fdc->packet_rx_cnt < 0) - { - // This is wrong too... - fdc->packet_rx_cnt = 0; - return; - } - - memcpy(fdc->packet_rx + fdc->packet_rx_cnt, data, copy_bits); - fdc->packet_rx_cnt += copy_bits; - - if (end_bits != 0 && fdc->packet_rx_cnt >= 2) - { - unsigned short calc_crc = fdc_crc(fdc->packet_rx, fdc->packet_rx_cnt - 2); - unsigned short rx_crc; - rx_crc = fdc->packet_rx[fdc->packet_rx_cnt - 1] << 8; - rx_crc |= fdc->packet_rx[fdc->packet_rx_cnt - 2]; - - if (rx_crc == calc_crc) - { - if ((std::size_t) fdc->packet_rx_cnt == size) { - /* It is a single header field, remember it for later */ - memcpy(fdc->rx_header, fdc->packet_rx, 6); - } - - /* callback */ - if (fdc->cb_rx) - { - unsigned char tmp[6]; - memcpy(tmp, fdc->packet_rx, 6); - memcpy(fdc->packet_rx, fdc->packet_rx + 6, 6); - memcpy(fdc->packet_rx + 6, tmp, 6); - std::size_t size = fdc->packet_rx_cnt - 2; - - if (size < 12) { - size = 12; - } - - fdc->cb_rx(fdc->cb_rx_state, fdc->packet_rx, size); - } - } - - fdc->packet_rx_cnt = 0; - } -} - -void freedv_data_channel_tx_frame(struct freedv_data_channel *fdc, unsigned char *data, std::size_t size, int *from_bit, int *bcast_bit, int *crc_bit, int *end_bits) -{ - *from_bit = 0; - *bcast_bit = 0; - *crc_bit = 0; - - if (!fdc->packet_tx_size) { - fdc->packet_tx_cnt = 0; - - if (fdc->cb_tx) { - fdc->packet_tx_size = FREEDV_DATA_CHANNEL_PACKET_MAX; - fdc->cb_tx(fdc->cb_tx_state, fdc->packet_tx, &fdc->packet_tx_size); - } - if (!fdc->packet_tx_size) { - /* Nothing to send, insert a header frame */ - memcpy(fdc->packet_tx, fdc->tx_header, size); - if (size < 8) { - *end_bits = fdc_crc4(fdc->tx_header, size); - *crc_bit = 1; - memcpy(data, fdc->tx_header, size); - - return; - } else { - fdc->packet_tx_size = size; - } - } else { - /* new packet */ - unsigned short crc; - unsigned char tmp[6]; - - *from_bit = !memcmp(fdc->packet_tx + 6, fdc->tx_header, 6); - *bcast_bit = !memcmp(fdc->packet_tx, fdc_header_bcast, 6); - - memcpy(tmp, fdc->packet_tx, 6); - memcpy(fdc->packet_tx, fdc->packet_tx + 6, 6); - memcpy(fdc->packet_tx + 6, tmp, 6); - - crc = fdc_crc(fdc->packet_tx, fdc->packet_tx_size); - - fdc->packet_tx[fdc->packet_tx_size] = crc & 0xff; - fdc->packet_tx_size++; - fdc->packet_tx[fdc->packet_tx_size] = (crc >> 8) & 0xff; - fdc->packet_tx_size++; - - if (*from_bit) { - fdc->packet_tx_cnt = 6; - } else { - if (*bcast_bit) { - memcpy(fdc->packet_tx + 6, fdc->packet_tx, 6); - } - } - if (*bcast_bit) { - fdc->packet_tx_cnt += 6; - } - } - } - if (fdc->packet_tx_size) { - std::size_t copy = fdc->packet_tx_size - fdc->packet_tx_cnt; - - if (copy > size) { - copy = size; - *end_bits = 0; - } else { - *end_bits = copy; - fdc->packet_tx_size = 0; - } - memcpy(data, fdc->packet_tx + fdc->packet_tx_cnt, copy); - fdc->packet_tx_cnt += copy; - } -} - -void freedv_data_set_header(struct freedv_data_channel *fdc, unsigned char *header) -{ - unsigned short crc = fdc_crc(header, 6); - - memcpy(fdc->tx_header, header, 6); - fdc->tx_header[6] = crc & 0xff; - fdc->tx_header[7] = (crc >> 8) & 0xff; -} - -int freedv_data_get_n_tx_frames(struct freedv_data_channel *fdc, std::size_t size) -{ - if (fdc->packet_tx_size == 0) - return 0; - /* packet will be send in 'size' byte frames */ - return (fdc->packet_tx_size - fdc->packet_tx_cnt + size-1) / size; -} - -} // FreeDV diff --git a/libfreedv/freedv_data_channel.h b/libfreedv/freedv_data_channel.h deleted file mode 100644 index 7e2f142ae..000000000 --- a/libfreedv/freedv_data_channel.h +++ /dev/null @@ -1,75 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: freedv_data_channel.h - AUTHOR......: Jeroen Vreeken - DATE CREATED: 03 March 2016 - - Data channel for ethernet like packets in freedv VHF frames. - Currently designed for- - * 2 control bits per frame - * 4 byte counter bits per frame - * 64 bits of data per frame -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2016 Jeroen Vreeken - - 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 . -*/ - -#ifndef _FREEDV_DATA_CHANNEL_H -#define _FREEDV_DATA_CHANNEL_H - -#include - -#define FREEDV_DATA_CHANNEL_PACKET_MAX 2048 - -namespace FreeDV -{ - -typedef void (*freedv_data_callback_rx)(void *, unsigned char *packet, size_t size); -typedef void (*freedv_data_callback_tx)(void *, unsigned char *packet, size_t *size); - -struct freedv_data_channel { - freedv_data_callback_rx cb_rx; - void *cb_rx_state; - freedv_data_callback_tx cb_tx; - void *cb_tx_state; - - unsigned char rx_header[8]; - unsigned char packet_rx[FREEDV_DATA_CHANNEL_PACKET_MAX + 2]; - int packet_rx_cnt; - - unsigned char tx_header[8]; - unsigned char packet_tx[FREEDV_DATA_CHANNEL_PACKET_MAX + 2]; - int packet_tx_cnt; - size_t packet_tx_size; -}; - - -struct freedv_data_channel *freedv_data_channel_create(void); -void freedv_data_channel_destroy(struct freedv_data_channel *fdc); - -void freedv_data_set_cb_rx(struct freedv_data_channel *fdc, freedv_data_callback_rx cb, void *state); -void freedv_data_set_cb_tx(struct freedv_data_channel *fdc, freedv_data_callback_tx cb, void *state); - -void freedv_data_channel_rx_frame(struct freedv_data_channel *fdc, unsigned char *data, size_t size, int from_bit, int bcast_bit, int crc_bit, int end_bits); -void freedv_data_channel_tx_frame(struct freedv_data_channel *fdc, unsigned char *data, size_t size, int *from_bit, int *bcast_bit, int *crc_bit, int *end_bits); - -void freedv_data_set_header(struct freedv_data_channel *fdc, unsigned char *header); -int freedv_data_get_n_tx_frames(struct freedv_data_channel *fdc, size_t size); - -} // FreeDV - -#endif /* _FREEDV_DATA_CHANNEL_H */ diff --git a/libfreedv/freedv_filter.cpp b/libfreedv/freedv_filter.cpp deleted file mode 100644 index 34236e361..000000000 --- a/libfreedv/freedv_filter.cpp +++ /dev/null @@ -1,293 +0,0 @@ -/* - Copyright (C) 2018 James C. Ahlstrom - - 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 -#include -#include - -#include "freedv_filter.h" -#include "freedv_filter_coef.h" - -#include "fdv_arm_math.h" - -#define cmplx(value) (COSF(value) + SINF(value) * std::complex(0.0f, 1.0f)) - -namespace FreeDV -{ - -/* - * This is a library of filter functions. They were copied from Quisk and converted to single precision. - */ - -/*---------------------------------------------------------------------------*\ - - FUNCTIONS...: quisk_filt_cfInit - AUTHOR......: Jim Ahlstrom - DATE CREATED: 27 August 2015 - MODIFIED: 4 June 2018 - - Initialize a FIR filter that has complex samples, and either real or complex coefficients. - -\*---------------------------------------------------------------------------*/ - -void quisk_filt_cfInit(struct quisk_cfFilter * filter, float * coefs, int taps) -{ - // Prepare a new filter using coefs and taps. Samples are complex. Coefficients can - // be real or complex. - filter->dCoefs = coefs; - filter->cpxCoefs = nullptr; - filter->cSamples = new std::complex[taps]; - std::fill(filter->cSamples, filter->cSamples + taps, std::complex{0.0, 0.0}); - filter->ptcSamp = filter->cSamples; - filter->nTaps = taps; - filter->cBuf = nullptr; - filter->nBuf = 0; - filter->decim_index = 0; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTIONS...: quisk_filt_destroy - AUTHOR......: Jim Ahlstrom - DATE CREATED: 27 August 2015 - MODIFIED: 4 June 2018 - - Destroy the FIR filter and free all resources. - -\*---------------------------------------------------------------------------*/ - -void quisk_filt_destroy(struct quisk_cfFilter * filter) -{ - if (filter->cSamples) - { - delete[] filter->cSamples; - filter->cSamples = nullptr; - } - - if (filter->cBuf) - { - delete[] filter->cBuf; - filter->cBuf = nullptr; - } - - if (filter->cpxCoefs) - { - delete[] filter->cpxCoefs; - filter->cpxCoefs = nullptr; - } -} - -/*---------------------------------------------------------------------------*\ - - FUNCTIONS...: quisk_cfInterpDecim - AUTHOR......: Jim Ahlstrom - DATE CREATED: 27 August 2015 - MODIFIED: 4 June 2018 - - Take an array of samples cSamples of length count, multiply the sample rate - by interp, and then divide the sample rate by decim. Return the new number - of samples. Each specific interp and decim will require its own custom - low pass FIR filter with real coefficients. - -\*---------------------------------------------------------------------------*/ - -int quisk_cfInterpDecim(std::complex * cSamples, int count, struct quisk_cfFilter * filter, int interp, int decim) { - // Interpolate by interp, and then decimate by decim. - // This uses the float coefficients of filter (not the complex). Samples are complex. - int i, k, nOut; - float * ptCoef; - std::complex *ptSample; - std::complex csample; - - if (count > filter->nBuf) { // increase size of sample buffer - filter->nBuf = count * 2; - - if (filter->cBuf) - free(filter->cBuf); - - filter->cBuf = new std::complex[filter->nBuf]; - } - - memcpy(filter->cBuf, cSamples, count * sizeof(std::complex)); - nOut = 0; - - for (i = 0; i < count; i++) { - // Put samples into buffer left to right. Use samples right to left. - *filter->ptcSamp = filter->cBuf[i]; - - while (filter->decim_index < interp) { - ptSample = filter->ptcSamp; - ptCoef = filter->dCoefs + filter->decim_index; - csample = 0; - - for (k = 0; k < filter->nTaps / interp; k++, ptCoef += interp) { - csample += *ptSample * *ptCoef; - - if (--ptSample < filter->cSamples) - ptSample = filter->cSamples + filter->nTaps - 1; - } - - cSamples[nOut] = csample * (float) interp; - nOut++; - filter->decim_index += decim; - } - - if (++filter->ptcSamp >= filter->cSamples + filter->nTaps) - filter->ptcSamp = filter->cSamples; - - filter->decim_index = filter->decim_index - interp; - } - - return nOut; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTIONS...: quisk_ccfInterpDecim - AUTHOR......: Jim Ahlstrom - DATE CREATED: 7 June 2018 - - Take an array of samples cSamples of length count, multiply the sample rate - by interp, and then divide the sample rate by decim. Return the new number - of samples. Each specific interp and decim will require its own custom - low pass FIR filter with complex coefficients. This filter can be tuned. - - This filter is not currently used. - -\*---------------------------------------------------------------------------*/ -#if 0 -int quisk_ccfInterpDecim(complex float * cSamples, int count, struct quisk_cfFilter * filter, int interp, int decim) { - // Interpolate by interp, and then decimate by decim. - // This uses the complex coefficients of filter (not the real). Samples are complex. - int i, k, nOut; - complex float * ptCoef; - complex float * ptSample; - complex float csample; - - if (count > filter->nBuf) { // increase size of sample buffer - filter->nBuf = count * 2; - if (filter->cBuf) - FREE(filter->cBuf); - filter->cBuf = (complex float *)MALLOC(filter->nBuf * sizeof(complex float)); - } - - memcpy(filter->cBuf, cSamples, count * sizeof(complex float)); - nOut = 0; - - for (i = 0; i < count; i++) { - // Put samples into buffer left to right. Use samples right to left. - *filter->ptcSamp = filter->cBuf[i]; - - while (filter->decim_index < interp) { - ptSample = filter->ptcSamp; - ptCoef = filter->cpxCoefs + filter->decim_index; - csample = 0; - - for (k = 0; k < filter->nTaps / interp; k++, ptCoef += interp) { - csample += *ptSample * *ptCoef; - - if (--ptSample < filter->cSamples) - ptSample = filter->cSamples + filter->nTaps - 1; - } - - cSamples[nOut] = csample * interp; - nOut++; - filter->decim_index += decim; - } - - if (++filter->ptcSamp >= filter->cSamples + filter->nTaps) - filter->ptcSamp = filter->cSamples; - - filter->decim_index = filter->decim_index - interp; - } - - return nOut; -} -#endif - -/*---------------------------------------------------------------------------*\ - - FUNCTIONS...: quisk_cfTune - AUTHOR......: Jim Ahlstrom - DATE CREATED: 4 June 2018 - - Tune a low pass filter with float coefficients into an analytic I/Q bandpass filter - with complex coefficients. The "freq" is the center frequency / sample rate. - If the float coefs represent a low pass filter with bandwidth 1 kHz, the new bandpass - filter has width 2 kHz. The filter can be re-tuned repeatedly. - -\*---------------------------------------------------------------------------*/ - -void quisk_cfTune(struct quisk_cfFilter * filter, float freq) { - float D, tune; - int i; - - if ( ! filter->cpxCoefs) { - filter->cpxCoefs = new std::complex[filter->nTaps]; - } - - tune = 2.0 * M_PI * freq; - D = (filter->nTaps - 1.0) / 2.0; - - for (i = 0; i < filter->nTaps; i++) { - float tval = tune * (i - D); - filter->cpxCoefs[i] = cmplx(tval) * filter->dCoefs[i]; - } -} - -/*---------------------------------------------------------------------------*\ - - FUNCTIONS...: quisk_ccfFilter - AUTHOR......: Jim Ahlstrom - DATE CREATED: 4 June 2018 - - Filter complex samples using complex coefficients. The inSamples and outSamples may be - the same array. The loop runs forward over coefficients but backwards over samples. - Therefore, the coefficients must be reversed unless they are created by quisk_cfTune. - Low pass filter coefficients are symmetrical, so this does not usually matter. - -\*---------------------------------------------------------------------------*/ - -void quisk_ccfFilter(std::complex *inSamples, std::complex *outSamples, int count, struct quisk_cfFilter * filter) { - int i, k; - std::complex *ptSample; - std::complex *ptCoef; - std::complex accum; - - for (i = 0; i < count; i++) { - *filter->ptcSamp = inSamples[i]; - accum = 0; - ptSample = filter->ptcSamp; - ptCoef = filter->cpxCoefs; - - for (k = 0; k < filter->nTaps; k++, ptCoef++) { - accum += *ptSample * *ptCoef; - - if (--ptSample < filter->cSamples) - ptSample = filter->cSamples + filter->nTaps - 1; - } - - outSamples[i] = accum; - - if (++filter->ptcSamp >= filter->cSamples + filter->nTaps) - filter->ptcSamp = filter->cSamples; - } -} - -} // freeDV diff --git a/libfreedv/freedv_filter.h b/libfreedv/freedv_filter.h deleted file mode 100644 index 88be51449..000000000 --- a/libfreedv/freedv_filter.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - Copyright (C) 2018 James C. Ahlstrom - - 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 . -*/ - -#ifndef __FILTER__ -#define __FILTER__ - -#include - -namespace FreeDV -{ - -struct quisk_cfFilter { // Structure to hold the static data for FIR filters - float * dCoefs; // real filter coefficients - std::complex * cpxCoefs; // complex filter coefficients - int nBuf; // dimension of cBuf - int nTaps; // dimension of dSamples, cSamples, dCoefs - int decim_index; // index of next sample for decimation - std::complex * cSamples; // storage for old samples - std::complex * ptcSamp; // next available position in cSamples - std::complex * cBuf; // auxillary buffer for interpolation -} ; - -extern int quisk_cfInterpDecim(std::complex *, int, struct quisk_cfFilter *, int, int); -extern void quisk_filt_cfInit(struct quisk_cfFilter *, float *, int); -extern void quisk_filt_destroy(struct quisk_cfFilter *); -extern void quisk_cfTune(struct quisk_cfFilter *, float); -extern void quisk_ccfFilter(std::complex *, std::complex *, int, struct quisk_cfFilter *); - -extern float quiskFilt120t480[480]; -extern float filtP550S750[160]; - -} // FreeDV - -#endif diff --git a/libfreedv/freedv_filter_coef.h b/libfreedv/freedv_filter_coef.h deleted file mode 100644 index 9694eb5c1..000000000 --- a/libfreedv/freedv_filter_coef.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - Copyright (C) 2018 James C. Ahlstrom - - 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 . -*/ - -/* - These are the coefficients for various FIR filters. A declaration of these filter coefficients is in filter.h. - Multiple filters can use these coefficients because they are read-only. - - Although a sample rate is specified, the filters may be used at other sample rates. For example, if - filtP750S1040 is used at 48000 sps, the pass and stop frequencies are 4500 and 6240 hz. -*/ - -namespace FreeDV -{ - -// Low pass filter, sample rate 8000 hz, 0.2 dB ripple, 100 dB atten, pass 550 hz, stop 750 hz. -float filtP550S750[160]={ - 0.000001500540125945, 0.000020553368071006, 0.000052842049763802, 0.000112071233638701, - 0.000202565299657164, 0.000325476960438197, 0.000474396686568771, 0.000633746562372497, 0.000778858561033731, - 0.000878592697224500, 0.000900611877226272, 0.000818750000130019, 0.000621157718914443, 0.000317269738067462, --0.000058614729046822, -0.000448959090901751, -0.000780751290682747, -0.000978953969922609, -0.000983534965413392, --0.000766540799920385, -0.000344938705664714, 0.000214927788687815, 0.000804118320944653, 0.001289527679116282, - 0.001541598437149897, 0.001466078039230554, 0.001032493743140772, 0.000291727467744814, -0.000623607913580581, --0.001518948630011706, -0.002175907515711935, -0.002402252989524116, -0.002082876981631170, -0.001219318501019004, - 0.000053915753894017, 0.001483599323867600, 0.002743518309691092, 0.003504691193108974, 0.003515993126242027, - 0.002676486805582815, 0.001080325423865147, -0.000980649349095093, -0.003062866925046052, -0.004660487490214220, --0.005321805637618908, -0.004767235761853469, -0.002979877569160189, -0.000242864453416682, 0.002892365745006815, - 0.005707645107750651, 0.007473145256589892, 0.007624527169837005, 0.005921569713871673, 0.002547381438730890, --0.001883079571618079, -0.006418195698900790, -0.009958090016198632, -0.011502199858687428, -0.010403943660694560, --0.006572745274759415, -0.000569370325758693, 0.006440667006225166, 0.012881777376768124, 0.017083918451421990, - 0.017661533458054445, 0.013877952730549446, 0.005912685575826365, -0.005037640104142052, -0.016864250576905999, --0.026855876467499887, -0.032168177048912679, -0.030370760878632559, -0.019967289813872333, -0.000782327027950076, - 0.025871098651626040, 0.057290144048617792, 0.089743290905422241, 0.119038289777397190, 0.141198609990722840, - 0.153125933205703250, 0.153125933205703250, 0.141198609990722840, 0.119038289777397190, 0.089743290905422241, - 0.057290144048617792, 0.025871098651626040, -0.000782327027950076, -0.019967289813872333, -0.030370760878632559, --0.032168177048912679, -0.026855876467499887, -0.016864250576905999, -0.005037640104142052, 0.005912685575826365, - 0.013877952730549446, 0.017661533458054445, 0.017083918451421990, 0.012881777376768124, 0.006440667006225166, --0.000569370325758693, -0.006572745274759415, -0.010403943660694560, -0.011502199858687428, -0.009958090016198632, --0.006418195698900790, -0.001883079571618079, 0.002547381438730890, 0.005921569713871673, 0.007624527169837005, - 0.007473145256589892, 0.005707645107750651, 0.002892365745006815, -0.000242864453416682, -0.002979877569160189, --0.004767235761853469, -0.005321805637618908, -0.004660487490214220, -0.003062866925046052, -0.000980649349095093, - 0.001080325423865147, 0.002676486805582815, 0.003515993126242027, 0.003504691193108974, 0.002743518309691092, - 0.001483599323867600, 0.000053915753894017, -0.001219318501019004, -0.002082876981631170, -0.002402252989524116, --0.002175907515711935, -0.001518948630011706, -0.000623607913580581, 0.000291727467744814, 0.001032493743140772, - 0.001466078039230554, 0.001541598437149897, 0.001289527679116282, 0.000804118320944653, 0.000214927788687815, --0.000344938705664714, -0.000766540799920385, -0.000983534965413392, -0.000978953969922609, -0.000780751290682747, --0.000448959090901751, -0.000058614729046822, 0.000317269738067462, 0.000621157718914443, 0.000818750000130019, - 0.000900611877226272, 0.000878592697224500, 0.000778858561033731, 0.000633746562372497, 0.000474396686568771, - 0.000325476960438197, 0.000202565299657164, 0.000112071233638701, 0.000052842049763802, 0.000020553368071006, - 0.000001500540125945 -}; - -// FIR filter suitable for changing rates 7500 to/from 8000 -// Sample 120000 Hz, pass 2700, stop 3730, ripple 0.1dB, atten 100 dB. Stop 0.03108. -float quiskFilt120t480[480] = { -0.000005050567303837, -0.000000267011791999, 0.000000197734700398, 0.000001038946634000, - 0.000002322193058869, 0.000004115682735322, 0.000006499942123311, 0.000009551098482930, 0.000013350669444763, - 0.000017966192635412, 0.000023463361155584, 0.000029885221425020, 0.000037271082107518, 0.000045630720487935, - 0.000054970017069384, 0.000065233162392019, 0.000076360900545177, 0.000088271373315159, 0.000100818605854714, - 0.000113853476544409, 0.000127174196746337, 0.000140558396336177, 0.000153744508371709, 0.000166450784469067, - 0.000178368313347299, 0.000189176709991702, 0.000198541881389953, 0.000206128795372885, 0.000211604878787747, - 0.000214655997661182, 0.000214994859281552, 0.000212358734245594, 0.000206539880117977, 0.000197379393194548, - 0.000184780318878738, 0.000168719942655099, 0.000149250512353807, 0.000126511346757621, 0.000100726393185629, - 0.000072210925236429, 0.000041365841965015, 0.000008680571408025, -0.000025277165852799, -0.000059865389594949, --0.000094384355854646, -0.000128080670195777, -0.000160170174848483, -0.000189854272533545, -0.000216333899003825, --0.000238836419299503, -0.000256632149501508, -0.000269058714331757, -0.000275541485292432, -0.000275614059005332, --0.000268937472718753, -0.000255317038867589, -0.000234717772155001, -0.000207273956099563, -0.000173297342436372, --0.000133280012107173, -0.000087895370243821, -0.000037986085678081, 0.000015440388211825, 0.000071232572821451, - 0.000128114399130489, 0.000184710477990398, 0.000239577162514028, 0.000291234779803098, 0.000338204791740229, - 0.000379047713684221, 0.000412403761615261, 0.000437031818051652, 0.000451848709179591, 0.000455966225408344, - 0.000448726371643413, 0.000429729020814434, 0.000398857326863837, 0.000356297600912998, 0.000302547334727027, - 0.000238422248479072, 0.000165048886226905, 0.000083853091464077, -0.000003462782744354, -0.000094949813106744, --0.000188451833293202, -0.000281651282503015, -0.000372121907291206, -0.000457387566635848, -0.000534985542936898, --0.000602532044011899, -0.000657788245032425, -0.000698728981427767, -0.000723604675185869, -0.000731002305621048, --0.000719899536922384, -0.000689709694056092, -0.000640319946685634, -0.000572115873292030, -0.000485996080304965, --0.000383371840261246, -0.000266155252511831, -0.000136731311264191, 0.000002082667095075, 0.000147092077716480, - 0.000294790953130229, 0.000441441918072383, 0.000583164190168290, 0.000716029226064227, 0.000836164238172957, - 0.000939856052624227, 0.001023657909064450, 0.001084492755093968, 0.001119751426837743, 0.001127383039339373, - 0.001105974243787613, 0.001054815583369999, 0.000973950761085690, 0.000864209315714227, 0.000727219011746881, - 0.000565398080608305, 0.000381924396468366, 0.000180685902835315, -0.000033793183292569, -0.000256444114966522, --0.000481764526566339, -0.000703946352348464, -0.000917016099829735, -0.001114986581270253, -0.001292014799874503, --0.001442563411804926, -0.001561559957317790, -0.001644551048567398, -0.001687846581475964, -0.001688649703502788, --0.001645167889846890, -0.001556702802350076, -0.001423714708648073, -0.001247857669697092, -0.001031986722557201, --0.000780131048444402, -0.000497436825078657, -0.000190077210351809, 0.000134868279325909, 0.000469563533327739, - 0.000805591531546815, 0.001134152328775355, 0.001446279849797673, 0.001733071409562941, 0.001985924997799762, - 0.002196778054604388, 0.002358342626407065, 0.002464328098407475, 0.002509648218888532, 0.002490604086803692, - 0.002405037734357425, 0.002252452724297770, 0.002034094661603120, 0.001752990365583534, 0.001413941154886139, - 0.001023470495638453, 0.000589723521647734, 0.000122320866350319, -0.000367832138027160, -0.000868777013398284, --0.001367771151677059, -0.001851587344265625, -0.002306838088978190, -0.002720317947026380, -0.003079353614002113, --0.003372155891804708, -0.003588162376578369, -0.003718362558663737, -0.003755596511143005, -0.003694818131674599, --0.003533315298404129, -0.003270878754553819, -0.002909914962857412, -0.002455496391464944, -0.001915346645364514, --0.001299757227227888, -0.000621437066532776, 0.000104706515738248, 0.000861849931067767, 0.001631595707499856, - 0.002394368911341672, 0.003129858565588139, 0.003817496679992245, 0.004436963307209760, 0.004968707287606522, - 0.005394469536085115, 0.005697797543539088, 0.005864537618023589, 0.005883292537600076, 0.005745832319314692, - 0.005447447099071761, 0.004987231255534477, 0.004368289529377007, 0.003597859022418248, 0.002687338851256991, - 0.001652226293162047, 0.000511956075882180, -0.000710356149138656, -0.001988263330091648, -0.003292424566049982, --0.004591123342747130, -0.005850857852106148, -0.007036991266043732, -0.008114450164977267, -0.009048456200082230, --0.009805276478965942, -0.010352975302354198, -0.010662152577592631, -0.010706650669328861, -0.010464214075017983, --0.009917087295446811, -0.009052534679222271, -0.007863270920348924, -0.006347789704693751, -0.004510582323649121, --0.002362238055733795, 0.000080576968834213, 0.002795265196543707, 0.005753566158586979, 0.008921944932552510, - 0.012262093950265378, 0.015731539846483594, 0.019284344624007944, 0.022871886384520687, 0.026443706729191677, - 0.029948406200633094, 0.033334570666910354, 0.036551709955124537, 0.039551189200810140, 0.042287133974308874, - 0.044717290029466283, 0.046803820535016104, 0.048514022996355009, 0.049820951883635139, 0.050703932928426454, - 0.051148959210315710, 0.051148959210315710, 0.050703932928426454, 0.049820951883635139, 0.048514022996355009, - 0.046803820535016104, 0.044717290029466283, 0.042287133974308874, 0.039551189200810140, 0.036551709955124537, - 0.033334570666910354, 0.029948406200633094, 0.026443706729191677, 0.022871886384520687, 0.019284344624007944, - 0.015731539846483594, 0.012262093950265378, 0.008921944932552510, 0.005753566158586979, 0.002795265196543707, - 0.000080576968834213, -0.002362238055733795, -0.004510582323649121, -0.006347789704693751, -0.007863270920348924, --0.009052534679222271, -0.009917087295446811, -0.010464214075017983, -0.010706650669328861, -0.010662152577592631, --0.010352975302354198, -0.009805276478965942, -0.009048456200082230, -0.008114450164977267, -0.007036991266043732, --0.005850857852106148, -0.004591123342747130, -0.003292424566049982, -0.001988263330091648, -0.000710356149138656, - 0.000511956075882180, 0.001652226293162047, 0.002687338851256991, 0.003597859022418248, 0.004368289529377007, - 0.004987231255534477, 0.005447447099071761, 0.005745832319314692, 0.005883292537600076, 0.005864537618023589, - 0.005697797543539088, 0.005394469536085115, 0.004968707287606522, 0.004436963307209760, 0.003817496679992245, - 0.003129858565588139, 0.002394368911341672, 0.001631595707499856, 0.000861849931067767, 0.000104706515738248, --0.000621437066532776, -0.001299757227227888, -0.001915346645364514, -0.002455496391464944, -0.002909914962857412, --0.003270878754553819, -0.003533315298404129, -0.003694818131674599, -0.003755596511143005, -0.003718362558663737, --0.003588162376578369, -0.003372155891804708, -0.003079353614002113, -0.002720317947026380, -0.002306838088978190, --0.001851587344265625, -0.001367771151677059, -0.000868777013398284, -0.000367832138027160, 0.000122320866350319, - 0.000589723521647734, 0.001023470495638453, 0.001413941154886139, 0.001752990365583534, 0.002034094661603120, - 0.002252452724297770, 0.002405037734357425, 0.002490604086803692, 0.002509648218888532, 0.002464328098407475, - 0.002358342626407065, 0.002196778054604388, 0.001985924997799762, 0.001733071409562941, 0.001446279849797673, - 0.001134152328775355, 0.000805591531546815, 0.000469563533327739, 0.000134868279325909, -0.000190077210351809, --0.000497436825078657, -0.000780131048444402, -0.001031986722557201, -0.001247857669697092, -0.001423714708648073, --0.001556702802350076, -0.001645167889846890, -0.001688649703502788, -0.001687846581475964, -0.001644551048567398, --0.001561559957317790, -0.001442563411804926, -0.001292014799874503, -0.001114986581270253, -0.000917016099829735, --0.000703946352348464, -0.000481764526566339, -0.000256444114966522, -0.000033793183292569, 0.000180685902835315, - 0.000381924396468366, 0.000565398080608305, 0.000727219011746881, 0.000864209315714227, 0.000973950761085690, - 0.001054815583369999, 0.001105974243787613, 0.001127383039339373, 0.001119751426837743, 0.001084492755093968, - 0.001023657909064450, 0.000939856052624227, 0.000836164238172957, 0.000716029226064227, 0.000583164190168290, - 0.000441441918072383, 0.000294790953130229, 0.000147092077716480, 0.000002082667095075, -0.000136731311264191, --0.000266155252511831, -0.000383371840261246, -0.000485996080304965, -0.000572115873292030, -0.000640319946685634, --0.000689709694056092, -0.000719899536922384, -0.000731002305621048, -0.000723604675185869, -0.000698728981427767, --0.000657788245032425, -0.000602532044011899, -0.000534985542936898, -0.000457387566635848, -0.000372121907291206, --0.000281651282503015, -0.000188451833293202, -0.000094949813106744, -0.000003462782744354, 0.000083853091464077, - 0.000165048886226905, 0.000238422248479072, 0.000302547334727027, 0.000356297600912998, 0.000398857326863837, - 0.000429729020814434, 0.000448726371643413, 0.000455966225408344, 0.000451848709179591, 0.000437031818051652, - 0.000412403761615261, 0.000379047713684221, 0.000338204791740229, 0.000291234779803098, 0.000239577162514028, - 0.000184710477990398, 0.000128114399130489, 0.000071232572821451, 0.000015440388211825, -0.000037986085678081, --0.000087895370243821, -0.000133280012107173, -0.000173297342436372, -0.000207273956099563, -0.000234717772155001, --0.000255317038867589, -0.000268937472718753, -0.000275614059005332, -0.000275541485292432, -0.000269058714331757, --0.000256632149501508, -0.000238836419299503, -0.000216333899003825, -0.000189854272533545, -0.000160170174848483, --0.000128080670195777, -0.000094384355854646, -0.000059865389594949, -0.000025277165852799, 0.000008680571408025, - 0.000041365841965015, 0.000072210925236429, 0.000100726393185629, 0.000126511346757621, 0.000149250512353807, - 0.000168719942655099, 0.000184780318878738, 0.000197379393194548, 0.000206539880117977, 0.000212358734245594, - 0.000214994859281552, 0.000214655997661182, 0.000211604878787747, 0.000206128795372885, 0.000198541881389953, - 0.000189176709991702, 0.000178368313347299, 0.000166450784469067, 0.000153744508371709, 0.000140558396336177, - 0.000127174196746337, 0.000113853476544409, 0.000100818605854714, 0.000088271373315159, 0.000076360900545177, - 0.000065233162392019, 0.000054970017069384, 0.000045630720487935, 0.000037271082107518, 0.000029885221425020, - 0.000023463361155584, 0.000017966192635412, 0.000013350669444763, 0.000009551098482930, 0.000006499942123311, - 0.000004115682735322, 0.000002322193058869, 0.000001038946634000, 0.000000197734700398, -0.000000267011791999, --0.000005050567303837 }; - -} // FreeDV diff --git a/libfreedv/freedv_vhf_framing.cpp b/libfreedv/freedv_vhf_framing.cpp deleted file mode 100644 index 86c9bf208..000000000 --- a/libfreedv/freedv_vhf_framing.cpp +++ /dev/null @@ -1,886 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: fsk.c - AUTHOR......: Brady O'Brien - DATE CREATED: 11 February 2016 - - Framer and deframer for VHF FreeDV modes 'A' and 'B' - Currently designed for- - * 40ms ota modem frames - * 40ms Codec2 1300 frames - * 52 bits of Codec2 per frame - * 16 bits of unique word per frame - * 28 'spare' bits per frame - * - 4 spare bits at front and end of frame (8 total) for padding - * - 20 'protocol' bits, either for higher layers of 'protocol' or - * - 18 'protocol' bits and 2 vericode sidechannel bits - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2016 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 -#include -#include -#include "freedv_vhf_framing.h" - -namespace FreeDV -{ - -/* The voice UW of the VHF type A frame */ -static const uint8_t A_uw_v[] = {0,1,1,0,0,1,1,1, - 1,0,1,0,1,1,0,1}; - -/* The data UW of the VHF type A frame */ -static const uint8_t A_uw_d[] = {1,1,1,1,0,0,0,1, - 1,1,1,1,1,1,0,0}; - -/* Blank VHF type A frame */ -static const uint8_t A_blank[] = {1,0,1,0,0,1,1,1, /* Padding[0:3] Proto[0:3] */ - 1,0,1,0,0,1,1,1, /* Proto[4:11] */ - 0,0,0,0,0,0,0,0, /* Voice[0:7] */ - 0,0,0,0,0,0,0,0, /* Voice[8:15] */ - 0,0,0,0,0,0,0,0, /* Voice[16:23] */ - 0,1,1,0,0,1,1,1, /* UW[0:7] */ - 1,0,1,0,1,1,0,1, /* UW[8:15] */ - 0,0,0,0,0,0,0,0, /* Voice[24:31] */ - 0,0,0,0,0,0,0,0, /* Voice[32:39] */ - 0,0,0,0,0,0,0,0, /* Voice[40:47] */ - 0,0,0,0,0,0,1,0, /* Voice[48:51] Proto[12:15] */ - 0,1,1,1,0,0,1,0};/* Proto[16:19] Padding[4:7] */ - -/* Blank VHF type AT (A for TDMA; padding bits not transmitted) frame */ -static const uint8_t AT_blank[] = { 0,1,1,1, /* Proto[0:3] */ - 1,0,1,0,0,1,1,1, /* Proto[4:11] */ - 0,0,0,0,0,0,0,0, /* Voice[0:7] */ - 0,0,0,0,0,0,0,0, /* Voice[8:15] */ - 0,0,0,0,0,0,0,0, /* Voice[16:23] */ - 0,1,1,0,0,1,1,1, /* UW[0:7] */ - 1,0,1,0,1,1,0,1, /* UW[8:15] */ - 0,0,0,0,0,0,0,0, /* Voice[24:31] */ - 0,0,0,0,0,0,0,0, /* Voice[32:39] */ - 0,0,0,0,0,0,0,0, /* Voice[40:47] */ - 0,0,0,0,0,0,1,0, /* Voice[48:51] Proto[12:15] */ - 0,1,1,1 };/* Proto[16:19] */ - -/* HF Type B voice UW */ -static const uint8_t B_uw_v[] = {0,1,1,0,0,1,1,1}; - -/* HF Type B data UW */ -static const uint8_t B_uw_d[] = {1,1,1,1,0,0,1,0}; - -/* Blank HF type B frame */ -static const uint8_t B_blank[] = {0,1,1,0,0,1,1,1, /* UW[0:7] */ - 0,0,0,0,0,0,0,0, /* Voice1[0:7] */ - 0,0,0,0,0,0,0,0, /* Voice1[8:15] */ - 0,0,0,0,0,0,0,0, /* Voice1[16:23] */ - 0,0,0,0,0,0,0,0, /* Voice1[24:28] Voice2[0:3] */ - 0,0,0,0,0,0,0,0, /* Voice2[4:11] */ - 0,0,0,0,0,0,0,0, /* Voice2[12:19] */ - 0,0,0,0,0,0,0,0};/* Voice2[20:28] */ - -/* States */ -#define ST_NOSYNC 0 /* Not synchronized */ -#define ST_SYNC 1 /* Synchronized */ - -/* Get a single bit out of an MSB-first packed byte array */ -#define UNPACK_BIT_MSBFIRST(bytes,bitidx) ((bytes)[(bitidx)>>3]>>(7-((bitidx)&0x7)))&0x1 - -enum frame_payload_type { - FRAME_PAYLOAD_TYPE_VOICE, - FRAME_PAYLOAD_TYPE_DATA, -}; - -/* Place codec and other bits into a frame */ -void fvhff_frame_bits( int frame_type, - uint8_t bits_out[], - uint8_t codec2_in[], - uint8_t proto_in[], - uint8_t vc_in[]){ - int i,ibit; - if(frame_type == FREEDV_VHF_FRAME_A){ - /* Fill out frame with blank frame prototype */ - for(i=0; i<96; i++) - bits_out[i] = A_blank[i]; - - /* Fill in protocol bits, if present */ - if(proto_in!=NULL){ - ibit = 0; - /* First half of protocol bits */ - /* Extract and place in frame, MSB first */ - for(i=4 ; i<16; i++){ - bits_out[i] = UNPACK_BIT_MSBFIRST(proto_in,ibit); - ibit++; - } - /* Last set of protocol bits */ - for(i=84; i<92; i++){ - bits_out[i] = UNPACK_BIT_MSBFIRST(proto_in,ibit); - ibit++; - } - } - - /* Fill in varicode bits, if present */ - if(vc_in!=NULL){ - bits_out[90] = vc_in[0]; - bits_out[91] = vc_in[1]; - } - - /* Fill in codec2 bits, present or not */ - ibit = 0; - for(i=16; i<40; i++){ /* First half */ - bits_out[i] = UNPACK_BIT_MSBFIRST(codec2_in,ibit); - ibit++; - } - for(i=56; i<84; i++){ /* Second half */ - bits_out[i] = UNPACK_BIT_MSBFIRST(codec2_in,ibit); - ibit++; - } - }else if(frame_type == FREEDV_HF_FRAME_B){ - /* Pointers to both c2 frames so the bit unpack macro works */ - uint8_t * codec2_in1 = &codec2_in[0]; - uint8_t * codec2_in2 = &codec2_in[4]; - /* Fill out frame with blank prototype */ - for(i=0; i<64; i++) - bits_out[i] = B_blank[i]; - - /* Fill out first codec2 block */ - ibit=0; - for(i=8; i<36; i++){ - bits_out[i] = UNPACK_BIT_MSBFIRST(codec2_in1,ibit); - ibit++; - } - /* Fill out second codec2 block */ - ibit=0; - for(i=36; i<64; i++){ - bits_out[i] = UNPACK_BIT_MSBFIRST(codec2_in2,ibit); - ibit++; - } - }else if(frame_type == FREEDV_VHF_FRAME_AT){ - /* Fill out frame with blank frame prototype */ - for(i=0; i<88; i++) - bits_out[i] = AT_blank[i]; - - /* Fill in protocol bits, if present */ - if(proto_in!=NULL){ - ibit = 0; - /* First half of protocol bits */ - /* Extract and place in frame, MSB first */ - for(i=0 ; i<12; i++){ - bits_out[i] = UNPACK_BIT_MSBFIRST(proto_in,ibit); - ibit++; - } - /* Last set of protocol bits */ - for(i=80; i<88; i++){ - bits_out[i] = UNPACK_BIT_MSBFIRST(proto_in,ibit); - ibit++; - } - } - - /* Fill in varicode bits, if present */ - if(vc_in!=NULL){ - bits_out[86] = vc_in[0]; - bits_out[87] = vc_in[1]; - } - - /* Fill in codec2 bits, present or not */ - ibit = 0; - for(i=12; i<36; i++){ /* First half */ - bits_out[i] = UNPACK_BIT_MSBFIRST(codec2_in,ibit); - ibit++; - } - for(i=52; i<80; i++){ /* Second half */ - bits_out[i] = UNPACK_BIT_MSBFIRST(codec2_in,ibit); - ibit++; - } - } -} - -/* Place data and other bits into a frame */ -void fvhff_frame_data_bits(struct freedv_vhf_deframer * def, int frame_type, - uint8_t bits_out[]){ - int i,ibit; - if(frame_type == FREEDV_VHF_FRAME_A){ - uint8_t data[8]; - int end_bits; - int from_bit; - int bcast_bit; - int crc_bit; - - /* Fill out frame with blank frame prototype */ - for(i=0; i<4; i++) - bits_out[i] = A_blank[i]; - for(i=92; i<96; i++) - bits_out[i] = A_blank[i]; - - /* UW data */ - for (i=0; i < 16; i++) - bits_out[40 + i] = A_uw_d[i]; - - if (def->fdc) - freedv_data_channel_tx_frame(def->fdc, data, 8, &from_bit, &bcast_bit, &crc_bit, &end_bits); - else - return; - - bits_out[4] = from_bit; - bits_out[5] = bcast_bit; - bits_out[6] = 0; /* unused */ - bits_out[7] = 0; /* unused */ - - /* Fill in data bits */ - ibit = 0; - for(i=8; i<40; i++){ /* First half */ - bits_out[i] = UNPACK_BIT_MSBFIRST(data,ibit); - ibit++; - } - for(i=56; i<88; i++){ /* Second half */ - bits_out[i] = UNPACK_BIT_MSBFIRST(data,ibit); - ibit++; - } - - for (i = 0; i < 4; i++) - bits_out[88 + i] = (end_bits >> (3-i)) & 0x1; - } else if (frame_type == FREEDV_HF_FRAME_B){ - uint8_t data[6]; - int end_bits; - int from_bit; - int bcast_bit; - int crc_bit; - - /* Fill out frame with blank prototype */ - for(i=0; i<64; i++) - bits_out[i] = B_blank[i]; - - /* UW data */ - for (i=0; i < 8; i++) - bits_out[0 + i] = B_uw_d[i]; - - if (def->fdc) - freedv_data_channel_tx_frame(def->fdc, data, 6, &from_bit, &bcast_bit, &crc_bit, &end_bits); - else - return; - - bits_out[56] = from_bit; - bits_out[57] = bcast_bit; - bits_out[58] = crc_bit; - bits_out[59] = 0; /* unused */ - - /* Fill in data bits */ - ibit = 0; - for(i=8; i<56; i++){ /* First half */ - bits_out[i] = UNPACK_BIT_MSBFIRST(data,ibit); - ibit++; - } - for (i = 0; i < 4; i++) - bits_out[60 + i] = (end_bits >> (3-i)) & 0x1; - } -} - -/* Init and allocate memory for a freedv-vhf framer/deframer */ -struct freedv_vhf_deframer * fvhff_create_deframer(uint8_t frame_type, int enable_bit_flip) -{ - struct freedv_vhf_deframer * deframer; - uint8_t *bits,*invbits; - int frame_size; - int uw_size; - - assert((frame_type == FREEDV_VHF_FRAME_A) || (frame_type == FREEDV_HF_FRAME_B)); - - /* It's a Type A frame */ - if (frame_type == FREEDV_VHF_FRAME_A) - { - frame_size = 96; - uw_size = 16; - } - else if (frame_type == FREEDV_HF_FRAME_B) - { - frame_size = 64; - uw_size = 8; - } - else - { - return nullptr; - } - - /* Allocate memory for the thing */ - deframer = (freedv_vhf_deframer*) malloc(sizeof(struct freedv_vhf_deframer)); - - if (deframer == nullptr) { - return nullptr; - } - - /* Allocate the not-bit buffer */ - if (enable_bit_flip) - { - invbits = (uint8_t*) malloc(sizeof(uint8_t)*frame_size); - - if (invbits == nullptr) - { - free(deframer); - return nullptr; - } - } - else - { - invbits = nullptr; - } - - /* Allocate the bit buffer */ - bits = (uint8_t*) malloc(sizeof(uint8_t)*frame_size); - - if (bits == nullptr) - { - if (invbits) { - free(invbits); - } - - free(deframer); - return nullptr; - } - - deframer->bits = bits; - deframer->invbits = invbits; - deframer->ftype = frame_type; - deframer->state = ST_NOSYNC; - deframer->bitptr = 0; - deframer->last_uw = 0; - deframer->miss_cnt = 0; - deframer->frame_size = frame_size; - deframer->uw_size = uw_size; - deframer->on_inv_bits = 0; - deframer->sym_size = 1; - - deframer->ber_est = 0; - deframer->total_uw_bits = 0; - deframer->total_uw_err = 0; - - deframer->fdc = NULL; - - return deframer; -} - -/* Get size of frame in bits */ -int fvhff_get_frame_size(struct freedv_vhf_deframer * def){ - return def->frame_size; -} - -/* Codec2 size in bytes */ -int fvhff_get_codec2_size(struct freedv_vhf_deframer * def){ - if(def->ftype == FREEDV_VHF_FRAME_A){ - return 7; - } else if(def->ftype == FREEDV_HF_FRAME_B){ - return 8; - } else{ - return 0; - } -} - -/* Protocol bits in bits */ -int fvhff_get_proto_size(struct freedv_vhf_deframer * def){ - if(def->ftype == FREEDV_VHF_FRAME_A){ - return 20; - } else if(def->ftype == FREEDV_HF_FRAME_B){ - return 0; - } else{ - return 0; - } -} - -/* Varicode bits in bits */ -int fvhff_get_varicode_size(struct freedv_vhf_deframer * def){ - if(def->ftype == FREEDV_VHF_FRAME_A){ - return 2; - } else if(def->ftype == FREEDV_HF_FRAME_B){ - return 0; - } else{ - return 0; - } -} - -void fvhff_destroy_deframer(struct freedv_vhf_deframer * def){ - freedv_data_channel_destroy(def->fdc); - free(def->bits); - free(def); -} - -int fvhff_synchronized(struct freedv_vhf_deframer * def){ - return (def->state) == ST_SYNC; -} - -/* Search for a complete UW in a buffer of bits */ -std::size_t fvhff_search_uw(const uint8_t bits[], std::size_t nbits, - const uint8_t uw[], std::size_t uw_len, - std::size_t * delta_out, std::size_t bits_per_sym){ - - std::size_t ibits,iuw; - std::size_t delta_min = uw_len; - std::size_t delta; - std::size_t offset_min = 0; - /* Walk through buffer bits */ - for(ibits = 0; ibits < nbits-uw_len; ibits+=bits_per_sym){ - delta = 0; - for(iuw = 0; iuw < uw_len; iuw++){ - if(bits[ibits+iuw] != uw[iuw]) delta++; - } - if( delta < delta_min ){ - delta_min = delta; - offset_min = ibits; - } - } - if(delta_out != NULL) *delta_out = delta_min; - return offset_min; -} - -/* See if the UW is where it should be, to within a tolerance, in a bit buffer */ -static int fvhff_match_uw(struct freedv_vhf_deframer * def,uint8_t bits[],int tol,int *rdiff, enum frame_payload_type *pt){ - int frame_type = def->ftype; - int bitptr = def->bitptr; - int frame_size = def->frame_size; - int uw_len = def->uw_size; - int iuw,ibit; - const uint8_t * uw[2]; - int uw_offset; - int diff[2] = { 0, 0 }; - int i; - int match[2]; - int r; - - /* defaults to make compiler happy on -O3 */ - - *pt = FRAME_PAYLOAD_TYPE_VOICE; - *rdiff = 0; - - /* Set up parameters for the standard type of frame */ - if(frame_type == FREEDV_VHF_FRAME_A){ - uw[0] = A_uw_v; - uw[1] = A_uw_d; - uw_len = 16; - uw_offset = 40; - } else if(frame_type == FREEDV_HF_FRAME_B){ - uw[0] = B_uw_v; - uw[1] = B_uw_d; - uw_len = 8; - uw_offset = 0; - } else { - return 0; - } - - /* Check both the voice and data UWs */ - for (i = 0; i < 2; i++) { - /* Start bit pointer where UW should be */ - ibit = bitptr + uw_offset; - if(ibit >= frame_size) ibit -= frame_size; - /* Walk through and match bits in frame with bits of UW */ - for(iuw=0; iuw= frame_size) ibit = 0; - } - match[i] = diff[i] <= tol; - } - /* Pick the best matching UW */ - - if (diff[0] < diff[1]) { - r = match[0]; - *rdiff = diff[0]; - *pt = FRAME_PAYLOAD_TYPE_VOICE; - } else { - r = match[1]; - *rdiff = diff[1]; - *pt = FRAME_PAYLOAD_TYPE_DATA; - } - - return r; -} - -static void fvhff_extract_frame_voice(struct freedv_vhf_deframer * def,uint8_t bits[], - uint8_t codec2_out[],uint8_t proto_out[],uint8_t vc_out[]){ - int frame_type = def->ftype; - int bitptr = def->bitptr; - int frame_size = def->frame_size; - int iframe,ibit; - - if(frame_type == FREEDV_VHF_FRAME_A){ - /* Extract codec2 bits */ - memset(codec2_out,0,7); - ibit = 0; - /* Extract and pack first half, MSB first */ - iframe = bitptr+16; - if(iframe >= frame_size) iframe-=frame_size; - for(;ibit<24;ibit++){ - codec2_out[ibit>>3] |= (bits[iframe]&0x1)<<(7-(ibit&0x7)); - iframe++; - if(iframe >= frame_size) iframe=0; - } - - /* Extract and pack last half, MSB first */ - iframe = bitptr+56; - if(iframe >= frame_size) iframe-=frame_size; - for(;ibit<52;ibit++){ - codec2_out[ibit>>3] |= (bits[iframe]&0x1)<<(7-(ibit&0x7)); - iframe++; - if(iframe >= frame_size) iframe=0; - } - /* Extract varicode bits, if wanted */ - if(vc_out!=NULL){ - iframe = bitptr+90; - if(iframe >= frame_size) iframe-=frame_size; - vc_out[0] = bits[iframe]; - iframe++; - vc_out[1] = bits[iframe]; - } - /* Extract protocol bits, if proto is passed through */ - if(proto_out!=NULL){ - /* Clear protocol bit array */ - memset(proto_out,0,3); - ibit = 0; - /* Extract and pack first half, MSB first */ - iframe = bitptr+4; - if(iframe >= frame_size) iframe-=frame_size; - for(;ibit<12;ibit++){ - proto_out[ibit>>3] |= (bits[iframe]&0x1)<<(7-(ibit&0x7)); - iframe++; - if(iframe >= frame_size) iframe=0; - } - - /* Extract and pack last half, MSB first */ - iframe = bitptr+84; - if(iframe >= frame_size) iframe-=frame_size; - for(;ibit<20;ibit++){ - proto_out[ibit>>3] |= (bits[iframe]&0x1)<<(7-(ibit&0x7)); - iframe++; - if(iframe >= frame_size) iframe=0; - } - } - - }else if(frame_type == FREEDV_HF_FRAME_B){ - /* Pointers to both c2 frames */ - uint8_t * codec2_out1 = &codec2_out[0]; - uint8_t * codec2_out2 = &codec2_out[4]; - - /* Extract codec2 bits */ - memset(codec2_out,0,8); - ibit = 0; - - /* Extract and pack first c2 frame, MSB first */ - iframe = bitptr+8; - if(iframe >= frame_size) iframe-=frame_size; - for(;ibit<28;ibit++){ - codec2_out1[ibit>>3] |= (bits[iframe]&0x1)<<(7-(ibit&0x7)); - iframe++; - if(iframe >= frame_size) iframe=0; - } - - /* Extract and pack second c2 frame, MSB first */ - iframe = bitptr+36; - ibit = 0; - if(iframe >= frame_size) iframe-=frame_size; - for(;ibit<28;ibit++){ - codec2_out2[ibit>>3] |= (bits[iframe]&0x1)<<(7-(ibit&0x7)); - iframe++; - if(iframe >= frame_size) iframe=0; - } - }else if(frame_type == FREEDV_VHF_FRAME_AT){ - /* Extract codec2 bits */ - memset(codec2_out,0,7); - ibit = 0; - /* Extract and pack first half, MSB first */ - iframe = bitptr+12; - if(iframe >= frame_size) iframe-=frame_size; - for(;ibit<24;ibit++){ - codec2_out[ibit>>3] |= (bits[iframe]&0x1)<<(7-(ibit&0x7)); - iframe++; - if(iframe >= frame_size) iframe=0; - } - - /* Extract and pack last half, MSB first */ - iframe = bitptr+52; - if(iframe >= frame_size) iframe-=frame_size; - for(;ibit<52;ibit++){ - codec2_out[ibit>>3] |= (bits[iframe]&0x1)<<(7-(ibit&0x7)); - iframe++; - if(iframe >= frame_size) iframe=0; - } - /* Extract varicode bits, if wanted */ - if(vc_out!=NULL){ - iframe = bitptr+86; - if(iframe >= frame_size) iframe-=frame_size; - vc_out[0] = bits[iframe]; - iframe++; - vc_out[1] = bits[iframe]; - } - /* Extract protocol bits, if proto is passed through */ - if(proto_out!=NULL){ - /* Clear protocol bit array */ - memset(proto_out,0,3); - ibit = 0; - /* Extract and pack first half, MSB first */ - iframe = bitptr+4; - if(iframe >= frame_size) iframe-=frame_size; - for(;ibit<12;ibit++){ - proto_out[ibit>>3] |= (bits[iframe]&0x1)<<(7-(ibit&0x7)); - iframe++; - if(iframe >= frame_size) iframe=0; - } - - /* Extract and pack last half, MSB first */ - iframe = bitptr+84; - if(iframe >= frame_size) iframe-=frame_size; - for(;ibit<20;ibit++){ - proto_out[ibit>>3] |= (bits[iframe]&0x1)<<(7-(ibit&0x7)); - iframe++; - if(iframe >= frame_size) iframe=0; - } - } - - } -} - -static void fvhff_extract_frame_data(struct freedv_vhf_deframer * def,uint8_t bits[]){ - int frame_type = def->ftype; - int bitptr = def->bitptr; - int frame_size = def->frame_size; - int iframe,ibit; - - if(frame_type == FREEDV_VHF_FRAME_A){ - uint8_t data[8]; - int end_bits = 0; - int from_bit; - int bcast_bit; - - iframe = bitptr+4; - if(iframe >= frame_size) iframe-=frame_size; - from_bit = bits[iframe]; - iframe++; - if(iframe >= frame_size) iframe-=frame_size; - bcast_bit = bits[iframe]; - - /* Extract data bits */ - memset(data,0,8); - ibit = 0; - /* Extract and pack first half, MSB first */ - iframe = bitptr+8; - if(iframe >= frame_size) iframe-=frame_size; - for(;ibit<32;ibit++){ - data[ibit>>3] |= (bits[iframe]&0x1)<<(7-(ibit&0x7)); - iframe++; - if(iframe >= frame_size) iframe=0; - } - - /* Extract and pack last half, MSB first */ - iframe = bitptr+56; - if(iframe >= frame_size) iframe-=frame_size; - for(;ibit<64;ibit++){ - data[ibit>>3] |= (bits[iframe]&0x1)<<(7-(ibit&0x7)); - iframe++; - if(iframe >= frame_size) iframe=0; - } - - /* Extract endbits value, MSB first*/ - iframe = bitptr+88; - ibit = 0; - if(iframe >= frame_size) iframe-=frame_size; - for(;ibit<4;ibit++){ - end_bits |= (bits[iframe]&0x1)<<(3-(ibit)); - iframe++; - if(iframe >= frame_size) iframe=0; - } - - if (def->fdc) { - freedv_data_channel_rx_frame(def->fdc, data, 8, from_bit, bcast_bit, 0, end_bits); - } - } else if(frame_type == FREEDV_HF_FRAME_B){ - uint8_t data[6]; - int end_bits = 0; - int from_bit; - int bcast_bit; - int crc_bit; - - ibit = 0; - memset(data,0,6); - - /* Extract and pack first c2 frame, MSB first */ - iframe = bitptr+8; - if(iframe >= frame_size) iframe-=frame_size; - for(;ibit<48;ibit++){ - data[ibit>>3] |= (bits[iframe]&0x1)<<(7-(ibit&0x7)); - iframe++; - if(iframe >= frame_size) iframe=0; - } - - iframe = bitptr+56; - if(iframe >= frame_size) iframe-=frame_size; - from_bit = bits[iframe]; - iframe++; - if(iframe >= frame_size) iframe-=frame_size; - bcast_bit = bits[iframe]; - iframe++; - if(iframe >= frame_size) iframe-=frame_size; - crc_bit = bits[iframe]; - - /* Extract endbits value, MSB first*/ - iframe = bitptr+60; - ibit = 0; - if(iframe >= frame_size) iframe-=frame_size; - for(;ibit<4;ibit++){ - end_bits |= (bits[iframe]&0x1)<<(3-(ibit)); - iframe++; - if(iframe >= frame_size) iframe=0; - } - - if (def->fdc) { - freedv_data_channel_rx_frame(def->fdc, data, 6, from_bit, bcast_bit, crc_bit, end_bits); - } - } -} - -static void fvhff_extract_frame(struct freedv_vhf_deframer * def,uint8_t bits[],uint8_t codec2_out[], - uint8_t proto_out[],uint8_t vc_out[],enum frame_payload_type pt){ - switch (pt) { - case FRAME_PAYLOAD_TYPE_VOICE: - fvhff_extract_frame_voice(def, bits, codec2_out, proto_out, vc_out); - break; - case FRAME_PAYLOAD_TYPE_DATA: - fvhff_extract_frame_data(def, bits); - break; - } -} - -/* - * Try to find the UW and extract codec/proto/vc bits in def->frame_size bits - */ -int fvhff_deframe_bits(struct freedv_vhf_deframer * def,uint8_t codec2_out[],uint8_t proto_out[], - uint8_t vc_out[],uint8_t bits_in[]){ - uint8_t * strbits = def->bits; - uint8_t * invbits = def->invbits; - uint8_t * bits; - int on_inv_bits = def->on_inv_bits; - int frame_type = def->ftype; - int state = def->state; - int bitptr = def->bitptr; - int last_uw = def->last_uw; - int miss_cnt = def->miss_cnt; - int frame_size = def->frame_size; - int uw_size = def->uw_size; - int uw_diff; - int i; - int uw_first_tol; - int uw_sync_tol; - int miss_tol; - int extracted_frame = 0; - enum frame_payload_type pt = FRAME_PAYLOAD_TYPE_VOICE; - - /* Possibly set up frame-specific params here */ - if(frame_type == FREEDV_VHF_FRAME_A){ - uw_first_tol = 1; /* The UW bit-error tolerance for the first frame */ - uw_sync_tol = 3; /* The UW bit error tolerance for frames after sync */ - miss_tol = 4; /* How many UWs may be missed before going into the de-synced state */ - }else if(frame_type == FREEDV_HF_FRAME_B){ - uw_first_tol = 0; /* The UW bit-error tolerance for the first frame */ - uw_sync_tol = 1; /* The UW bit error tolerance for frames after sync */ - miss_tol = 3; /* How many UWs may be missed before going into the de-synced state */ - }else{ - return 0; - } - /* Skip N bits for multi-bit symbol modems */ - for(i=0; i= frame_size) bitptr -= frame_size; - def->bitptr = bitptr; - /* Enter state machine */ - if(state==ST_SYNC){ - /* Already synchronized, just wait till UW is back where it should be */ - last_uw++; - if(invbits!=NULL){ - if(on_inv_bits) - bits = invbits; - else - bits = strbits; - }else{ - bits=strbits; - } - /* UW should be here. We're sunk, so deframe anyway */ - if(last_uw == frame_size){ - last_uw = 0; - - if(!fvhff_match_uw(def,bits,uw_sync_tol,&uw_diff, &pt)) - miss_cnt++; - else - miss_cnt=0; - - /* If we go over the miss tolerance, go into no-sync */ - if(miss_cnt>miss_tol){ - state = ST_NOSYNC; - } - /* Extract the bits */ - extracted_frame = 1; - fvhff_extract_frame(def,bits,codec2_out,proto_out,vc_out,pt); - - /* Update BER estimate */ - def->ber_est = (.995*def->ber_est) + (.005*((float)uw_diff)/((float)uw_size)); - def->total_uw_bits += uw_size; - def->total_uw_err += uw_diff; - } - /* Not yet sunk */ - }else{ - /* It's a sync!*/ - if(invbits!=NULL){ - if(fvhff_match_uw(def,invbits,uw_first_tol, &uw_diff, &pt)){ - state = ST_SYNC; - last_uw = 0; - miss_cnt = 0; - extracted_frame = 1; - on_inv_bits = 1; - fvhff_extract_frame(def,invbits,codec2_out,proto_out,vc_out,pt); - /* Update BER estimate */ - def->ber_est = (.995*def->ber_est) + (.005*((float)uw_diff)/((float)uw_size)); - def->total_uw_bits += uw_size; - def->total_uw_err += uw_diff; - } - } - if(fvhff_match_uw(def,strbits,uw_first_tol, &uw_diff, &pt)){ - state = ST_SYNC; - last_uw = 0; - miss_cnt = 0; - extracted_frame = 1; - on_inv_bits = 0; - fvhff_extract_frame(def,strbits,codec2_out,proto_out,vc_out,pt); - /* Update BER estimate */ - def->ber_est = (.995*def->ber_est) + (.005*((float)uw_diff)/((float)uw_size)); - def->total_uw_bits += uw_size; - def->total_uw_err += uw_diff; - } - } - } - def->state = state; - def->last_uw = last_uw; - def->miss_cnt = miss_cnt; - def->on_inv_bits = on_inv_bits; - /* return zero for data frames, they are already handled by callback */ - return extracted_frame && pt == FRAME_PAYLOAD_TYPE_VOICE; -} - -} // FreeDV diff --git a/libfreedv/freedv_vhf_framing.h b/libfreedv/freedv_vhf_framing.h deleted file mode 100644 index 3f08cbb2e..000000000 --- a/libfreedv/freedv_vhf_framing.h +++ /dev/null @@ -1,104 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: freedv_vhf_framing.h - AUTHOR......: Brady O'Brien - DATE CREATED: 11 February 2016 - - Framer and deframer for VHF FreeDV modes 'A' and 'B' - Currently designed for- - * 40ms ota modem frames - * 40ms Codec2 1300 frames - * 52 bits of Codec2 per frame - * 16 bits of unique word per frame - * 28 'spare' bits per frame - * - 4 spare bits at front and end of frame (8 total) for padding - * - 20 'protocol' bits, either for higher layers of 'protocol' or - * - 18 'protocol' bits and 2 vericode sidechannel bits -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2016 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 . -*/ - -#ifndef _FREEDV_VHF_FRAMING_H -#define _FREEDV_VHF_FRAMING_H - -#include -#include "freedv_data_channel.h" - -/* Standard frame type */ -#define FREEDV_VHF_FRAME_A 1 /* 2400A/B Frame */ -#define FREEDV_HF_FRAME_B 2 /* 800XA Frame */ -#define FREEDV_VHF_FRAME_AT 3 /* 4800T Frame */ - -namespace FreeDV -{ - -struct freedv_vhf_deframer { - int ftype; /* Type of frame to be looking for */ - int state; /* State of deframer */ - uint8_t * bits; /* Bits currently being decanted */ - uint8_t * invbits; /* Inversion of bits currently being decanted, for FMFSK */ - - int bitptr; /* Pointer into circular bit buffer */ - int miss_cnt; /* How many UWs have been missed */ - int last_uw; /* How many bits since the last UW? */ - int frame_size; /* How big is a frame? */ - int uw_size; /* How big is the UW */ - int on_inv_bits; /* Are we using the inverted bits? */ - int sym_size; /* How many bits in a modem symbol */ - - float ber_est; /* Bit error rate estimate */ - int total_uw_bits; /* Total RX-ed bits of UW */ - int total_uw_err; /* Total errors in UW bits */ - - struct freedv_data_channel *fdc; -}; - -/* Init and allocate memory for a freedv-vhf framer/deframer */ -struct freedv_vhf_deframer * fvhff_create_deframer(uint8_t frame_type,int enable_bit_flip); - -/* Get size of various frame parameters */ -/* Frame size in bits */ -int fvhff_get_frame_size(struct freedv_vhf_deframer * def); -/* Codec2 size in bytes */ -int fvhff_get_codec2_size(struct freedv_vhf_deframer * def); -/* Protocol bits in bits */ -int fvhff_get_proto_size(struct freedv_vhf_deframer * def); -/* Varicode bits in bits */ -int fvhff_get_varicode_size(struct freedv_vhf_deframer * def); - -/* Free the memory used by a freedv-vhf framer/deframer */ -void fvhff_destroy_deframer(struct freedv_vhf_deframer * def); - -/* Place codec and other bits into a frame */ -void fvhff_frame_bits(int frame_type,uint8_t bits_out[],uint8_t codec2_in[],uint8_t proto_in[],uint8_t vc_in[]); -void fvhff_frame_data_bits(struct freedv_vhf_deframer * def, int frame_type,uint8_t bits_out[]); - -/* Find and extract frames from a stream of bits */ -int fvhff_deframe_bits(struct freedv_vhf_deframer * def,uint8_t codec2_out[],uint8_t proto_out[],uint8_t vc_out[],uint8_t bits_in[]); - -/* Is the de-framer synchronized? */ -int fvhff_synchronized(struct freedv_vhf_deframer * def); - -/* Search for a complete UW in a buffer of bits */ -std::size_t fvhff_search_uw(const uint8_t bits[],size_t nbits, - const uint8_t uw[], std::size_t uw_len, - std::size_t * delta_out, std::size_t bits_per_sym); - -} // FreeDV - -#endif //_FREEDV_VHF_FRAMING_H diff --git a/libfreedv/fsk.cpp b/libfreedv/fsk.cpp deleted file mode 100644 index e966b5550..000000000 --- a/libfreedv/fsk.cpp +++ /dev/null @@ -1,1257 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: fsk.c - AUTHOR......: Brady O'Brien - DATE CREATED: 7 January 2016 - - C Implementation of 2/4FSK modulator/demodulator, based on octave/fsk_horus.m - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2016 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 . -*/ - -/*---------------------------------------------------------------------------*\ - - DEFINES - -\*---------------------------------------------------------------------------*/ - -/* P oversampling rate constant -- should probably be init-time configurable */ -#define horus_P 8 - -/* Define this to enable EbNodB estimate */ -/* This needs square roots, may take more cpu time than it's worth */ -#define EST_EBNO - -/* This is a flag for the freq. estimator to use a precomputed/rt computed hann window table - On platforms with slow cosf, this will produce a substantial speedup at the cost of a small - amount of memory -*/ -#define USE_HANN_TABLE - -/* This flag turns on run-time hann table generation. If USE_HANN_TABLE is unset, - this flag has no effect. If USE_HANN_TABLE is set and this flag is set, the - hann table will be allocated and generated when fsk_init or fsk_init_hbr is - called. If this flag is not set, a hann function table of size fsk->Ndft MUST - be provided. On small platforms, this can be used with a precomputed table to - save memory at the cost of flash space. -*/ -#define GENERATE_HANN_TABLE_RUNTIME - -/* Turn off table generation if on cortex M4 to save memory */ -#ifdef CORTEX_M4 -#undef USE_HANN_TABLE -#endif - -/*---------------------------------------------------------------------------*\ - - INCLUDES - -\*---------------------------------------------------------------------------*/ - -#include -#include -#include -#include - -#include "fsk.h" -#include "comp_prim.h" -#include "kiss_fftr.h" -#include "modem_probe.h" - -namespace FreeDV -{ - -/*---------------------------------------------------------------------------*\ - - FUNCTIONS - -\*---------------------------------------------------------------------------*/ - -static void stats_init(struct FSK *fsk); - -#ifdef USE_HANN_TABLE -/* - This is used by fsk_create and fsk_create_hbr to generate a hann function - table -*/ -static void fsk_generate_hann_table(struct FSK* fsk){ - int Ndft = fsk->Ndft; - int i; - - /* Set up complex oscilator to calculate hann function */ - COMP dphi = comp_exp_j((2*M_PI)/((float)Ndft-1)); - COMP rphi = {.5,0}; - - rphi = cmult(cconj(dphi),rphi); - - for (i = 0; i < Ndft; i++) - { - rphi = cmult(dphi,rphi); - float hannc = .5-rphi.real; - //float hann = .5-(.5*cosf((2*M_PI*(float)(i))/((float)Ndft-1))); - fsk->hann_table[i] = hannc; - } -} -#endif - - - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: fsk_create_hbr - AUTHOR......: Brady O'Brien - DATE CREATED: 11 February 2016 - - Create and initialize an instance of the FSK modem. Returns a pointer - to the modem state/config struct. One modem config struct may be used - for both mod and demod. returns NULL on failure. - -\*---------------------------------------------------------------------------*/ - -struct FSK * fsk_create_hbr(int Fs, int Rs,int P,int M, int tx_f1, int tx_fs) -{ - struct FSK *fsk; - int i; - int memold; - int Ndft = 0; - /* Number of symbols in a processing frame */ - int nsyms = 48; - /* Check configuration validity */ - assert(Fs > 0 ); - assert(Rs > 0 ); - assert(tx_f1 > 0); - assert(tx_fs > 0); - assert(P > 0); - /* Ts (Fs/Rs) must be an integer */ - assert( (Fs%Rs) == 0 ); - /* Ts/P (Fs/Rs/P) must be an integer */ - assert( ((Fs/Rs)%P) == 0 ); - assert( M==2 || M==4); - - fsk = (struct FSK*) malloc(sizeof(struct FSK)); - if(fsk == NULL) return NULL; - - - /* Set constant config parameters */ - fsk->Fs = Fs; - fsk->Rs = Rs; - fsk->Ts = Fs/Rs; - fsk->burst_mode = 0; - fsk->N = fsk->Ts*nsyms; - fsk->P = P; - fsk->Nsym = nsyms; - fsk->Nmem = fsk->N+(2*fsk->Ts); - fsk->f1_tx = tx_f1; - fsk->fs_tx = tx_fs; - fsk->nin = fsk->N; - fsk->mode = M==2 ? MODE_2FSK : MODE_4FSK; - fsk->Nbits = M==2 ? fsk->Nsym : fsk->Nsym*2; - - /* Find smallest 2^N value that fits Fs for efficient FFT */ - /* It would probably be better to use KISS-FFt's routine here */ - for(i=1; i; i<<=1) - if((fsk->N)&i) - Ndft = i; - - fsk->Ndft = Ndft; - - fsk->est_min = Rs/4; - if(fsk->est_min<0) fsk->est_min = 0; - - fsk->est_max = (Fs/2)-Rs/4; - - fsk->est_space = Rs-(Rs/5); - - /* Set up rx state */ - - for( i=0; iphi_c[i] = comp_exp_j(0); - - memold = (4*fsk->Ts); - - fsk->nstash = memold; - fsk->samp_old = (COMP*) malloc(sizeof(COMP)*memold); - if(fsk->samp_old == NULL){ - free(fsk); - return NULL; - } - - for(i=0;isamp_old[i].real = 0; - fsk->samp_old[i].imag = 0; - } - - fsk->fft_cfg = kiss_fft_alloc(fsk->Ndft,0,NULL,NULL); - if(fsk->fft_cfg == NULL){ - free(fsk->samp_old); - free(fsk); - return NULL; - } - - fsk->fft_est = (float*)malloc(sizeof(float)*fsk->Ndft/2); - if(fsk->fft_est == NULL){ - free(fsk->samp_old); - free(fsk->fft_cfg); - free(fsk); - return NULL; - } - - #ifdef USE_HANN_TABLE - #ifdef GENERATE_HANN_TABLE_RUNTIME - fsk->hann_table = (float*)malloc(sizeof(float)*fsk->Ndft); - if(fsk->hann_table == NULL){ - free(fsk->fft_est); - free(fsk->samp_old); - free(fsk->fft_cfg); - free(fsk); - return NULL; - } - fsk_generate_hann_table(fsk); - #else - fsk->hann_table = NULL; - #endif - #endif - - for(i=0;iNdft/2;i++)fsk->fft_est[i] = 0; - - fsk->norm_rx_timing = 0; - - /* Set up tx state */ - fsk->tx_phase_c = comp_exp_j(0); - - /* Set up demod stats */ - fsk->EbNodB = 0; - - for( i=0; if_est[i] = 0; - - fsk->ppm = 0; - - fsk->stats = (struct MODEM_STATS*)malloc(sizeof(struct MODEM_STATS)); - if(fsk->stats == NULL){ - free(fsk->fft_est); - free(fsk->samp_old); - free(fsk->fft_cfg); - free(fsk); - return NULL; - } - stats_init(fsk); - fsk->normalise_eye = 1; - - return fsk; -} - - -#define HORUS_MIN 800 -#define HORUS_MAX 2500 -#define HORUS_MIN_SPACING 100 - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: fsk_create - AUTHOR......: Brady O'Brien - DATE CREATED: 7 January 2016 - - Create and initialize an instance of the FSK modem. Returns a pointer - to the modem state/config struct. One modem config struct may be used - for both mod and demod. returns NULL on failure. - -\*---------------------------------------------------------------------------*/ - -struct FSK * fsk_create(int Fs, int Rs,int M, int tx_f1, int tx_fs) -{ - struct FSK *fsk; - int i; - int Ndft = 0; - int memold; - - /* Check configuration validity */ - assert(Fs > 0 ); - assert(Rs > 0 ); - assert(tx_f1 > 0); - assert(tx_fs > 0); - assert(horus_P > 0); - /* Ts (Fs/Rs) must be an integer */ - assert( (Fs%Rs) == 0 ); - /* Ts/P (Fs/Rs/P) must be an integer */ - assert( ((Fs/Rs)%horus_P) == 0 ); - assert( M==2 || M==4); - - fsk = (struct FSK*) malloc(sizeof(struct FSK)); - if(fsk == NULL) return NULL; - - Ndft = 1024; - - /* Set constant config parameters */ - fsk->Fs = Fs; - fsk->Rs = Rs; - fsk->Ts = Fs/Rs; - fsk->N = Fs; - fsk->burst_mode = 0; - fsk->P = horus_P; - fsk->Nsym = fsk->N/fsk->Ts; - fsk->Ndft = Ndft; - fsk->Nmem = fsk->N+(2*fsk->Ts); - fsk->f1_tx = tx_f1; - fsk->fs_tx = tx_fs; - fsk->nin = fsk->N; - fsk->mode = M==2 ? MODE_2FSK : MODE_4FSK; - fsk->Nbits = M==2 ? fsk->Nsym : fsk->Nsym*2; - fsk->est_min = HORUS_MIN; - fsk->est_max = HORUS_MAX; - fsk->est_space = HORUS_MIN_SPACING; - - /* Set up rx state */ - for( i=0; iphi_c[i] = comp_exp_j(0); - - memold = (4*fsk->Ts); - - fsk->nstash = memold; - fsk->samp_old = (COMP*) malloc(sizeof(COMP)*memold); - if(fsk->samp_old == NULL){ - free(fsk); - return NULL; - } - - for(i=0;isamp_old[i].real = 0.0; - fsk->samp_old[i].imag = 0.0; - } - - fsk->fft_cfg = kiss_fft_alloc(Ndft,0,NULL,NULL); - if(fsk->fft_cfg == NULL){ - free(fsk->samp_old); - free(fsk); - return NULL; - } - - fsk->fft_est = (float*)malloc(sizeof(float)*fsk->Ndft/2); - if(fsk->fft_est == NULL){ - free(fsk->samp_old); - free(fsk->fft_cfg); - free(fsk); - return NULL; - } - - #ifdef USE_HANN_TABLE - #ifdef GENERATE_HANN_TABLE_RUNTIME - fsk->hann_table = (float*)malloc(sizeof(float)*fsk->Ndft); - if(fsk->hann_table == NULL){ - free(fsk->fft_est); - free(fsk->samp_old); - free(fsk->fft_cfg); - free(fsk); - return NULL; - } - fsk_generate_hann_table(fsk); - #else - fsk->hann_table = NULL; - #endif - #endif - - for(i=0;ifft_est[i] = 0; - - fsk->norm_rx_timing = 0; - - /* Set up tx state */ - fsk->tx_phase_c = comp_exp_j(0); - - /* Set up demod stats */ - fsk->EbNodB = 0; - - for( i=0; if_est[i] = 0; - - fsk->ppm = 0; - - fsk->stats = (struct MODEM_STATS*)malloc(sizeof(struct MODEM_STATS)); - - if(fsk->stats == NULL){ - free(fsk->fft_est); - free(fsk->samp_old); - free(fsk->fft_cfg); - free(fsk); - return NULL; - } - stats_init(fsk); - fsk->normalise_eye = 1; - - return fsk; -} - -/* make sure stats have known values in case monitoring process reads stats before they are set */ - -static void stats_init(struct FSK *fsk) { - /* Take a sample for the eye diagrams */ - int i,j,m; - int P = fsk->P; - int M = fsk->mode; - - /* due to oversample rate P, we have too many samples for eye - trace. So lets output a decimated version */ - - /* asserts below as we found some problems over-running eye matrix */ - - /* TODO: refactor eye tracing code here and in fsk_demod */ - - int neyesamp_dec = ceil(((float)P*2)/MODEM_STATS_EYE_IND_MAX); - int neyesamp = (P*2)/neyesamp_dec; - assert(neyesamp <= MODEM_STATS_EYE_IND_MAX); - fsk->stats->neyesamp = neyesamp; - - int eye_traces = MODEM_STATS_ET_MAX/M; - - fsk->stats->neyetr = fsk->mode*eye_traces; - for(i=0; istats->rx_eye[i*M+m][j] = 0; - } - } - } - - fsk->stats->rx_timing = fsk->stats->snr_est = 0; - -} - - -void fsk_set_nsym(struct FSK *fsk,int nsyms){ - assert(nsyms>0); - int Ndft,i; - Ndft = 0; - - /* Set constant config parameters */ - fsk->N = fsk->Ts*nsyms; - fsk->Nsym = nsyms; - fsk->Nmem = fsk->N+(2*fsk->Ts); - fsk->nin = fsk->N; - fsk->Nbits = fsk->mode==2 ? fsk->Nsym : fsk->Nsym*2; - - /* Find smallest 2^N value that fits Fs for efficient FFT */ - /* It would probably be better to use KISS-FFt's routine here */ - for(i=1; i; i<<=1) - if((fsk->N)&i) - Ndft = i; - - fsk->Ndft = Ndft; - - free(fsk->fft_cfg); - free(fsk->fft_est); - - fsk->fft_cfg = kiss_fft_alloc(Ndft,0,NULL,NULL); - fsk->fft_est = (float*)malloc(sizeof(float)*fsk->Ndft/2); - - for(i=0;ifft_est[i] = 0; - -} - -/* Set the FSK modem into burst demod mode */ - -void fsk_enable_burst_mode(struct FSK *fsk,int nsyms){ - fsk_set_nsym(fsk,nsyms); - fsk->nin = fsk->N; - fsk->burst_mode = 1; -} - -void fsk_clear_estimators(struct FSK *fsk){ - int i; - /* Clear freq estimator state */ - for(i=0; i < (fsk->Ndft/2); i++){ - fsk->fft_est[i] = 0; - } - /* Reset timing diff correction */ - fsk->nin = fsk->N; -} - -uint32_t fsk_nin(struct FSK *fsk){ - return (uint32_t)fsk->nin; -} - -void fsk_destroy(struct FSK *fsk){ - free(fsk->fft_cfg); - free(fsk->samp_old); - free(fsk->stats); - free(fsk); -} - -void fsk_get_demod_stats(struct FSK *fsk, struct MODEM_STATS *stats){ - /* copy from internal stats, note we can't overwrite stats completely - as it has other states rqd by caller, also we want a consistent - interface across modem types for the freedv_api. - */ - - stats->clock_offset = fsk->stats->clock_offset; - stats->snr_est = fsk->stats->snr_est; // TODO: make this SNR not Eb/No - stats->rx_timing = fsk->stats->rx_timing; - stats->foff = fsk->stats->foff; - - stats->neyesamp = fsk->stats->neyesamp; - stats->neyetr = fsk->stats->neyetr; - memcpy(stats->rx_eye, fsk->stats->rx_eye, sizeof(stats->rx_eye)); - memcpy(stats->f_est, fsk->stats->f_est, fsk->mode*sizeof(float)); - - /* these fields not used for FSK so set to something sensible */ - - stats->sync = 0; - stats->nr = fsk->stats->nr; - stats->Nc = fsk->stats->Nc; -} - -/* - * Set the minimum and maximum frequencies at which the freq. estimator can find tones - */ -void fsk_set_est_limits(struct FSK *fsk,int est_min, int est_max){ - - fsk->est_min = est_min; - if(fsk->est_min<0) fsk->est_min = 0; - - fsk->est_max = est_max; -} - -/* - * Internal function to estimate the frequencies of the two tones within a block of samples. - * This is split off because it is fairly complicated, needs a bunch of memory, and probably - * takes more cycles than the rest of the demod. - * Parameters: - * fsk - FSK struct from demod containing FSK config - * fsk_in - block of samples in this demod cycles, must be nin long - * freqs - Array for the estimated frequencies - * M - number of frequency peaks to find - */ -void fsk_demod_freq_est(struct FSK *fsk, COMP fsk_in[],float *freqs,int M){ - int Ndft = fsk->Ndft; - int Fs = fsk->Fs; - int nin = fsk->nin; - int i,j; - float hann; - float max; - float tc; - int imax; - kiss_fft_cfg fft_cfg = fsk->fft_cfg; - int *freqi = new int[M]; - int f_min,f_max,f_zero; - - /* Array to do complex FFT from using kiss_fft */ - kiss_fft_cpx *fftin = (kiss_fft_cpx*)malloc(sizeof(kiss_fft_cpx)*Ndft); - kiss_fft_cpx *fftout = (kiss_fft_cpx*)malloc(sizeof(kiss_fft_cpx)*Ndft); - - #ifndef USE_HANN_TABLE - COMP dphi = comp_exp_j((2*M_PI)/((float)Ndft-1)); - COMP rphi = {.5,0}; - rphi = cmult(cconj(dphi),rphi); - #endif - - f_min = (fsk->est_min*Ndft)/Fs; - f_max = (fsk->est_max*Ndft)/Fs; - f_zero = (fsk->est_space*Ndft)/Fs; - - /* scale averaging time constant based on number of samples */ - tc = 0.95*Ndft/Fs; - - int samps; - int fft_samps; - int fft_loops = nin / Ndft; - - for (j = 0; j < fft_loops; j++) - { - /* 48000 sample rate (for example) will have a spare */ - /* 896 samples besides the 46 "Ndft" samples, so adjust */ - - samps = (nin - ((j + 1) * Ndft)); - fft_samps = (samps >= Ndft) ? Ndft : samps; - - /* Copy FSK buffer into reals of FFT buffer and apply a hann window */ - for(i=0; ihann_table[i]; - #else - //hann = 1-cosf((2*M_PI*(float)(i))/((float)fft_samps-1)); - rphi = cmult(dphi,rphi); - hann = .5-rphi.real; - #endif - fftin[i].r = hann*fsk_in[i+Ndft*j].real; - fftin[i].i = hann*fsk_in[i+Ndft*j].imag; - } - - /* Zero out the remaining slots on spare samples */ - for(; ifft_est[i] = (fsk->fft_est[i]*(1-tc)) + (sqrtf(fftout[i].r)*tc); - fftout[i].i = fsk->fft_est[i]; - } - } - - modem_probe_samp_f("t_fft_est", fsk->fft_est, Ndft/2); - - max = 0; - /* Find the M frequency peaks here */ - for(i=0; i max){ - max = fftout[j].i; - imax = j; - } - } - /* Blank out FMax +/-Fspace/2 */ - f_min = imax - f_zero; - f_min = f_min < 0 ? 0 : f_min; - f_max = imax + f_zero; - f_max = f_max > Ndft ? Ndft : f_max; - for(j=f_min; j= freqi[i-1]) i++; - else{ - j = freqi[i]; - freqi[i] = freqi[i-1]; - freqi[i-1] = j; - if(i>1) i--; - } - } - - /* Convert freqs from indices to frequencies */ - for(i=0; iN; - int Ts = fsk->Ts; - int Rs = fsk->Rs; - int Fs = fsk->Fs; - int nsym = fsk->Nsym; - int nin = fsk->nin; - int P = fsk->P; - int Nmem = fsk->Nmem; - int M = fsk->mode; - int i, j, m, dc_i, cbuf_i; - float ft1; - int nstash = fsk->nstash; - - COMP* *f_int = new COMP*[M]; /* Filtered and downsampled symbol tones */ - COMP *t = new COMP[M]; /* complex number temps */ - COMP t_c; /* another complex temp */ - COMP *phi_c = new COMP[M]; - COMP phi_ft; - int nold = Nmem-nin; - - COMP *dphi = new COMP[M]; - COMP dphift; - float rx_timing,norm_rx_timing,old_norm_rx_timing,d_norm_rx_timing,appm; - int using_old_samps; - - COMP* sample_src; - COMP* f_intbuf_m; - - float *f_est = new float[M]; - float fc_avg, fc_tx; - float meanebno,stdebno,eye_max; - int neyesamp,neyeoffset; - - #ifdef MODEMPROBE_ENABLE - char mp_name_tmp[20]; /* Temporary string for modem probe trace names */ - #endif - - //for(size_t jj = 0; jjphi_c[m]; - } - - /* Estimate tone frequencies */ - fsk_demod_freq_est(fsk,fsk_in,f_est,M); - modem_probe_samp_f("t_f_est",f_est,M); - - - /* Allocate circular buffer for integration */ - f_intbuf_m = (COMP*) malloc(sizeof(COMP)*Ts); - - /* allocate memory for the integrated samples */ - for( m=0; mf_est[0]<1){ - for( m=0; mf_est[m] = f_est[m]; - } - - /* Initalize downmixers for each symbol tone */ - for( m=0; mf_est[m])/(float)(Fs))); - phi_c[m] = cmult(dphi[m],phi_c[m]); - //fprintf(stderr,"F%d = %f",m,fsk->f_est[m]); - - /* Figure out how much to nudge each sample downmixer for every sample */ - dphi[m] = comp_exp_j(2*M_PI*((fsk->f_est[m])/(float)(Fs))); - } - - /* Integrate and downsample for symbol tones */ - for(m=0; msamp_old[nstash-nold]); - using_old_samps = 1; - - /* Pre-fill integration buffer */ - for(dc_i=0; dc_i=nold && using_old_samps){ - sample_src = &fsk_in[0]; - dc_i = 0; - using_old_samps = 0; - - /* Recalculate delta-phi after switching to new sample source */ - phi_c[m] = comp_normalize(phi_c[m]); - dphi_m = comp_exp_j(2*M_PI*((f_est_m)/(float)(Fs))); - } - /* Downconvert and place into integration buffer */ - f_intbuf_m[dc_i]=cmult(sample_src[dc_i],cconj(phi_c[m])); - - #ifdef MODEMPROBE_ENABLE - snprintf(mp_name_tmp,19,"t_f%zd_dc",m+1); - modem_probe_samp_c(mp_name_tmp,&f_intbuf_m[dc_i],1); - #endif - /* Spin downconversion phases */ - phi_c[m] = cmult(phi_c[m],dphi_m); - } - cbuf_i = dc_i; - - /* Integrate over Ts at offsets of Ts/P */ - for(i=0; i<(nsym+1)*P; i++){ - /* Downconvert and Place Ts/P samples in the integration buffers */ - for(j=0; j<(Ts/P); j++,dc_i++){ - /* Switch sample source to new samples when we run out of old ones */ - if(dc_i>=nold && using_old_samps){ - sample_src = &fsk_in[0]; - dc_i = 0; - using_old_samps = 0; - - /* Recalculate delta-phi after switching to new sample source */ - phi_c[m] = comp_normalize(phi_c[m]); - dphi_m = comp_exp_j(2*M_PI*((f_est_m)/(float)(Fs))); - } - /* Downconvert and place into integration buffer */ - f_intbuf_m[cbuf_i+j]=cmult(sample_src[dc_i],cconj(phi_c[m])); - - #ifdef MODEMPROBE_ENABLE - snprintf(mp_name_tmp,19,"t_f%zd_dc",m+1); - modem_probe_samp_c(mp_name_tmp,&f_intbuf_m[cbuf_i+j],1); - #endif - /* Spin downconversion phases */ - phi_c[m] = cmult(phi_c[m],dphi_m); - - } - - /* Dump internal samples */ - cbuf_i += Ts/P; - if(cbuf_i>=Ts) cbuf_i = 0; - - /* Integrate over the integration buffers, save samples */ - float it_r = 0; - float it_i = 0; - for(j=0; jphi_c[m] = phi_c[m]; - fsk->f_est[m] = f_est[m]; - } - - /* Stash samples away in the old sample buffer for the next round of bit getting */ - memcpy((void*)&(fsk->samp_old[0]),(void*)&(fsk_in[nin-nstash]),sizeof(COMP)*nstash); - - /* Fine Timing Estimation */ - /* Apply magic nonlinearity to f1_int and f2_int, shift down to 0, - * extract angle */ - - /* Figure out how much to spin the oscillator to extract magic spectral line */ - dphift = comp_exp_j(2*M_PI*((float)(Rs)/(float)(P*Rs))); - phi_ft.real = 1; - phi_ft.imag = 0; - t_c=comp0(); - for(i=0; i<(nsym+1)*P; i++){ - /* Get abs^2 of fx_int[i], and add 'em */ - ft1 = 0; - for( m=0; mnorm_rx_timing; - fsk->norm_rx_timing = norm_rx_timing; - - /* Estimate sample clock offset */ - d_norm_rx_timing = norm_rx_timing - old_norm_rx_timing; - - /* Filter out big jumps in due to nin change */ - if(fabsf(d_norm_rx_timing) < .2){ - appm = 1e6*d_norm_rx_timing/(float)nsym; - fsk->ppm = .9*fsk->ppm + .1*appm; - } - - /* Figure out how many samples are needed the next modem cycle */ - /* Unless we're in burst mode */ - if(!fsk->burst_mode){ - if(norm_rx_timing > 0.25) - fsk->nin = N+Ts/2; - else if(norm_rx_timing < -0.25) - fsk->nin = N-Ts/2; - else - fsk->nin = N; - } - - modem_probe_samp_f("t_norm_rx_timing",&(norm_rx_timing),1); - modem_probe_samp_i("t_nin",&(fsk->nin),1); - - /* Re-sample the integrators with linear interpolation magic */ - int low_sample = (int)floorf(rx_timing); - float fract = rx_timing - (float)low_sample; - int high_sample = (int)ceilf(rx_timing); - - /* Vars for finding the max-of-4 for each bit */ - float *tmax = new float[M]; - - #ifdef EST_EBNO - meanebno = 0; - stdebno = 0; - #endif - - /* FINALLY, THE BITS */ - /* also, resample fx_int */ - for(i = 0; i < nsym; i++) - { - int st = (i+1)*P; - for( m=0; mmax){ - max = tmax[m]; - sym = m; - } - if(tmax[m]>1; - } - } - - /* Produce soft decision symbols */ - if(rx_sd != NULL){ - /* Convert symbols from max^2 into max */ - for( m=0; m 0.0) { - stdebno = sqrt(stdebno); - } else { - stdebno = 0.0; - } - - fsk->EbNodB = -6+(20*log10f((1e-6+meanebno)/(1e-6+stdebno))); - #else - fsk->EbNodB = 1; - #endif - - /* Write some statistics to the stats struct */ - - /* Save clock offset in ppm */ - fsk->stats->clock_offset = fsk->ppm; - - /* Calculate and save SNR from EbNodB estimate */ - - fsk->stats->snr_est = .5*fsk->stats->snr_est + .5*fsk->EbNodB;//+ 10*log10f(((float)Rs)/((float)Rs*M)); - - /* Save rx timing */ - fsk->stats->rx_timing = (float)rx_timing; - - /* Estimate and save frequency offset */ - fc_avg = (f_est[0]+f_est[1])/2; - fc_tx = (fsk->f1_tx+fsk->f1_tx+fsk->fs_tx)/2; - fsk->stats->foff = fc_tx-fc_avg; - - /* Take a sample for the eye diagrams ---------------------------------- */ - - /* due to oversample rate P, we have too many samples for eye - trace. So lets output a decimated version. We use 2P - as we want two symbols worth of samples in trace */ - - int neyesamp_dec = ceil(((float)P*2)/MODEM_STATS_EYE_IND_MAX); - neyesamp = (P*2)/neyesamp_dec; - assert(neyesamp <= MODEM_STATS_EYE_IND_MAX); - fsk->stats->neyesamp = neyesamp; - - #ifdef I_DONT_UNDERSTAND - neyeoffset = high_sample+1+(P*28); /* WTF this line? Where does "28" come from ? */ - #endif /* ifdef-ed out as I am afraid it will index out of memory as P changes */ - neyeoffset = high_sample+1; - - int eye_traces = MODEM_STATS_ET_MAX/M; - int ind; - - fsk->stats->neyetr = fsk->mode*eye_traces; - for( i=0; iMODEM_STATS_EYE_IND_MAX advance through integrated - samples newamp_dec at a time so we dont overflow rx_eye[][] - */ - ind = 2*P*i + neyeoffset + j*neyesamp_dec; - assert((i*M+m) < MODEM_STATS_ET_MAX); - assert(ind < (nsym+1)*P); - fsk->stats->rx_eye[i*M+m][j] = cabsolute(f_int[m][ind]); - } - } - } - - if (fsk->normalise_eye) { - eye_max = 0; - /* Normalize eye to +/- 1 */ - for(i=0; istats->rx_eye[i][j])>eye_max) - eye_max = fabsf(fsk->stats->rx_eye[i][j]); - - for(i=0; istats->rx_eye[i][j] = fsk->stats->rx_eye[i][j]/eye_max; - } - - fsk->stats->nr = 0; - fsk->stats->Nc = 0; - - for(i=0; istats->f_est[i] = f_est[i]; - } - - /* Dump some internal samples */ - modem_probe_samp_f("t_EbNodB",&(fsk->EbNodB),1); - modem_probe_samp_f("t_ppm",&(fsk->ppm),1); - modem_probe_samp_f("t_rx_timing",&(rx_timing),1); - - #ifdef MODEMPROBE_ENABLE - for( m=0; mtx_phase_c; /* Current complex TX phase */ - int f1_tx = fsk->f1_tx; /* '0' frequency */ - int fs_tx = fsk->fs_tx; /* space between frequencies */ - int Ts = fsk->Ts; /* samples-per-symbol */ - int Fs = fsk->Fs; /* sample freq */ - int M = fsk->mode; - COMP *dosc_f = new COMP[M]; /* phase shift per sample */ - COMP dph; /* phase shift of current bit */ - int i, j, m, bit_i, sym; - - /* Init the per sample phase shift complex numbers */ - for( m=0; mNsym; i++){ - sym = 0; - /* Pack the symbol number from the bit stream */ - for( m=M; m>>=1; ){ - uint8_t bit = tx_bits[bit_i]; - bit = (bit==1)?1:0; - sym = (sym<<1)|bit; - bit_i++; - } - /* Look up symbol phase shift */ - dph = dosc_f[sym]; - /* Spin the oscillator for a symbol period */ - for(j=0; jtx_phase_c = tx_phase_c; - - delete[] dosc_f; -} - -void fsk_mod_c(struct FSK *fsk,COMP fsk_out[],uint8_t tx_bits[]){ - COMP tx_phase_c = fsk->tx_phase_c; /* Current complex TX phase */ - int f1_tx = fsk->f1_tx; /* '0' frequency */ - int fs_tx = fsk->fs_tx; /* space between frequencies */ - int Ts = fsk->Ts; /* samples-per-symbol */ - int Fs = fsk->Fs; /* sample freq */ - int M = fsk->mode; - COMP *dosc_f = new COMP[M]; /* phase shift per sample */ - COMP dph; /* phase shift of current bit */ - int i, j, bit_i, sym; - int m; - - /* Init the per sample phase shift complex numbers */ - for( m=0; mNsym; i++){ - sym = 0; - /* Pack the symbol number from the bit stream */ - for( m=M; m>>=1; ){ - uint8_t bit = tx_bits[bit_i]; - bit = (bit==1)?1:0; - sym = (sym<<1)|bit; - bit_i++; - } - /* Look up symbol phase shift */ - dph = dosc_f[sym]; - /* Spin the oscillator for a symbol period */ - for(j=0; jtx_phase_c = tx_phase_c; - - delete[] dosc_f; -} - - -/* Modulator that assume an external VCO. The output is a voltage - that changes for each symbol */ - -void fsk_mod_ext_vco(struct FSK *fsk, float vco_out[], uint8_t tx_bits[]) { - int f1_tx = fsk->f1_tx; /* '0' frequency */ - int fs_tx = fsk->fs_tx; /* space between frequencies */ - int Ts = fsk->Ts; /* samples-per-symbol */ - int M = fsk->mode; - int i, j, m, sym, bit_i; - - bit_i = 0; - for(i=0; iNsym; i++) { - /* generate the symbol number from the bit stream, - e.g. 0,1 for 2FSK, 0,1,2,3 for 4FSK */ - - sym = 0; - - /* unpack the symbol number from the bit stream */ - - for( m=M; m>>=1; ){ - uint8_t bit = tx_bits[bit_i]; - bit = (bit==1)?1:0; - sym = (sym<<1)|bit; - bit_i++; - } - - /* - Map 'sym' to VCO frequency - Note: drive is inverted, a higher tone drives VCO voltage lower - */ - - //fprintf(stderr, "i: %d sym: %d freq: %f\n", i, sym, f1_tx + fs_tx*(float)sym); - for(j=0; jnormalise_eye = normalise_enable; -} - -} // freeDV - - - - - diff --git a/libfreedv/fsk.h b/libfreedv/fsk.h deleted file mode 100644 index 412d904e0..000000000 --- a/libfreedv/fsk.h +++ /dev/null @@ -1,209 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: fsk.h - AUTHOR......: Brady O'Brien - DATE CREATED: 6 January 2016 - - C Implementation of 2FSK/4FSK modulator/demodulator, based on octave/fsk_horus.m - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2016 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 . -*/ - - -#ifndef __C2FSK_H -#define __C2FSK_H -#include -#include "codec2/comp.h" -#include "kiss_fftr.h" -#include "modem_stats.h" - -#define MODE_2FSK 2 -#define MODE_4FSK 4 - -#define MODE_M_MAX 4 - -#define FSK_SCALE 16383 - -namespace FreeDV -{ - -struct FSK { - /* Static parameters set up by fsk_init */ - int Ndft; /* buffer size for freq offset est fft */ - int Fs; /* sample freq */ - int N; /* processing buffer size */ - int Rs; /* symbol rate */ - int Ts; /* samples per symbol */ - int Nmem; /* size of extra mem for timing adj */ - int P; /* oversample rate for timing est/adj */ - int Nsym; /* Number of symbols spat out in a processing frame */ - int Nbits; /* Number of bits spat out in a processing frame */ - int f1_tx; /* f1 for modulator */ - int fs_tx; /* Space between TX freqs for modulatosr */ - int mode; /* 2FSK or 4FSK */ - int est_min; /* Minimum frequency for freq. estimator */ - int est_max; /* Maximum frequency for freq. estimaotr */ - int est_space; /* Minimum frequency spacing for freq. estimator */ - float* hann_table; /* Precomputed or runtime computed hann window table */ - - /* Parameters used by demod */ - COMP phi_c[MODE_M_MAX]; - - kiss_fft_cfg fft_cfg; /* Config for KISS FFT, used in freq est */ - float norm_rx_timing; /* Normalized RX timing */ - - COMP* samp_old; /* Tail end of last batch of samples */ - int nstash; /* How many elements are in there */ - - float* fft_est; /* Freq est FFT magnitude */ - - /* Memory used by demod but not important between demod frames */ - - /* Parameters used by mod */ - COMP tx_phase_c; /* TX phase, but complex */ - - /* Statistics generated by demod */ - float EbNodB; /* Estimated EbNo in dB */ - float f_est[MODE_M_MAX];/* Estimated frequencies */ - float ppm; /* Estimated PPM clock offset */ - - /* Parameters used by mod/demod and driving code */ - int nin; /* Number of samples to feed the next demod cycle */ - int burst_mode; /* enables/disables 'burst' mode */ - - /* modem statistic struct */ - struct MODEM_STATS *stats; - int normalise_eye; /* enables/disables normalisation of eye diagram */ -}; - -/* - * Create an FSK config/state struct from a set of config parameters - * - * int Fs - Sample frequency - * int Rs - Symbol rate - * int tx_f1 - '0' frequency - * int tx_fs - frequency spacing - */ -struct FSK * fsk_create(int Fs, int Rs, int M, int tx_f1, int tx_fs); - -/* - * Create an FSK config/state struct from a set of config parameters - * - * int Fs - Sample frequency - * int Rs - Symbol rate - * int tx_f1 - '0' frequency - * int tx_fs - frequency spacing - */ -struct FSK * fsk_create_hbr(int Fs, int Rs, int P, int M, int tx_f1, int tx_fs); - -/* - * Set a new number of symbols per processing frame - */ -void fsk_set_nsym(struct FSK *fsk,int nsym); - -/* - * Set the minimum and maximum frequencies at which the freq. estimator can find tones - */ -void fsk_set_est_limits(struct FSK *fsk,int fmin, int fmax); - -/* - * Clear the estimator states - */ -void fsk_clear_estimators(struct FSK *fsk); - -/* - * Fills MODEM_STATS struct with demod statistics - */ -void fsk_get_demod_stats(struct FSK *fsk, struct MODEM_STATS *stats); - -/* - * Destroy an FSK state struct and free it's memory - * - * struct FSK *fsk - FSK config/state struct to be destroyed - */ -void fsk_destroy(struct FSK *fsk); - -/* - * Modulates Nsym bits into N samples - * - * struct FSK *fsk - FSK config/state struct, set up by fsk_create - * float fsk_out[] - Buffer for N samples of modulated FSK - * uint8_t tx_bits[] - Buffer containing Nbits unpacked bits - */ -void fsk_mod(struct FSK *fsk, float fsk_out[], uint8_t tx_bits[]); - -/* - * Modulates Nsym bits into N samples - * - * struct FSK *fsk - FSK config/state struct, set up by fsk_create - * float fsk_out[] - Buffer for N samples of "voltage" used to modulate an external VCO - * uint8_t tx_bits[] - Buffer containing Nbits unpacked bits - */ -void fsk_mod_ext_vco(struct FSK *fsk, float vco_out[], uint8_t tx_bits[]); - -/* - * Modulates Nsym bits into N complex samples - * - * struct FSK *fsk - FSK config/state struct, set up by fsk_create - * comp fsk_out[] - Buffer for N samples of modulated FSK - * uint8_t tx_bits[] - Buffer containing Nbits unpacked bits - */ -void fsk_mod_c(struct FSK *fsk, COMP fsk_out[], uint8_t tx_bits[]); - - -/* - * Returns the number of samples needed for the next fsk_demod() cycle - * - * struct FSK *fsk - FSK config/state struct, set up by fsk_create - * returns - number of samples to be fed into fsk_demod next cycle - */ -uint32_t fsk_nin(struct FSK *fsk); - - -/* - * Demodulate some number of FSK samples. The number of samples to be - * demodulated can be found by calling fsk_nin(). - * - * struct FSK *fsk - FSK config/state struct, set up by fsk_create - * uint8_t rx_bits[] - Buffer for Nbits unpacked bits to be written - * float fsk_in[] - nin samples of modualted FSK - */ -void fsk_demod(struct FSK *fsk, uint8_t rx_bits[],COMP fsk_in[]); - -/* - * Demodulate some number of FSK samples. The number of samples to be - * demodulated can be found by calling fsk_nin(). - * - * struct FSK *fsk - FSK config/state struct, set up by fsk_create - * float rx_bits[] - Buffer for Nbits soft decision bits to be written - * float fsk_in[] - nin samples of modualted FSK - */ -void fsk_demod_sd(struct FSK *fsk, float rx_bits[],COMP fsk_in[]); - -/* enables/disables normalisation of eye diagram samples */ - -void fsk_stats_normalise_eye(struct FSK *fsk, int normalise_enable); - -/* Set the FSK modem into burst demod mode */ - -void fsk_enable_burst_mode(struct FSK *fsk,int nsyms); - -} // FreeSV - -#endif diff --git a/libfreedv/gp_interleaver.cpp b/libfreedv/gp_interleaver.cpp deleted file mode 100644 index 2177097cc..000000000 --- a/libfreedv/gp_interleaver.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: gp_interleaver.c - AUTHOR......: David Rowe - DATE CREATED: April 2018 - - Golden Prime Interleaver. My interpretation of "On the Analysis and - Design of Good Algebraic Interleavers", Xie et al,eq (5). - - See also octvae/gp_interleaver.m - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2018 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 "gp_interleaver.h" - -namespace FreeDV -{ - -/* - Choose b for Golden Prime Interleaver. b is chosen to be the - closest integer, which is relatively prime to N, to the Golden - section of N. - - Implemented with a LUT in C for convenience, Octave version - has a more complete implementation. -*/ - -int b_table[] = { - 112,71, - 224,139, - 448,277, - 672,419, - 896,557, - 1120,701, - 1344,839, - 1568,971, - 1792,1109, - 2016,1249, - 2240,1399, - 2464,1523, - 2688,1663, - 2912,1801, - 3136,1949, - 3360,2081, - 3584,2213 -}; - -int choose_interleaver_b(int Nbits) -{ - unsigned int i; - - for (i = 0; i < sizeof(b_table)/(2*sizeof(int)); i += 2) - { - if (b_table[i] == Nbits) { - return b_table[i+1]; - } - } - - /* if we get it means a Nbits we dont have in our table so choke */ - - fprintf(stderr, "FreeDV::choose_interleaver_b: Nbits not in table return 0 as default"); - return 0; -} - - -void gp_interleave_comp(COMP interleaved_frame[], COMP frame[], int Nbits) { - int b = choose_interleaver_b(Nbits); - int i,j; - for (i=0; i. -*/ - -#ifndef __GP_INTERLEAVER__ -#define __GP_INTERLEAVER__ - -#include "codec2/comp.h" - -namespace FreeDV -{ - -void gp_interleave_comp(COMP interleaved_frame[], COMP frame[], int Nbits); -void gp_deinterleave_comp(COMP frame[], COMP interleaved_frame[], int Nbits); -void gp_interleave_float(float frame[], float interleaved_frame[], int Nbits); -void gp_deinterleave_float(float interleaved_frame[], float frame[], int Nbits); - -} // FreeDV - -#endif diff --git a/libfreedv/hanning.h b/libfreedv/hanning.h deleted file mode 100644 index 167a4e32e..000000000 --- a/libfreedv/hanning.h +++ /dev/null @@ -1,649 +0,0 @@ -/* Generated by hanning_file() Octave function */ - -namespace FreeDV -{ - -const float hanning[]={ - 0, - 2.4171e-05, - 9.66816e-05, - 0.000217525, - 0.000386689, - 0.000604158, - 0.00086991, - 0.00118392, - 0.00154616, - 0.00195659, - 0.00241517, - 0.00292186, - 0.00347661, - 0.00407937, - 0.00473008, - 0.00542867, - 0.00617507, - 0.00696922, - 0.00781104, - 0.00870045, - 0.00963736, - 0.0106217, - 0.0116533, - 0.0127322, - 0.0138581, - 0.0150311, - 0.0162509, - 0.0175175, - 0.0188308, - 0.0201906, - 0.0215968, - 0.0230492, - 0.0245478, - 0.0260923, - 0.0276826, - 0.0293186, - 0.0310001, - 0.032727, - 0.034499, - 0.036316, - 0.0381779, - 0.0400844, - 0.0420354, - 0.0440307, - 0.04607, - 0.0481533, - 0.0502802, - 0.0524506, - 0.0546643, - 0.056921, - 0.0592206, - 0.0615627, - 0.0639473, - 0.0663741, - 0.0688427, - 0.0713531, - 0.0739048, - 0.0764978, - 0.0791318, - 0.0818064, - 0.0845214, - 0.0872767, - 0.0900718, - 0.0929066, - 0.0957807, - 0.0986939, - 0.101646, - 0.104636, - 0.107665, - 0.110732, - 0.113836, - 0.116978, - 0.120156, - 0.123372, - 0.126624, - 0.129912, - 0.133235, - 0.136594, - 0.139989, - 0.143418, - 0.146881, - 0.150379, - 0.153911, - 0.157476, - 0.161074, - 0.164705, - 0.168368, - 0.172063, - 0.17579, - 0.179549, - 0.183338, - 0.187158, - 0.191008, - 0.194888, - 0.198798, - 0.202737, - 0.206704, - 0.2107, - 0.214724, - 0.218775, - 0.222854, - 0.226959, - 0.231091, - 0.235249, - 0.239432, - 0.243641, - 0.247874, - 0.252132, - 0.256414, - 0.260719, - 0.265047, - 0.269398, - 0.273772, - 0.278167, - 0.282584, - 0.287021, - 0.29148, - 0.295958, - 0.300456, - 0.304974, - 0.30951, - 0.314065, - 0.318638, - 0.323228, - 0.327835, - 0.332459, - 0.3371, - 0.341756, - 0.346427, - 0.351113, - 0.355814, - 0.360528, - 0.365256, - 0.369997, - 0.374751, - 0.379516, - 0.384293, - 0.389082, - 0.393881, - 0.398691, - 0.40351, - 0.408338, - 0.413176, - 0.418022, - 0.422876, - 0.427737, - 0.432605, - 0.43748, - 0.44236, - 0.447247, - 0.452138, - 0.457034, - 0.461935, - 0.466839, - 0.471746, - 0.476655, - 0.481568, - 0.486481, - 0.491397, - 0.496313, - 0.501229, - 0.506145, - 0.511061, - 0.515976, - 0.520889, - 0.5258, - 0.530708, - 0.535614, - 0.540516, - 0.545414, - 0.550308, - 0.555197, - 0.560081, - 0.564958, - 0.56983, - 0.574695, - 0.579552, - 0.584402, - 0.589244, - 0.594077, - 0.598901, - 0.603715, - 0.60852, - 0.613314, - 0.618097, - 0.622868, - 0.627628, - 0.632375, - 0.63711, - 0.641831, - 0.646538, - 0.651232, - 0.655911, - 0.660574, - 0.665222, - 0.669855, - 0.67447, - 0.679069, - 0.683651, - 0.688215, - 0.69276, - 0.697287, - 0.701795, - 0.706284, - 0.710752, - 0.7152, - 0.719627, - 0.724033, - 0.728418, - 0.73278, - 0.73712, - 0.741437, - 0.74573, - 0.75, - 0.754246, - 0.758467, - 0.762663, - 0.766833, - 0.770978, - 0.775097, - 0.779189, - 0.783254, - 0.787291, - 0.791301, - 0.795283, - 0.799236, - 0.80316, - 0.807055, - 0.810921, - 0.814756, - 0.81856, - 0.822334, - 0.826077, - 0.829788, - 0.833468, - 0.837115, - 0.840729, - 0.844311, - 0.847859, - 0.851374, - 0.854855, - 0.858301, - 0.861713, - 0.86509, - 0.868431, - 0.871737, - 0.875007, - 0.87824, - 0.881437, - 0.884598, - 0.887721, - 0.890806, - 0.893854, - 0.896864, - 0.899835, - 0.902768, - 0.905661, - 0.908516, - 0.911331, - 0.914106, - 0.916841, - 0.919536, - 0.92219, - 0.924804, - 0.927376, - 0.929907, - 0.932397, - 0.934845, - 0.93725, - 0.939614, - 0.941935, - 0.944213, - 0.946448, - 0.94864, - 0.950789, - 0.952894, - 0.954955, - 0.956972, - 0.958946, - 0.960874, - 0.962759, - 0.964598, - 0.966393, - 0.968142, - 0.969846, - 0.971505, - 0.973118, - 0.974686, - 0.976207, - 0.977683, - 0.979112, - 0.980495, - 0.981832, - 0.983122, - 0.984365, - 0.985561, - 0.986711, - 0.987813, - 0.988868, - 0.989876, - 0.990837, - 0.99175, - 0.992616, - 0.993434, - 0.994204, - 0.994927, - 0.995601, - 0.996228, - 0.996807, - 0.997337, - 0.99782, - 0.998255, - 0.998641, - 0.998979, - 0.999269, - 0.999511, - 0.999704, - 0.999849, - 0.999946, - 0.999994, - 0.999994, - 0.999946, - 0.999849, - 0.999704, - 0.999511, - 0.999269, - 0.998979, - 0.998641, - 0.998255, - 0.99782, - 0.997337, - 0.996807, - 0.996228, - 0.995601, - 0.994927, - 0.994204, - 0.993434, - 0.992616, - 0.99175, - 0.990837, - 0.989876, - 0.988868, - 0.987813, - 0.986711, - 0.985561, - 0.984365, - 0.983122, - 0.981832, - 0.980495, - 0.979112, - 0.977683, - 0.976207, - 0.974686, - 0.973118, - 0.971505, - 0.969846, - 0.968142, - 0.966393, - 0.964598, - 0.962759, - 0.960874, - 0.958946, - 0.956972, - 0.954955, - 0.952894, - 0.950789, - 0.94864, - 0.946448, - 0.944213, - 0.941935, - 0.939614, - 0.93725, - 0.934845, - 0.932397, - 0.929907, - 0.927376, - 0.924804, - 0.92219, - 0.919536, - 0.916841, - 0.914106, - 0.911331, - 0.908516, - 0.905661, - 0.902768, - 0.899835, - 0.896864, - 0.893854, - 0.890806, - 0.887721, - 0.884598, - 0.881437, - 0.87824, - 0.875007, - 0.871737, - 0.868431, - 0.86509, - 0.861713, - 0.858301, - 0.854855, - 0.851374, - 0.847859, - 0.844311, - 0.840729, - 0.837115, - 0.833468, - 0.829788, - 0.826077, - 0.822334, - 0.81856, - 0.814756, - 0.810921, - 0.807055, - 0.80316, - 0.799236, - 0.795283, - 0.791301, - 0.787291, - 0.783254, - 0.779189, - 0.775097, - 0.770978, - 0.766833, - 0.762663, - 0.758467, - 0.754246, - 0.75, - 0.74573, - 0.741437, - 0.73712, - 0.73278, - 0.728418, - 0.724033, - 0.719627, - 0.7152, - 0.710752, - 0.706284, - 0.701795, - 0.697287, - 0.69276, - 0.688215, - 0.683651, - 0.679069, - 0.67447, - 0.669855, - 0.665222, - 0.660574, - 0.655911, - 0.651232, - 0.646538, - 0.641831, - 0.63711, - 0.632375, - 0.627628, - 0.622868, - 0.618097, - 0.613314, - 0.60852, - 0.603715, - 0.598901, - 0.594077, - 0.589244, - 0.584402, - 0.579552, - 0.574695, - 0.56983, - 0.564958, - 0.560081, - 0.555197, - 0.550308, - 0.545414, - 0.540516, - 0.535614, - 0.530708, - 0.5258, - 0.520889, - 0.515976, - 0.511061, - 0.506145, - 0.501229, - 0.496313, - 0.491397, - 0.486481, - 0.481568, - 0.476655, - 0.471746, - 0.466839, - 0.461935, - 0.457034, - 0.452138, - 0.447247, - 0.44236, - 0.43748, - 0.432605, - 0.427737, - 0.422876, - 0.418022, - 0.413176, - 0.408338, - 0.40351, - 0.398691, - 0.393881, - 0.389082, - 0.384293, - 0.379516, - 0.374751, - 0.369997, - 0.365256, - 0.360528, - 0.355814, - 0.351113, - 0.346427, - 0.341756, - 0.3371, - 0.332459, - 0.327835, - 0.323228, - 0.318638, - 0.314065, - 0.30951, - 0.304974, - 0.300456, - 0.295958, - 0.29148, - 0.287021, - 0.282584, - 0.278167, - 0.273772, - 0.269398, - 0.265047, - 0.260719, - 0.256414, - 0.252132, - 0.247874, - 0.243641, - 0.239432, - 0.235249, - 0.231091, - 0.226959, - 0.222854, - 0.218775, - 0.214724, - 0.2107, - 0.206704, - 0.202737, - 0.198798, - 0.194888, - 0.191008, - 0.187158, - 0.183338, - 0.179549, - 0.17579, - 0.172063, - 0.168368, - 0.164705, - 0.161074, - 0.157476, - 0.153911, - 0.150379, - 0.146881, - 0.143418, - 0.139989, - 0.136594, - 0.133235, - 0.129912, - 0.126624, - 0.123372, - 0.120156, - 0.116978, - 0.113836, - 0.110732, - 0.107665, - 0.104636, - 0.101646, - 0.0986939, - 0.0957807, - 0.0929066, - 0.0900718, - 0.0872767, - 0.0845214, - 0.0818064, - 0.0791318, - 0.0764978, - 0.0739048, - 0.0713531, - 0.0688427, - 0.0663741, - 0.0639473, - 0.0615627, - 0.0592206, - 0.056921, - 0.0546643, - 0.0524506, - 0.0502802, - 0.0481533, - 0.04607, - 0.0440307, - 0.0420354, - 0.0400844, - 0.0381779, - 0.036316, - 0.034499, - 0.032727, - 0.0310001, - 0.0293186, - 0.0276826, - 0.0260923, - 0.0245478, - 0.0230492, - 0.0215968, - 0.0201906, - 0.0188308, - 0.0175175, - 0.0162509, - 0.0150311, - 0.0138581, - 0.0127322, - 0.0116533, - 0.0106217, - 0.00963736, - 0.00870045, - 0.00781104, - 0.00696922, - 0.00617507, - 0.00542867, - 0.00473008, - 0.00407937, - 0.00347661, - 0.00292186, - 0.00241517, - 0.00195659, - 0.00154616, - 0.00118392, - 0.00086991, - 0.000604158, - 0.000386689, - 0.000217525, - 9.66816e-05, - 2.4171e-05, - 0 -}; - -} // FreeDV diff --git a/libfreedv/interldpc.cpp b/libfreedv/interldpc.cpp deleted file mode 100644 index 0c613717c..000000000 --- a/libfreedv/interldpc.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: interldpc.c - AUTHOR......: David Rowe - DATE CREATED: April 2018 - - Helper functions for interleaved LDPC waveforms. - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2018 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 -#include -#include -#include - -#include "interldpc.h" -#include "codec2_ofdm.h" -#include "mpdecode_core.h" -#include "gp_interleaver.h" -#include "HRA_112_112.h" - -namespace FreeDV -{ - -/* CRC type function, used to compare QPSK vectors when debugging */ - -COMP test_acc(COMP v[], int n) { - COMP acc = {0.0f, 0.0f}; - int i; - - for (i = 0; i < n; i++) { - acc.real += roundf(v[i].real); - acc.imag += roundf(v[i].imag); - } - - return acc; -} - -void printf_n(COMP v[], int n) { - int i; - - for (i = 0; i < n; i++) { - fprintf(stderr, "%d %10f %10f\n", i, round(v[i].real), round(v[i].imag)); - } -} - -void set_up_hra_112_112(struct LDPC *ldpc, struct OFDM_CONFIG *config) { - ldpc->max_iter = HRA_112_112_MAX_ITER; - ldpc->dec_type = 0; - ldpc->q_scale_factor = 1; - ldpc->r_scale_factor = 1; - ldpc->CodeLength = HRA_112_112_CODELENGTH; - ldpc->NumberParityBits = HRA_112_112_NUMBERPARITYBITS; - ldpc->NumberRowsHcols = HRA_112_112_NUMBERROWSHCOLS; - ldpc->max_row_weight = HRA_112_112_MAX_ROW_WEIGHT; - ldpc->max_col_weight = HRA_112_112_MAX_COL_WEIGHT; - ldpc->H_rows = (uint16_t *) HRA_112_112_H_rows; - ldpc->H_cols = (uint16_t *) HRA_112_112_H_cols; - - /* provided for convenience and to match Octave vaiable names */ - - ldpc->data_bits_per_frame = HRA_112_112_CODELENGTH - HRA_112_112_NUMBERPARITYBITS; - ldpc->coded_bits_per_frame = HRA_112_112_CODELENGTH; - ldpc->coded_syms_per_frame = ldpc->coded_bits_per_frame / config->bps; -} - -void ldpc_encode_frame(struct LDPC *ldpc, int codeword[], unsigned char tx_bits_char[]) { - unsigned char *pbits = new unsigned char[ldpc->NumberParityBits]; - int i, j; - - encode(ldpc, tx_bits_char, pbits); - - for (i = 0; i < ldpc->data_bits_per_frame; i++) { - codeword[i] = tx_bits_char[i]; - } - - for (j = 0; i < ldpc->coded_bits_per_frame; i++, j++) { - codeword[i] = pbits[j]; - } - - delete[] pbits; -} - -void qpsk_modulate_frame(COMP tx_symbols[], int codeword[], int n) { - int s, i; - int dibit[2]; - std::complex qpsk_symb; - - for (s = 0, i = 0; i < n; s += 2, i++) { - dibit[0] = codeword[s + 1] & 0x1; - dibit[1] = codeword[s] & 0x1; - qpsk_symb = qpsk_mod(dibit); - tx_symbols[i].real = std::real(qpsk_symb); - tx_symbols[i].imag = std::imag(qpsk_symb); - } -} - -void interleaver_sync_state_machine(struct OFDM *ofdm, - struct LDPC *ldpc, - struct OFDM_CONFIG *config, - COMP codeword_symbols_de[], - float codeword_amps_de[], - float EsNo, int interleave_frames, - int *iter, int *parityCheckCount, int *Nerrs_coded) -{ - (void) config; - int coded_syms_per_frame = ldpc->coded_syms_per_frame; - int coded_bits_per_frame = ldpc->coded_bits_per_frame; - int data_bits_per_frame = ldpc->data_bits_per_frame; - float *llr = new float[coded_bits_per_frame]; - uint8_t *out_char = new uint8_t[coded_bits_per_frame]; - State next_sync_state_interleaver; - - next_sync_state_interleaver = ofdm->sync_state_interleaver; - - if ((ofdm->sync_state_interleaver == search) && (ofdm->frame_count >= (interleave_frames - 1))) { - symbols_to_llrs(llr, codeword_symbols_de, codeword_amps_de, EsNo, ofdm->mean_amp, coded_syms_per_frame); - iter[0] = run_ldpc_decoder(ldpc, out_char, llr, parityCheckCount); - Nerrs_coded[0] = data_bits_per_frame - parityCheckCount[0]; - - if ((Nerrs_coded[0] == 0) || (interleave_frames == 1)) { - /* sucessful decode! */ - next_sync_state_interleaver = synced; - ofdm->frame_count_interleaver = interleave_frames; - } - } - - ofdm->sync_state_interleaver = next_sync_state_interleaver; - delete[] out_char; - delete[] llr; -} - -/* measure uncoded (raw) bit errors over interleaver frame, note we - don't include txt bits as this is done after we dissassemmble the - frame */ - -int count_uncoded_errors(struct LDPC *ldpc, struct OFDM_CONFIG *config, int Nerrs_raw[], int interleave_frames, COMP codeword_symbols_de[]) { - int i, j, Nerrs, Terrs; - - int coded_syms_per_frame = ldpc->coded_syms_per_frame; - int coded_bits_per_frame = ldpc->coded_bits_per_frame; - int data_bits_per_frame = ldpc->data_bits_per_frame; - int *rx_bits_raw = new int[coded_bits_per_frame]; - - /* generate test codeword from known payload data bits */ - - int *test_codeword = new int[coded_bits_per_frame]; - uint16_t *r = new uint16_t[data_bits_per_frame]; - uint8_t *tx_bits = new uint8_t[data_bits_per_frame]; - - ofdm_rand(r, data_bits_per_frame); - - for (i = 0; i < data_bits_per_frame; i++) { - tx_bits[i] = r[i] > 16384; - } - - ldpc_encode_frame(ldpc, test_codeword, tx_bits); - - Terrs = 0; - for (j = 0; j < interleave_frames; j++) { - for (i = 0; i < coded_syms_per_frame; i++) { - int bits[2]; - std::complex s = std::complex{codeword_symbols_de[j * coded_syms_per_frame + i].real, codeword_symbols_de[j * coded_syms_per_frame + i].imag}; - qpsk_demod(s, bits); - rx_bits_raw[config->bps * i] = bits[1]; - rx_bits_raw[config->bps * i + 1] = bits[0]; - } - - Nerrs = 0; - - for (i = 0; i < coded_bits_per_frame; i++) { - if (test_codeword[i] != rx_bits_raw[i]) { - Nerrs++; - } - } - - Nerrs_raw[j] = Nerrs; - Terrs += Nerrs; - } - - delete[] tx_bits; - delete[] r; - delete[] test_codeword; - delete[] rx_bits_raw; - - return Terrs; -} - -int count_errors(uint8_t tx_bits[], uint8_t rx_bits[], int n) { - int i; - int Nerrs = 0; - - for (i = 0; i < n; i++) { - if (tx_bits[i] != rx_bits[i]) { - Nerrs++; - } - } - - return Nerrs; -} - -/* - Given an array of tx_bits, LDPC encodes, interleaves, and OFDM - modulates. - - Note this could be refactored to save memory, e.g. for embedded - applications we could call ofdm_txframe on a frame by frame - basis - */ - -void ofdm_ldpc_interleave_tx(struct OFDM *ofdm, struct LDPC *ldpc, std::complex tx_sams[], uint8_t tx_bits[], uint8_t txt_bits[], int interleave_frames, struct OFDM_CONFIG *config) { - int coded_syms_per_frame = ldpc->coded_syms_per_frame; - int coded_bits_per_frame = ldpc->coded_bits_per_frame; - int data_bits_per_frame = ldpc->data_bits_per_frame; - int ofdm_bitsperframe = ofdm_get_bits_per_frame(); - int *codeword = new int[coded_bits_per_frame]; - COMP *coded_symbols = new COMP[interleave_frames * coded_syms_per_frame]; - COMP *coded_symbols_inter = new COMP[interleave_frames * coded_syms_per_frame]; - int Nsamperframe = ofdm_get_samples_per_frame(); - std::complex *tx_symbols = new std::complex[ofdm_bitsperframe / config->bps]; - int j; - - for (j = 0; j < interleave_frames; j++) { - ldpc_encode_frame(ldpc, codeword, &tx_bits[j * data_bits_per_frame]); - qpsk_modulate_frame(&coded_symbols[j * coded_syms_per_frame], codeword, coded_syms_per_frame); - } - - gp_interleave_comp(coded_symbols_inter, coded_symbols, interleave_frames * coded_syms_per_frame); - - for (j = 0; j < interleave_frames; j++) { - ofdm_assemble_modem_frame_symbols(tx_symbols, &coded_symbols_inter[j * coded_syms_per_frame], &txt_bits[config->txtbits * j]); - ofdm_txframe(ofdm, &tx_sams[j * Nsamperframe], tx_symbols); - } - - delete[] tx_symbols; - delete[] coded_symbols_inter; - delete[] coded_symbols; - delete[] codeword; -} - -} // FreeDV diff --git a/libfreedv/interldpc.h b/libfreedv/interldpc.h deleted file mode 100644 index 76de9c567..000000000 --- a/libfreedv/interldpc.h +++ /dev/null @@ -1,59 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: interldpc.h - AUTHOR......: David Rowe - DATE CREATED: April 2018 - - Helper functions for interleaved LDPC modems. - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2018 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 . -*/ - -#ifndef __INTERLDPC__ -#define __INTERLDPC__ - -#include - -#include "codec2/comp.h" -#include "mpdecode_core.h" -#include "ofdm_internal.h" - -namespace FreeDV -{ - -/* CRC type function, used to compare QPSK vectors when debugging */ - -COMP test_acc(COMP v[], int n); -void printf_n(COMP v[], int n); -void set_up_hra_112_112(struct LDPC *ldpc, struct OFDM_CONFIG *); -void ldpc_encode_frame(struct LDPC *ldpc, int codeword[], unsigned char tx_bits_char[]); -void qpsk_modulate_frame(COMP tx_symbols[], int codeword[], int n); -void interleaver_sync_state_machine(struct OFDM *ofdm, struct LDPC *ldpc, struct OFDM_CONFIG *config, - COMP codeword_symbols_de[], - float codeword_amps_de[], - float EsNo, int interleave_frames, - int *inter, int *parityCheckCount, int *Nerrs_coded); -int count_uncoded_errors(struct LDPC *ldpc, struct OFDM_CONFIG *config, int Nerrs_raw[], int interleave_frames, COMP codeword_symbols_de[]); -int count_errors(uint8_t tx_bits[], uint8_t rx_bits[], int n); -void ofdm_ldpc_interleave_tx(struct OFDM *ofdm, struct LDPC *ldpc, std::complex tx_sams[], uint8_t tx_bits[], uint8_t txt_bits[], int interleave_frames, struct OFDM_CONFIG *config); -void build_modulated_uw(struct OFDM *ofdm, std::complex tx_symbols[], uint8_t txt_bits[], struct OFDM_CONFIG *config); - -} // FreeDV - -#endif diff --git a/libfreedv/kiss_fft.cpp b/libfreedv/kiss_fft.cpp deleted file mode 100644 index 271693f33..000000000 --- a/libfreedv/kiss_fft.cpp +++ /dev/null @@ -1,416 +0,0 @@ -/* -Copyright (c) 2003-2010, Mark Borgerding - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * 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. - * Neither the author nor the names of any 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 OWNER 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. -*/ - -// fix gcc >= 4.6 -// see https://gcc.gnu.org/gcc-4.6/porting_to.html -#include - -#include "_kiss_fft_guts.h" -/* The guts header contains all the multiplication and addition macros that are defined for - fixed or floating point complex numbers. It also delares the kf_ internal functions. - */ - -namespace FreeDV -{ - -static void kf_bfly2( - kiss_fft_cpx * Fout, - const std::size_t fstride, - const kiss_fft_cfg st, - int m - ) -{ - kiss_fft_cpx * Fout2; - kiss_fft_cpx * tw1 = st->twiddles; - kiss_fft_cpx t; - Fout2 = Fout + m; - do{ - C_FIXDIV(*Fout,2); C_FIXDIV(*Fout2,2); - - C_MUL (t, *Fout2 , *tw1); - tw1 += fstride; - C_SUB( *Fout2 , *Fout , t ); - C_ADDTO( *Fout , t ); - ++Fout2; - ++Fout; - }while (--m); -} - -static void kf_bfly4( - kiss_fft_cpx * Fout, - const std::size_t fstride, - const kiss_fft_cfg st, - const std::size_t m - ) -{ - kiss_fft_cpx *tw1,*tw2,*tw3; - kiss_fft_cpx scratch[6]; - std::size_t k=m; - const std::size_t m2=2*m; - const std::size_t m3=3*m; - - - tw3 = tw2 = tw1 = st->twiddles; - - do { - C_FIXDIV(*Fout,4); C_FIXDIV(Fout[m],4); C_FIXDIV(Fout[m2],4); C_FIXDIV(Fout[m3],4); - - C_MUL(scratch[0],Fout[m] , *tw1 ); - C_MUL(scratch[1],Fout[m2] , *tw2 ); - C_MUL(scratch[2],Fout[m3] , *tw3 ); - - C_SUB( scratch[5] , *Fout, scratch[1] ); - C_ADDTO(*Fout, scratch[1]); - C_ADD( scratch[3] , scratch[0] , scratch[2] ); - C_SUB( scratch[4] , scratch[0] , scratch[2] ); - C_SUB( Fout[m2], *Fout, scratch[3] ); - tw1 += fstride; - tw2 += fstride*2; - tw3 += fstride*3; - C_ADDTO( *Fout , scratch[3] ); - - if(st->inverse) { - Fout[m].r = scratch[5].r - scratch[4].i; - Fout[m].i = scratch[5].i + scratch[4].r; - Fout[m3].r = scratch[5].r + scratch[4].i; - Fout[m3].i = scratch[5].i - scratch[4].r; - }else{ - Fout[m].r = scratch[5].r + scratch[4].i; - Fout[m].i = scratch[5].i - scratch[4].r; - Fout[m3].r = scratch[5].r - scratch[4].i; - Fout[m3].i = scratch[5].i + scratch[4].r; - } - ++Fout; - }while(--k); -} - -static void kf_bfly3( - kiss_fft_cpx * Fout, - const std::size_t fstride, - const kiss_fft_cfg st, - std::size_t m - ) -{ - std::size_t k=m; - const std::size_t m2 = 2*m; - kiss_fft_cpx *tw1,*tw2; - kiss_fft_cpx scratch[5]; - kiss_fft_cpx epi3; - epi3 = st->twiddles[fstride*m]; - - tw1=tw2=st->twiddles; - - do{ - C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3); - - C_MUL(scratch[1],Fout[m] , *tw1); - C_MUL(scratch[2],Fout[m2] , *tw2); - - C_ADD(scratch[3],scratch[1],scratch[2]); - C_SUB(scratch[0],scratch[1],scratch[2]); - tw1 += fstride; - tw2 += fstride*2; - - Fout[m].r = Fout->r - HALF_OF(scratch[3].r); - Fout[m].i = Fout->i - HALF_OF(scratch[3].i); - - C_MULBYSCALAR( scratch[0] , epi3.i ); - - C_ADDTO(*Fout,scratch[3]); - - Fout[m2].r = Fout[m].r + scratch[0].i; - Fout[m2].i = Fout[m].i - scratch[0].r; - - Fout[m].r -= scratch[0].i; - Fout[m].i += scratch[0].r; - - ++Fout; - }while(--k); -} - -static void kf_bfly5( - kiss_fft_cpx * Fout, - const std::size_t fstride, - const kiss_fft_cfg st, - int m - ) -{ - kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; - int u; - kiss_fft_cpx scratch[13]; - kiss_fft_cpx * twiddles = st->twiddles; - kiss_fft_cpx *tw; - kiss_fft_cpx ya,yb; - ya = twiddles[fstride*m]; - yb = twiddles[fstride*2*m]; - - Fout0=Fout; - Fout1=Fout0+m; - Fout2=Fout0+2*m; - Fout3=Fout0+3*m; - Fout4=Fout0+4*m; - - tw=st->twiddles; - for ( u=0; ur += scratch[7].r + scratch[8].r; - Fout0->i += scratch[7].i + scratch[8].i; - - scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r); - scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r); - - scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i); - scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i); - - C_SUB(*Fout1,scratch[5],scratch[6]); - C_ADD(*Fout4,scratch[5],scratch[6]); - - scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r); - scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r); - scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i); - scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i); - - C_ADD(*Fout2,scratch[11],scratch[12]); - C_SUB(*Fout3,scratch[11],scratch[12]); - - ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; - } -} - -/* perform the butterfly for one stage of a mixed radix FFT */ -static void kf_bfly_generic( - kiss_fft_cpx * Fout, - const std::size_t fstride, - const kiss_fft_cfg st, - int m, - int p - ) -{ - int u,k,q1,q; - kiss_fft_cpx * twiddles = st->twiddles; - kiss_fft_cpx t; - int Norig = st->nfft; - - kiss_fft_cpx * scratch = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC(sizeof(kiss_fft_cpx)*p); - - for ( u=0; u=Norig) twidx-=Norig; - C_MUL(t,scratch[q] , twiddles[twidx] ); - C_ADDTO( Fout[ k ] ,t); - } - k += m; - } - } - KISS_FFT_TMP_FREE(scratch); -} - -static -void kf_work( - kiss_fft_cpx * Fout, - const kiss_fft_cpx * f, - const std::size_t fstride, - int in_stride, - int * factors, - const kiss_fft_cfg st - ) -{ - kiss_fft_cpx * Fout_beg=Fout; - const int p=*factors++; /* the radix */ - const int m=*factors++; /* stage's fft length/p */ - const kiss_fft_cpx * Fout_end = Fout + p*m; - -#ifdef _OPENMP - // use openmp extensions at the - // top-level (not recursive) - if (fstride==1 && p<=5) - { - int k; - - // execute the p different work units in different threads -# pragma omp parallel for - for (k=0;k floor_sqrt) - p = n; /* no more factors, skip to end */ - } - n /= p; - *facbuf++ = p; - *facbuf++ = n; - } while (n > 1); -} - -/* - * - * User-callable function to allocate all necessary storage space for the fft. - * - * The return value is a contiguous block of memory, allocated with malloc. As such, - * It can be freed with free(), rather than a kiss_fft-specific function. - * */ -kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem, std::size_t * lenmem ) -{ - kiss_fft_cfg st=NULL; - std::size_t memneeded = sizeof(struct kiss_fft_state) - + sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/ - - if ( lenmem==NULL ) { - st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded ); - }else{ - if (mem != NULL && *lenmem >= memneeded) - st = (kiss_fft_cfg)mem; - *lenmem = memneeded; - } - if (st) { - int i; - st->nfft=nfft; - st->inverse = inverse_fft; - - for (i=0;iinverse) - phase *= -1; - kf_cexp(st->twiddles+i, phase ); - } - - kf_factor(nfft,st->factors); - } - return st; -} - - -void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride) -{ - if (fin == fout) { - //NOTE: this is not really an in-place FFT algorithm. - //It just performs an out-of-place FFT into a temp buffer - kiss_fft_cpx * tmpbuf = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC( sizeof(kiss_fft_cpx)*st->nfft); - kf_work(tmpbuf,fin,1,in_stride, st->factors,st); - memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft); - KISS_FFT_TMP_FREE(tmpbuf); - }else{ - kf_work( fout, fin, 1,in_stride, st->factors,st ); - } -} - -void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) -{ - kiss_fft_stride(cfg,fin,fout,1); -} - - -void kiss_fft_cleanup(void) -{ - // nothing needed any more -} - -int kiss_fft_next_fast_size(int n) -{ - while(1) { - int m=n; - while ( (m%2) == 0 ) m/=2; - while ( (m%3) == 0 ) m/=3; - while ( (m%5) == 0 ) m/=5; - if (m<=1) - break; /* n is completely factorable by twos, threes, and fives */ - n++; - } - return n; -} - -} // FreeDV diff --git a/libfreedv/kiss_fft.h b/libfreedv/kiss_fft.h deleted file mode 100644 index 66beae128..000000000 --- a/libfreedv/kiss_fft.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef FREEDV_KISS_FFT_H -#define FREEDV_KISS_FFT_H - -#include -#include -#include -#include - - -/* - ATTENTION! - If you would like a : - -- a utility that will handle the caching of fft objects - -- real-only (no imaginary time component ) FFT - -- a multi-dimensional FFT - -- a command-line utility to perform ffts - -- a command-line utility to perform fast-convolution filtering - - Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c - in the tools/ directory. -*/ - -namespace FreeDV -{ - -#ifdef USE_SIMD -# include -# define kiss_fft_scalar __m128 -#define KISS_FFT_MALLOC(nbytes) _mm_malloc(nbytes,16) -#define KISS_FFT_FREE _mm_free -#else -#define KISS_FFT_MALLOC malloc -#define KISS_FFT_FREE free -#endif - - -#ifdef FIXED_POINT -#include -# if (FIXED_POINT == 32) -# define kiss_fft_scalar int32_t -# else -# define kiss_fft_scalar int16_t -# endif -#else -# ifndef kiss_fft_scalar -/* default is float */ -# define kiss_fft_scalar float -# endif -#endif - - -typedef struct { - kiss_fft_scalar r; - kiss_fft_scalar i; -}kiss_fft_cpx; - -typedef struct kiss_fft_state* kiss_fft_cfg; - -/* - * kiss_fft_alloc - * - * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. - * - * typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL); - * - * The return value from fft_alloc is a cfg buffer used internally - * by the fft routine or NULL. - * - * If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc. - * The returned value should be free()d when done to avoid memory leaks. - * - * The state can be placed in a user supplied buffer 'mem': - * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, - * then the function places the cfg in mem and the size used in *lenmem - * and returns mem. - * - * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), - * then the function returns NULL and places the minimum cfg - * buffer size in *lenmem. - * */ - -kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem); - -/* - * kiss_fft(cfg,in_out_buf) - * - * Perform an FFT on a complex input buffer. - * for a forward FFT, - * fin should be f[0] , f[1] , ... ,f[nfft-1] - * fout will be F[0] , F[1] , ... ,F[nfft-1] - * Note that each element is complex and can be accessed like - f[k].r and f[k].i - * */ -void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); - -/* - A more generic version of the above function. It reads its input from every Nth sample. - * */ -void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride); - -/* If kiss_fft_alloc allocated a buffer, it is one contiguous - buffer and can be simply free()d when no longer needed*/ -#define kiss_fft_free free - -/* - Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up - your compiler output to call this before you exit. -*/ -void kiss_fft_cleanup(void); - - -/* - * Returns the smallest integer k, such that k>=n and k has only "fast" factors (2,3,5) - */ -int kiss_fft_next_fast_size(int n); - -/* for real ffts, we need an even size */ -#define kiss_fftr_next_fast_size_real(n) \ - (kiss_fft_next_fast_size( ((n)+1)>>1)<<1) - -} // FreeDV - -#endif // FREEDV_KISS_FFT_H diff --git a/libfreedv/kiss_fftr.cpp b/libfreedv/kiss_fftr.cpp deleted file mode 100644 index 0dff20634..000000000 --- a/libfreedv/kiss_fftr.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* -Copyright (c) 2003-2004, Mark Borgerding - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * 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. - * Neither the author nor the names of any 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 OWNER 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. -*/ - -// fix gcc >= 4.6 -// see https://gcc.gnu.org/gcc-4.6/porting_to.html -#include - -#include "kiss_fftr.h" -#include "_kiss_fft_guts.h" -#include "assert.h" - -namespace FreeDV -{ - -struct kiss_fftr_state{ - kiss_fft_cfg substate; - kiss_fft_cpx * tmpbuf; - kiss_fft_cpx * super_twiddles; -#ifdef USE_SIMD - void * pad; -#endif -}; - -kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, std::size_t * lenmem) -{ - int i; - kiss_fftr_cfg st = NULL; - std::size_t subsize, memneeded; - - if (nfft & 1) { - fprintf(stderr,"Real FFT optimization must be even.\n"); - return NULL; - } - nfft >>= 1; - - kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize); - memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 3 / 2); - - if (lenmem == NULL) { - st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded); - } else { - if (*lenmem >= memneeded) - st = (kiss_fftr_cfg) mem; - *lenmem = memneeded; - } - if (!st) - return NULL; - - st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */ - st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize); - st->super_twiddles = st->tmpbuf + nfft; - kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize); - - for (i = 0; i < nfft/2; ++i) { - float phase = - -3.14159265358979323846264338327 * ((float) (i+1) / nfft + .5); - if (inverse_fft) - phase *= -1; - kf_cexp (st->super_twiddles+i,phase); - } - return st; -} - -void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata) -{ - /* input buffer timedata is stored row-wise */ - int k,ncfft; - kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc; - - assert(st->substate->inverse==0); - - ncfft = st->substate->nfft; - - /*perform the parallel fft of two real signals packed in real,imag*/ - kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf ); - /* The real part of the DC element of the frequency spectrum in st->tmpbuf - * contains the sum of the even-numbered elements of the input time sequence - * The imag part is the sum of the odd-numbered elements - * - * The sum of tdc.r and tdc.i is the sum of the input time sequence. - * yielding DC of input time sequence - * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... - * yielding Nyquist bin of input time sequence - */ - - tdc.r = st->tmpbuf[0].r; - tdc.i = st->tmpbuf[0].i; - C_FIXDIV(tdc,2); - CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i); - CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i); - freqdata[0].r = tdc.r + tdc.i; - freqdata[ncfft].r = tdc.r - tdc.i; -#ifdef USE_SIMD - freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0); -#else - freqdata[ncfft].i = freqdata[0].i = 0; -#endif - - for ( k=1;k <= ncfft/2 ; ++k ) { - fpk = st->tmpbuf[k]; - fpnk.r = st->tmpbuf[ncfft-k].r; - fpnk.i = - st->tmpbuf[ncfft-k].i; - C_FIXDIV(fpk,2); - C_FIXDIV(fpnk,2); - - C_ADD( f1k, fpk , fpnk ); - C_SUB( f2k, fpk , fpnk ); - C_MUL( tw , f2k , st->super_twiddles[k-1]); - - freqdata[k].r = HALF_OF(f1k.r + tw.r); - freqdata[k].i = HALF_OF(f1k.i + tw.i); - freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r); - freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i); - } -} - -void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata) -{ - /* input buffer timedata is stored row-wise */ - int k, ncfft; - - assert(st->substate->inverse == 1); - - ncfft = st->substate->nfft; - - st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r; - st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r; - C_FIXDIV(st->tmpbuf[0],2); - - for (k = 1; k <= ncfft / 2; ++k) { - kiss_fft_cpx fk, fnkc, fek, fok, tmp; - fk = freqdata[k]; - fnkc.r = freqdata[ncfft - k].r; - fnkc.i = -freqdata[ncfft - k].i; - C_FIXDIV( fk , 2 ); - C_FIXDIV( fnkc , 2 ); - - C_ADD (fek, fk, fnkc); - C_SUB (tmp, fk, fnkc); - C_MUL (fok, tmp, st->super_twiddles[k-1]); - C_ADD (st->tmpbuf[k], fek, fok); - C_SUB (st->tmpbuf[ncfft - k], fek, fok); -#ifdef USE_SIMD - st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0); -#else - st->tmpbuf[ncfft - k].i *= -1; -#endif - } - kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); -} - -} // FreeDV diff --git a/libfreedv/kiss_fftr.h b/libfreedv/kiss_fftr.h deleted file mode 100644 index 0816802e2..000000000 --- a/libfreedv/kiss_fftr.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef KISS_FTR_H -#define KISS_FTR_H - -#include "kiss_fft.h" - -namespace FreeDV -{ - -/* - - Real optimized version can save about 45% cpu time vs. complex fft of a real seq. - - - - */ - -typedef struct kiss_fftr_state *kiss_fftr_cfg; - - -kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem); -/* - nfft must be even - - If you don't care to allocate space, use mem = lenmem = NULL -*/ - - -void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata); -/* - input timedata has nfft scalar points - output freqdata has nfft/2+1 complex points -*/ - -void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata); -/* - input freqdata has nfft/2+1 complex points - output timedata has nfft scalar points -*/ - -} // FreeDV - -//#define kiss_fftr_free free - -#endif diff --git a/libfreedv/libfreedv.h b/libfreedv/libfreedv.h deleted file mode 100644 index 3a41f08fe..000000000 --- a/libfreedv/libfreedv.h +++ /dev/null @@ -1,187 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2019 Edouard Griffiths, F4EXB // -// // -// freedv_api.h replacement // -// // -// This program is free software; you can redistribute it and/or modify // -// it under the terms of the GNU General Public License as published by // -// the Free Software Foundation as version 3 of the License, or // -// (at your option) any later version. // -// // -// 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 V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - - -/*---------------------------------------------------------------------------*\ - - FILE........: freedv_api.h - AUTHOR......: David Rowe - DATE CREATED: August 2014 - - Library of API functions that implement FreeDV "modes", useful for - embedding FreeDV in other programs. Please see the documentation - for each function in freedv_api.c, and the sample freedv_tx.c and - freedv_rx.c programs. - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2014 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 . -*/ - -#ifndef LIBFREEDV_LIBFREEDV_H_ -#define LIBFREEDV_LIBFREEDV_H_ - -// This declares a single-precision (float) complex number -#include -#include - -#include "codec2/comp.h" -#include "codec2_ofdm.h" - -#define FREEDV_MODE_1600 0 -#define FREEDV_MODE_700 1 -#define FREEDV_MODE_700B 2 -#define FREEDV_MODE_2400A 3 -#define FREEDV_MODE_2400B 4 -#define FREEDV_MODE_800XA 5 -#define FREEDV_MODE_700C 6 -#define FREEDV_MODE_700D 7 - -/* operator control of 700D state machine */ - -#define FREEDV_SYNC_UNSYNC 0 /* force sync state machine to lose sync, and search for new sync */ -#define FREEDV_SYNC_AUTO 1 /* falls out of sync automatically */ -#define FREEDV_SYNC_MANUAL 2 /* fall out of sync only under operator control */ - - -namespace FreeDV -{ - -struct freedv; - -/* advanced freedv open options rqd by some modes */ - -struct freedv_advanced { - int interleave_frames; -}; - -/* Called when text message char is decoded */ -typedef void (*freedv_callback_rx)(void *, char); -/* Called when new text message char is needed */ -typedef char (*freedv_callback_tx)(void *); -typedef void (*freedv_calback_error_pattern) - (void *error_pattern_callback_state, short error_pattern[], int sz_error_pattern); - -/* Protocol bits are packed MSB-first */ -/* Called when a frame containing protocol data is decoded */ -typedef void (*freedv_callback_protorx)(void *, char *); -/* Called when a frame containing protocol data is to be sent */ -typedef void (*freedv_callback_prototx)(void *, char *); - -/* Data packet callbacks */ -/* Called when a packet has been received */ -typedef void (*freedv_callback_datarx)(void *, unsigned char *packet, std::size_t size); -/* Called when a new packet can be send */ -typedef void (*freedv_callback_datatx)(void *, unsigned char *packet, std::size_t *size); - - -/*---------------------------------------------------------------------------*\ - - FreeDV API functions - -\*---------------------------------------------------------------------------*/ - -// open, close ---------------------------------------------------------------- - -struct freedv *freedv_open(int mode); -struct freedv *freedv_open_advanced(int mode, struct freedv_advanced *adv); -void freedv_close (struct freedv *freedv); - -// Transmit ------------------------------------------------------------------- - -void freedv_tx (struct freedv *freedv, short mod_out[], short speech_in[]); -void freedv_comptx (struct freedv *freedv, COMP mod_out[], short speech_in[]); -void freedv_codectx (struct freedv *f, short mod_out[], unsigned char *packed_codec_bits); -void freedv_datatx (struct freedv *f, short mod_out[]); -int freedv_data_ntxframes (struct freedv *freedv); - -// Receive ------------------------------------------------------------------- - -int freedv_nin (struct freedv *freedv); -int freedv_rx (struct freedv *freedv, short speech_out[], short demod_in[]); -int freedv_shortrx (struct freedv *freedv, short speech_out[], short demod_in[], float gain); -int freedv_floatrx (struct freedv *freedv, short speech_out[], float demod_in[]); -int freedv_comprx (struct freedv *freedv, short speech_out[], COMP demod_in[]); -int freedv_codecrx (struct freedv *freedv, unsigned char *packed_codec_bits, short demod_in[]); - -// Set parameters ------------------------------------------------------------ - -void freedv_set_callback_txt (struct freedv *freedv, freedv_callback_rx rx, freedv_callback_tx tx, void *callback_state); -void freedv_set_callback_protocol (struct freedv *freedv, freedv_callback_protorx rx, freedv_callback_prototx tx, void *callback_state); -void freedv_set_callback_data (struct freedv *freedv, freedv_callback_datarx datarx, freedv_callback_datatx datatx, void *callback_state); -void freedv_set_test_frames (struct freedv *freedv, int test_frames); -void freedv_set_test_frames_diversity (struct freedv *freedv, int test_frames_diversity); -void freedv_set_smooth_symbols (struct freedv *freedv, int smooth_symbols); -void freedv_set_squelch_en (struct freedv *freedv, int squelch_en); -void freedv_set_snr_squelch_thresh (struct freedv *freedv, float snr_squelch_thresh); -void freedv_set_clip (struct freedv *freedv, int val); -void freedv_set_total_bit_errors (struct freedv *freedv, int val); -void freedv_set_total_bits (struct freedv *freedv, int val); -void freedv_set_callback_error_pattern (struct freedv *freedv, freedv_calback_error_pattern cb, void *state); -void freedv_set_varicode_code_num (struct freedv *freedv, int val); -void freedv_set_data_header (struct freedv *freedv, unsigned char *header); -int freedv_set_alt_modem_samp_rate (struct freedv *freedv, int samp_rate); -void freedv_set_carrier_ampl (struct freedv *freedv, int c, float ampl); -void freedv_set_sync (struct freedv *freedv, Sync sync_cmd); -void freedv_set_verbose (struct freedv *freedv, int verbosity); -void freedv_set_tx_bpf (struct freedv *freedv, int val); -void freedv_set_ext_vco (struct freedv *f, int val); - -// Get parameters ------------------------------------------------------------------------- - -struct MODEM_STATS; -int freedv_get_version(void); -int freedv_get_mode (struct freedv *freedv); -void freedv_get_modem_stats (struct freedv *freedv, int *sync, float *snr_est); -void freedv_get_modem_extended_stats(struct freedv *freedv, struct MODEM_STATS *stats); -int freedv_get_test_frames (struct freedv *freedv); -int freedv_get_n_speech_samples (struct freedv *freedv); -int freedv_get_modem_sample_rate (struct freedv *freedv); -int freedv_get_modem_symbol_rate (struct freedv *freedv); -int freedv_get_n_max_modem_samples (struct freedv *freedv); -int freedv_get_n_nom_modem_samples (struct freedv *freedv); -int freedv_get_total_bits (struct freedv *freedv); -int freedv_get_total_bit_errors (struct freedv *freedv); -int freedv_get_total_bits_coded (struct freedv *freedv); -int freedv_get_total_bit_errors_coded(struct freedv *freedv); -int freedv_get_sync (struct freedv *freedv); -int freedv_get_sync_interleaver (struct freedv *freedv); -struct FSK * freedv_get_fsk (struct freedv *f); -struct CODEC2 *freedv_get_codec2 (struct freedv *freedv); -int freedv_get_n_codec_bits (struct freedv *freedv); -int freedv_get_sz_error_pattern (struct freedv *freedv); -int freedv_get_protocol_bits (struct freedv *freedv); - -} // namespace FreeDV - -#endif /* LIBFREEDV_LIBFREEDV_H_ */ diff --git a/libfreedv/linreg.cpp b/libfreedv/linreg.cpp deleted file mode 100644 index c4fe96f66..000000000 --- a/libfreedv/linreg.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: linreg.c - AUTHOR......: David Rowe - DATE CREATED: April 2015 - - Linear regression C module based on: - - http://stackoverflow.com/questions/5083465/fast-efficient-least-squares-fit-algorithm-in-c - - Use: - - $ gcc linreg.c -o linreg -D__UNITTEST__ -Wall - $ ./linreg - - Then compare yfit results with octave/tlinreg.m - -\*---------------------------------------------------------------------------*/ - -/* - 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 - -#include "linreg.h" -#include "comp_prim.h" - -namespace FreeDV -{ - -void linreg(COMP *m, COMP *b, float x[], COMP y[], int n) -{ - float sumx = 0.0; /* sum of x */ - float sumx2 = 0.0; /* sum of x^2 */ - COMP sumxy = {0.0,0.0}; /* sum of x * y */ - COMP sumy = {0.0,0.0}; /* sum of y */ - COMP sumy2 = {0.0,0.0}; /* sum of y**2 */ - float denom; - COMP zero; - int i; - - for (i=0; i. -*/ - -#ifndef __LINREG__ -#define __LINREG__ - -#include "codec2/comp.h" - -namespace FreeDV -{ - -void linreg(COMP *m, COMP *b, float x[], COMP y[], int n); - -} // FreeDV - -#endif diff --git a/libfreedv/machdep.h b/libfreedv/machdep.h deleted file mode 100644 index 496468368..000000000 --- a/libfreedv/machdep.h +++ /dev/null @@ -1,57 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: machdep.h - AUTHOR......: David Rowe - DATE CREATED: May 2 2013 - - Machine dependant functions, e.g. profiling that requires access to a clock - counter register. - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2013 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 . -*/ - -#ifndef __MACHDEP__ -#define __MACHDEP__ - -namespace FreeDV -{ - -#ifdef PROFILE -#define PROFILE_VAR(...) unsigned int __VA_ARGS__ -#define PROFILE_SAMPLE(timestamp) timestamp = machdep_profile_sample() -#define PROFILE_SAMPLE_AND_LOG(timestamp, prev_timestamp, label) \ - timestamp = machdep_profile_sample_and_log(prev_timestamp, label) -#define PROFILE_SAMPLE_AND_LOG2(prev_timestamp, label) \ - machdep_profile_sample_and_log(prev_timestamp, label) -#else -#define PROFILE_VAR(...) -#define PROFILE_SAMPLE(timestamp) -#define PROFILE_SAMPLE_AND_LOG(timestamp, prev_timestamp, label) -#define PROFILE_SAMPLE_AND_LOG2(prev_timestamp, label) -#endif - -void machdep_profile_init(void); -void machdep_profile_reset(void); -unsigned int machdep_profile_sample(void); -unsigned int machdep_profile_sample_and_log(unsigned int start, char s[]); -void machdep_profile_print_logged_samples(void); - -} // FreeDV - -#endif diff --git a/libfreedv/modem_probe.h b/libfreedv/modem_probe.h deleted file mode 100644 index 826051ccc..000000000 --- a/libfreedv/modem_probe.h +++ /dev/null @@ -1,153 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: modem_probe.h - AUTHOR......: Brady O'Brien - DATE CREATED: 9 January 2016 - - Library to easily extract debug traces from modems during development - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2016 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 . -*/ - -#ifndef __MODEMPROBE_H -#define __MODEMPROBE_H -#include -#include -#include -#include "codec2/comp.h" - -namespace FreeDV -{ - -#ifdef MODEMPROBE_ENABLE - -/* Internal functions */ -void modem_probe_init_int(char *modname, char *runname); -void modem_probe_close_int(); - -void modem_probe_samp_i_int(char * tracename,int samp[],size_t cnt); -void modem_probe_samp_f_int(char * tracename,float samp[],size_t cnt); -void modem_probe_samp_c_int(char * tracename,COMP samp[],size_t cnt); - -/* - * Init the probe library. - * char *modname - Name of the modem under test - * char *runname - Name/path of the file data is dumped to - */ -static inline void modem_probe_init(char *modname,char *runname){ - modem_probe_init_int(modname,runname); -} - -/* - * Dump traces to a file and clean up - */ -static inline void modem_probe_close(){ - modem_probe_close_int(); -} - -/* - * Save some number of int samples to a named trace - * char *tracename - name of trace being saved to - * int samp[] - int samples - * size_t cnt - how many samples to save - */ -static inline void modem_probe_samp_i(char *tracename,int samp[],size_t cnt){ - modem_probe_samp_i_int(tracename,samp,cnt); -} - -/* - * Save some number of float samples to a named trace - * char *tracename - name of trace being saved to - * float samp[] - int samples - * size_t cnt - how many samples to save - */ -static inline void modem_probe_samp_f(char *tracename,float samp[],size_t cnt){ - modem_probe_samp_f_int(tracename,samp,cnt); -} - -/* - * Save some number of complex samples to a named trace - * char *tracename - name of trace being saved to - * COMP samp[] - int samples - * size_t cnt - how many samples to save - */ -static inline void modem_probe_samp_c(char *tracename,COMP samp[],size_t cnt){ - modem_probe_samp_c_int(tracename,samp,cnt); -} - -/* - * Save some number of complex samples to a named trace - * char *tracename - name of trace being saved to - * float complex samp[] - int samples - * size_t cnt - how many samples to save - */ -static inline void modem_probe_samp_cft(char *tracename,complex float samp[],size_t cnt){ - modem_probe_samp_c_int(tracename,(COMP*)samp,cnt); -} - -#else - -static inline void modem_probe_init(const char *modname, char *runname) -{ - (void) modname; - (void) runname; - return; -} - -static inline void modem_probe_close() { - return; -} - -static inline void modem_probe_samp_i(const char *name, int samp[], std::size_t sampcnt) -{ - (void) name; - (void) samp; - (void) sampcnt; - return; -} - -static inline void modem_probe_samp_f(const char *name, float samp[], std::size_t cnt) -{ - (void) name; - (void) samp; - (void) cnt; - return; -} - -static inline void modem_probe_samp_c(const char *name, COMP samp[], std::size_t cnt) -{ - (void) name; - (void) samp; - (void) cnt; - return; -} - -static inline void modem_probe_samp_cft(const char *name, std::complex samp[], std::size_t cnt) -{ - (void) name; - (void) samp; - (void) cnt; - return; -} - -#endif - -} // FreeDV - -#endif diff --git a/libfreedv/modem_stats.h b/libfreedv/modem_stats.h deleted file mode 100644 index 2fb5afd60..000000000 --- a/libfreedv/modem_stats.h +++ /dev/null @@ -1,79 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: modem_stats.h - AUTHOR......: David Rowe - DATE CREATED: June 2015 - - Common structure 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 . -*/ - -#ifndef __FREEDV_MODEM_STATS__ -#define __FREEDV_MODEM_STATS__ - -#include "codec2/comp.h" -#include "kiss_fft.h" - -#define MODEM_STATS_NC_MAX 20 -#define MODEM_STATS_NR_MAX 8 -#define MODEM_STATS_ET_MAX 8 -#define MODEM_STATS_EYE_IND_MAX 160 -#define MODEM_STATS_NSPEC 512 -#define MODEM_STATS_MAX_F_HZ 4000 -#define MODEM_STATS_MAX_F_EST 4 - -namespace FreeDV -{ - -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 */ - float sync_metric; /* number between 0 and 1 indicating quality of sync */ - - /* eye diagram traces */ - /* Eye diagram plot -- first dim is trace number, second is the trace idx */ - float rx_eye[MODEM_STATS_ET_MAX][MODEM_STATS_EYE_IND_MAX]; - int neyetr; /* How many eye traces are plotted */ - int neyesamp; /* How many samples in the eye diagram */ - - /* optional for FSK modems - est tone freqs */ - - float f_est[MODEM_STATS_MAX_F_EST]; - - /* 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); - -} // FreeDV - -#endif diff --git a/libfreedv/mpdecode_core.cpp b/libfreedv/mpdecode_core.cpp deleted file mode 100644 index da8c0badc..000000000 --- a/libfreedv/mpdecode_core.cpp +++ /dev/null @@ -1,726 +0,0 @@ -/* - FILE...: mpdecode_core.c - AUTHOR.: Matthew C. Valenti, Rohit Iyer Seshadri, David Rowe - CREATED: Sep 2016 - - C-callable core functions moved from MpDecode.c, so they can be used for - Octave and C programs. -*/ - -#include -#include -#include -#include -#include -#include "mpdecode_core.h" -#ifndef USE_ORIGINAL_PHI0 -#include "phi0.h" -#endif - -#ifdef __EMBEDDED__ -#include "machdep.h" -#endif - -#define QPSK_CONSTELLATION_SIZE 4 -#define QPSK_BITS_PER_SYMBOL 2 - -namespace FreeDV -{ - -/* QPSK constellation for symbol likelihood calculations */ - -static COMP S_matrix[] = { - { 1.0f, 0.0f}, - { 0.0f, 1.0f}, - { 0.0f, -1.0f}, - {-1.0f, 0.0f} -}; - -// c_nodes will be an array of NumberParityBits of struct c_node -// Each c_node contains an array of c_sub_node elements -// This structure reduces the indexing caluclations in SumProduct() - -struct c_sub_node { // Order is important here to keep total size small. - uint16_t index; // Values from H_rows (except last 2 entries) - uint16_t socket; // The socket number at the v_node - float message; // modified during operation! -}; - -struct c_node { - int degree; // A count of elements in the following arrays - struct c_sub_node *subs; -}; - -// v_nodes will be an array of CodeLength of struct v_node - -struct v_sub_node { - uint16_t index; // the index of a c_node it is connected to - // Filled with values from H_cols (except last 2 entries) - uint16_t socket; // socket number at the c_node - float message; // Loaded with input data - // modified during operation! - uint8_t sign; // 1 if input is negative - // modified during operation! -}; - -struct v_node { - int degree; // A count of ??? - float initial_value; - struct v_sub_node *subs; -}; - -void encode(struct LDPC *ldpc, unsigned char ibits[], unsigned char pbits[]) { - unsigned int tmp, par, prev=0; - int i, p, ind; - uint16_t *H_rows = ldpc->H_rows; - - for (p=0; pNumberParityBits; p++) { - par = 0; - - for (i=0; imax_row_weight; i++) { - ind = H_rows[p + i*ldpc->NumberParityBits]; - par = par + ibits[ind-1]; - } - - tmp = par + prev; - - tmp &= 1; // only retain the lsb - prev = tmp; - pbits[p] = tmp; - } -} - -#ifdef USE_ORIGINAL_PHI0 -/* Phi function */ -static float phi0( - float x ) -{ - float z; - - if (x>10) - return( 0 ); - else if (x< 9.08e-5 ) - return( 10 ); - else if (x > 9) - return( 1.6881e-4 ); - /* return( 1.4970e-004 ); */ - else if (x > 8) - return( 4.5887e-4 ); - /* return( 4.0694e-004 ); */ - else if (x > 7) - return( 1.2473e-3 ); - /* return( 1.1062e-003 ); */ - else if (x > 6) - return( 3.3906e-3 ); - /* return( 3.0069e-003 ); */ - else if (x > 5) - return( 9.2168e-3 ); - /* return( 8.1736e-003 ); */ - else { - z = (float) exp(x); - return( (float) log( (z+1)/(z-1) ) ); - } -} -#endif - - -/* Values for linear approximation (DecoderType=5) */ - -#define AJIAN -0.24904163195436 -#define TJIAN 2.50681740420944 - -/* The linear-log-MAP algorithm */ - -static float max_star0( - float delta1, - float delta2 ) -{ - float diff; - - diff = delta2 - delta1; - - if ( diff > TJIAN ) - return( delta2 ); - else if ( diff < -TJIAN ) - return( delta1 ); - else if ( diff > 0 ) - return( delta2 + AJIAN*(diff-TJIAN) ); - else - return( delta1 - AJIAN*(diff+TJIAN) ); -} - -void init_c_v_nodes(struct c_node *c_nodes, - int shift, - int NumberParityBits, - int max_row_weight, - uint16_t *H_rows, - int H1, - int CodeLength, - struct v_node *v_nodes, - int NumberRowsHcols, - uint16_t *H_cols, - int max_col_weight, - int dec_type, - float *input) -{ - int i, j, k, count, cnt, c_index, v_index; - - /* first determine the degree of each c-node */ - - if (shift ==0){ - for (i=0;i 0 ) { - count++; - } - } - c_nodes[i].degree = count; - if (H1){ - if (i==0){ - c_nodes[i].degree=count+1; - } - else{ - c_nodes[i].degree=count+2; - } - } - } - } - else{ - cnt=0; - for (i=0;i<(NumberParityBits/shift);i++) { - for (k=0;k 0 ) { - count++; - } - } - c_nodes[cnt].degree = count; - if ((i==0)||(i==(NumberParityBits/shift)-1)){ - c_nodes[cnt].degree=count+1; - } - else{ - c_nodes[cnt].degree=count+2; - } - cnt++; - } - } - } - - if (H1){ - - if (shift ==0){ - for (i=0;i0){ - cnt=0; - for (i=0;i<(NumberParityBits/shift);i++){ - - for (k =0;k 0 ) { - count++; - } - } - v_nodes[i].degree = count; - } - - for(i=CodeLength-NumberParityBits+shift;i 0 ) { - count++; - } - } - v_nodes[i].degree = count; - } - } - - if (shift>0){ - v_nodes[CodeLength-1].degree =v_nodes[CodeLength-1].degree+1; - } - - - /* set up v_nodes */ - - for (i=0;i=CodeLength-NumberParityBits+shift)){ - v_nodes[i].subs[j].index=i-(CodeLength-NumberParityBits+shift)+count; - if (shift ==0){ - count=count+1; - } - else{ - count=count+shift; - } - } else { - v_nodes[i].subs[j].index = (H_cols[i+j*NumberRowsHcols] - 1); - } - - /* search the connected c-node for the proper message value */ - for (c_index=0;c_indexindex ].subs[ cp->socket ]; - phi_sum += vp->message; - sign ^= vp->sign; - } - - if (sign==0) ssum++; - - for (i=0;iindex ].subs[ cp->socket ]; - if ( sign ^ vp->sign ) { - cp->message = -phi0( phi_sum - vp->message ); // *r_scale_factor; - } else - cp->message = phi0( phi_sum - vp->message ); // *r_scale_factor; - } - } - - /* update q */ - for (i=0;iindex ].subs[ vp->socket ].message; - } - - /* make hard decision */ - if (Qi < 0) { - DecodedBits[i] = 1; - } - - /* now subtract to get the extrinsic information */ - for (j=0;jindex ].subs[ vp->socket ].message; - - vp->message = phi0( fabs( temp_sum ) ); // *q_scale_factor; - if (temp_sum > 0) - vp->sign = 0; - else - vp->sign = 1; - } - } - - /* count data bit errors, assuming that it is systematic */ - for (i=0;imax_iter; - dec_type = ldpc->dec_type; - q_scale_factor = ldpc->q_scale_factor; - r_scale_factor = ldpc->r_scale_factor; - - CodeLength = ldpc->CodeLength; /* length of entire codeword */ - NumberParityBits = ldpc->NumberParityBits; - NumberRowsHcols = ldpc->NumberRowsHcols; - - char *DecodedBits = (char*) calloc( CodeLength, sizeof( char ) ); - assert(DecodedBits); - - /* derive some parameters */ - - shift = (NumberParityBits + NumberRowsHcols) - CodeLength; - if (NumberRowsHcols == CodeLength) { - H1=0; - shift=0; - } else { - H1=1; - } - - max_row_weight = ldpc->max_row_weight; - max_col_weight = ldpc->max_col_weight; - - /* initialize c-node and v-node structures */ - - c_nodes = (struct c_node*) calloc( NumberParityBits, sizeof( struct c_node ) ); - assert(c_nodes); - v_nodes = (struct v_node*) calloc( CodeLength, sizeof( struct v_node)); - assert(v_nodes); - - init_c_v_nodes(c_nodes, shift, NumberParityBits, max_row_weight, ldpc->H_rows, H1, CodeLength, - v_nodes, NumberRowsHcols, ldpc->H_cols, max_col_weight, dec_type, input); - - int DataLength = CodeLength - NumberParityBits; - int *data_int = (int*) calloc( DataLength, sizeof(int) ); - - /* need to clear these on each call */ - - for(i=0; i 0.0L) - (sd[i] < 0.0L); - x = (sd[i]/mean - sign); - sum += x; - sumsq += x*x; - } - estvar = (n * sumsq - sum * sum) / (n * (n - 1)); - //fprintf(stderr, "mean: %f var: %f\n", mean, estvar); - - estEsN0 = 1.0/(2.0L * estvar + 1E-3); - for(i=0; i> 1; - } - mask = 1 << (bps - 1); - - for (k=0;k> 1; - } - } - for (k=0;kmax_iter = %d\n", ldpc->max_iter); -fprintf(stderr, "ldpc->dec_type = %d\n", ldpc->dec_type); -fprintf(stderr, "ldpc->q_scale_factor = %d\n", ldpc->q_scale_factor); -fprintf(stderr, "ldpc->r_scale_factor = %d\n", ldpc->r_scale_factor); -fprintf(stderr, "ldpc->CodeLength = %d\n", ldpc->CodeLength); -fprintf(stderr, "ldpc->NumberParityBits = %d\n", ldpc->NumberParityBits); -fprintf(stderr, "ldpc->NumberRowsHcols = %d\n", ldpc->NumberRowsHcols); -fprintf(stderr, "ldpc->max_row_weight = %d\n", ldpc->max_row_weight); -fprintf(stderr, "ldpc->max_col_weight = %d\n", ldpc->max_col_weight); -fprintf(stderr, "ldpc->data_bits_per_frame = %d\n", ldpc->data_bits_per_frame); -fprintf(stderr, "ldpc->coded_bits_per_frame = %d\n", ldpc->coded_bits_per_frame); -fprintf(stderr, "ldpc->coded_syms_per_frame = %d\n", ldpc->coded_syms_per_frame); -} - -} // FreeDV - -/* vi:set ts=4 et sts=4: */ diff --git a/libfreedv/mpdecode_core.h b/libfreedv/mpdecode_core.h deleted file mode 100644 index 550f0df7e..000000000 --- a/libfreedv/mpdecode_core.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - FILE...: mpdecode_core.h - AUTHOR.: David Rowe - CREATED: Sep 2016 - - C-callable core functions for MpDecode, so they can be used for - Octave and C programs. Also some convenience functions to help use - the C-callable LDPC decoder in C programs. -*/ - -#ifndef __MPDECODE_CORE__ -#define __MPDECODE_CORE__ - -#include - -#include "codec2/comp.h" - -namespace FreeDV -{ - -struct LDPC { - int max_iter; - int dec_type; - int q_scale_factor; - int r_scale_factor; - int CodeLength; - int NumberParityBits; - int NumberRowsHcols; - int max_row_weight; - int max_col_weight; - int data_bits_per_frame; - int coded_bits_per_frame; - int coded_syms_per_frame; - uint16_t *H_rows; - uint16_t *H_cols; -}; - -void encode(struct LDPC *ldpc, unsigned char ibits[], unsigned char pbits[]); - -int run_ldpc_decoder(struct LDPC *ldpc, uint8_t out_char[], float input[], int *parityCheckCount); - -void sd_to_llr(float llr[], double sd[], int n); -void Demod2D(float symbol_likelihood[], COMP r[], COMP S_matrix[], float EsNo, float fading[], float mean_amp, int number_symbols); -void Somap(float bit_likelihood[], float symbol_likelihood[], int number_symbols); -void symbols_to_llrs(float llr[], COMP rx_qpsk_symbols[], float rx_amps[], float EsNo, float mean_amp, int nsyms); - -void ldpc_print_info(struct LDPC *ldpc); - -} // FreeDV - -#endif diff --git a/libfreedv/ofdm.cpp b/libfreedv/ofdm.cpp deleted file mode 100644 index 134547dcb..000000000 --- a/libfreedv/ofdm.cpp +++ /dev/null @@ -1,1750 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: ofdm.c - AUTHORS.....: David Rowe & Steve Sampson - DATE CREATED: June 2017 - - A Library of functions that implement a QPSK OFDM modem, C port of - the Octave functions in ofdm_lib.m - -\*---------------------------------------------------------------------------*/ -/* - Copyright (C) 2017/2018 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 -#include -#include -#include -#include -#include - -#include "codec2/comp.h" -#include "ofdm_internal.h" -#include "codec2_ofdm.h" -#include "freedv_filter.h" - -namespace FreeDV -{ - -/* Static Prototypes */ - -static std::complex vector_sum(std::complex *, int); -static void dft(struct OFDM *, std::complex *, std::complex *); -static void idft(struct OFDM *, std::complex *, std::complex *); -static void ofdm_demod_core(struct OFDM *ofdm, int *rx_bits); -static int ofdm_sync_search_core(struct OFDM *ofdm); - -/* Defines */ - -#define max( a, b ) ( ((a) > (b)) ? (a) : (b) ) -#define min( a, b ) ( ((a) < (b)) ? (a) : (b) ) - -/* - * QPSK Quadrant bit-pair values - Gray Coded - */ -static const std::complex constellation[] = { - std::complex{1.0f, 0.0f}, - std::complex{0.0f, 1.0f}, - std::complex{0.0f, - 1.0f}, - std::complex{-1.0f, + 0.0f} -}; - -/* - * These pilots are compatible with Octave version - */ -static const int8_t pilotvalues[] = { - -1,-1, 1, 1,-1,-1,-1, 1, - -1, 1,-1, 1, 1, 1, 1, 1, - 1, 1, 1,-1,-1, 1,-1, 1, - -1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1,-1, 1, 1, 1, 1, - 1,-1,-1,-1,-1,-1,-1, 1, - -1, 1,-1, 1,-1,-1, 1,-1, - 1, 1, 1, 1,-1, 1,-1, 1 -}; - -static std::complex *tx_uw_syms; -static int *uw_ind; -static int *uw_ind_sym; - -/* static variables */ - -static struct OFDM_CONFIG ofdm_config; - -static float ofdm_tx_centre; /* TX Center frequency */ -static float ofdm_rx_centre; /* RX Center frequency */ -static float ofdm_fs; /* Sample rate */ -static float ofdm_ts; /* Symbol cycle time */ -static float ofdm_rs; /* Symbol rate */ -static float ofdm_tcp; /* Cyclic prefix duration */ -static float ofdm_inv_m; /* 1/m */ -static float ofdm_tx_nlower; /* TX lowest carrier freq */ -static float ofdm_rx_nlower; /* RX lowest carrier freq */ -static float ofdm_doc; /* division of radian circle */ -static float ofdm_timing_mx_thresh; /* See 700D Part 4 Acquisition blog post and ofdm_dev.m routines for how this was set */ - -static int ofdm_nc; /* NS-1 data symbols between pilots */ -static int ofdm_ns; -static int ofdm_bps; /* Bits per symbol */ -static int ofdm_m; /* duration of each symbol in samples */ -static int ofdm_ncp; /* duration of CP in samples */ - -static int ofdm_ftwindowwidth; -static int ofdm_bitsperframe; -static int ofdm_rowsperframe; -static int ofdm_samplesperframe; -static int ofdm_max_samplesperframe; -static int ofdm_rxbuf; -static int ofdm_ntxtbits; /* reserve bits/frame for auxillary text information */ -static int ofdm_nuwbits; /* Unique word, used for positive indication of lock */ - -/* Functions -------------------------------------------------------------------*/ - -static float cnormf(std::complex val) { - float realf = val.real(); - float imagf = val.imag(); - - return realf * realf + imagf * imagf; -} - -/* Gray coded QPSK modulation function */ - -std::complex qpsk_mod(int *bits) { - return constellation[(bits[1] << 1) | bits[0]]; -} - -/* Gray coded QPSK demodulation function */ - -void qpsk_demod(std::complex symbol, int *bits) { - std::complex rotate = symbol * cmplx(ROT45); - - bits[0] = rotate.real() < 0.0f; - bits[1] = rotate.imag() < 0.0f; -} - -/* - * ------------ - * ofdm_create - * ------------ - * - * Returns OFDM data structure on success - * Return NULL on fail - * - * If you want the defaults, call this with config structure - * and the NC setting to 0. This will fill the structure with - * default values of the original OFDM modem. - */ - -struct OFDM *ofdm_create(const struct OFDM_CONFIG *config) { - struct OFDM *ofdm; - float tval; - int i, j; - - /* Check if called correctly */ - - if (config == NULL) { - return NULL; - } - - if (config->nc == 0) { - /* Fill in default values */ - - ofdm_nc = 17; /* Number of carriers */ - ofdm_ns = 8; /* Number of Symbol frames */ - ofdm_bps = 2; /* Bits per Symbol */ - ofdm_ts = 0.018f; - ofdm_tcp = .002f; /* Cyclic Prefix duration */ - ofdm_tx_centre = 1500.0f; /* TX Centre Audio Frequency */ - ofdm_rx_centre = 1500.0f; /* RX Centre Audio Frequency */ - ofdm_fs = 8000.0f; /* Sample Frequency */ - ofdm_ntxtbits = 4; - ofdm_ftwindowwidth = 11; - ofdm_timing_mx_thresh = 0.30f; - } else { - /* Use the users values */ - - ofdm_nc = config->nc; /* Number of carriers */ - ofdm_ns = config->ns; /* Number of Symbol frames */ - ofdm_bps = config->bps; /* Bits per Symbol */ - ofdm_ts = config->ts; - ofdm_tcp = config->tcp; /* Cyclic Prefix duration */ - ofdm_tx_centre = config->tx_centre; /* TX Centre Audio Frequency */ - ofdm_rx_centre = config->rx_centre; /* RX Centre Audio Frequency */ - ofdm_fs = config->fs; /* Sample Frequency */ - ofdm_ntxtbits = config->txtbits; - ofdm_ftwindowwidth = config->ftwindowwidth; - ofdm_timing_mx_thresh = config->ofdm_timing_mx_thresh; - } - - ofdm_rs = (1.0f / ofdm_ts); /* Modulation Symbol Rate */ - ofdm_m = (int) (ofdm_fs / ofdm_rs); /* 144 */ - ofdm_ncp = (int) (ofdm_tcp * ofdm_fs); /* 16 */ - ofdm_inv_m = (1.0f / (float) ofdm_m); - - /* Copy structure into global */ - - ofdm_config.tx_centre = ofdm_tx_centre; - ofdm_config.rx_centre = ofdm_rx_centre; - ofdm_config.fs = ofdm_fs; - ofdm_config.rs = ofdm_rs; - ofdm_config.ts = ofdm_ts; - ofdm_config.tcp = ofdm_tcp; - ofdm_config.ofdm_timing_mx_thresh = ofdm_timing_mx_thresh; - ofdm_config.nc = ofdm_nc; - ofdm_config.ns = ofdm_ns; - ofdm_config.bps = ofdm_bps; - ofdm_config.txtbits = ofdm_ntxtbits; - ofdm_config.ftwindowwidth = ofdm_ftwindowwidth; - - /* Calculate sizes from config param */ - - ofdm_bitsperframe = (ofdm_ns - 1) * (ofdm_nc * ofdm_bps); - ofdm_rowsperframe = ofdm_bitsperframe / (ofdm_nc * ofdm_bps); - ofdm_samplesperframe = ofdm_ns * (ofdm_m + ofdm_ncp); - ofdm_max_samplesperframe = ofdm_samplesperframe + (ofdm_m + ofdm_ncp) / 4; - ofdm_rxbuf = 3 * ofdm_samplesperframe + 3 * (ofdm_m + ofdm_ncp); - ofdm_nuwbits = (ofdm_ns - 1) * ofdm_bps - ofdm_ntxtbits; // 10 - - /* Were ready to start filling in the OFDM structure now */ - ofdm = new OFDM(); - ofdm->pilot_samples = new std::complex[ofdm_m + ofdm_ncp]; - ofdm->rxbuf = new std::complex[ofdm_rxbuf]; - ofdm->pilots = new std::complex[ofdm_nc + 2]; - - /* - * rx_sym is a 2D array of variable size - * - * allocate rx_sym row storage. It is a pointer to a pointer - */ - - ofdm->rx_sym = new std::complex*[ofdm_ns + 3]; - - /* allocate rx_sym column storage */ - - int free_last_rx_sym = 0; - for (i = 0; i < (ofdm_ns + 3); i++) - { - ofdm->rx_sym[i] = new std::complex[ofdm_nc + 2]; - - if (ofdm->rx_sym[i] == NULL) { - free_last_rx_sym = i; - } - - free_last_rx_sym = (ofdm_ns + 3); - } - - /* The rest of these are 1D arrays of variable size */ - - ofdm->rx_np = new std::complex[ofdm_rowsperframe * ofdm_nc]; - ofdm->rx_amp = (float*) malloc(sizeof (float) * (ofdm_rowsperframe * ofdm_nc)); - ofdm->aphase_est_pilot_log = (float*) malloc(sizeof (float) * (ofdm_rowsperframe * ofdm_nc)); - ofdm->tx_uw = (uint8_t*) malloc(sizeof (uint8_t) * ofdm_nuwbits); - - for (i = 0; i < ofdm_nuwbits; i++) { - ofdm->tx_uw[i] = 0; - } - - /* Null pointers to unallocated buffers */ - ofdm->ofdm_tx_bpf = NULL; - - /* store complex BPSK pilot symbols */ - - assert(sizeof (pilotvalues) >= (ofdm_nc + 2) * sizeof (int8_t)); - - /* There are only 64 pilot values available */ - - for (i = 0; i < (ofdm_nc + 2); i++) - { - ofdm->pilots[i].real((float) pilotvalues[i]); - ofdm->pilots[i].imag(0.0f); - } - - /* carrier tables for up and down conversion */ - - ofdm_doc = (TAU / (ofdm_fs / ofdm_rs)); - tval = ofdm_rs * ((float) ofdm_nc / 2); - ofdm_tx_nlower = floorf((ofdm_tx_centre - tval) / ofdm_rs); - ofdm_rx_nlower = floorf((ofdm_rx_centre - tval) / ofdm_rs); - - for (i = 0; i < ofdm_rxbuf; i++) { - ofdm->rxbuf[i] = 0.0f; - } - - for (i = 0; i < (ofdm_ns + 3); i++) { - for (j = 0; j < (ofdm_nc + 2); j++) { - ofdm->rx_sym[i][j] = 0.0f; - } - } - - for (i = 0; i < ofdm_rowsperframe * ofdm_nc; i++) { - ofdm->rx_np[i] = 0.0f; - } - - for (i = 0; i < ofdm_rowsperframe; i++) { - for (j = 0; j < ofdm_nc; j++) { - ofdm->aphase_est_pilot_log[ofdm_nc * i + j] = 0.0f; - ofdm->rx_amp[ofdm_nc * i + j] = 0.0f; - } - } - - /* default settings of options and states */ - - ofdm->verbose = 0; - ofdm->timing_en = true; - ofdm->foff_est_en = true; - ofdm->phase_est_en = true; - - ofdm->foff_est_gain = 0.05f; - ofdm->foff_est_hz = 0.0f; - ofdm->sample_point = 0; - ofdm->timing_est = 0; - ofdm->timing_valid = 0; - ofdm->timing_mx = 0.0f; - ofdm->nin = ofdm_samplesperframe; - ofdm->mean_amp = 0.0f; - ofdm->foff_metric = 0.0f; - - /* - * UW symbol placement, designed to get no false syncs at any freq - * offset. Use ofdm_dev.m, debug_false_sync() to test. Note we need - * to pair the UW bits so they fit into symbols. The LDPC decoder - * works on symbols so we can't break up any symbols into UW/LDPC bits. - */ - - uw_ind = (int*) malloc(sizeof (int) * ofdm_nuwbits); - uw_ind_sym = (int*) malloc(sizeof (int) * (ofdm_nuwbits / 2)); - - /* - * The Unique Word is placed in different indexes based on - * the number of carriers requested. - */ - - for (i = 0, j = 0; i < (ofdm_nuwbits / 2); i++, j += 2) { - int val = floorf((i + 1) * (ofdm_nc + 1) / 2); - uw_ind_sym[i] = val; // symbol index - uw_ind[j] = (val * 2); // bit index 1 - uw_ind[j + 1] = (val * 2) + 1; // bit index 2 - } - - tx_uw_syms = new std::complex[ofdm_nuwbits / 2]; - - for (i = 0; i < (ofdm_nuwbits / 2); i++) { - tx_uw_syms[i] = 1.0f; // qpsk_mod(0:0) - } - - /* sync state machine */ - - ofdm->sync_state = search; - ofdm->last_sync_state = search; - ofdm->sync_state_interleaver = search; - ofdm->last_sync_state_interleaver = search; - - ofdm->uw_errors = 0; - ofdm->sync_counter = 0; - ofdm->frame_count = 0; - ofdm->sync_start = false; - ofdm->sync_end = false; - ofdm->sync_mode = autosync; - ofdm->frame_count_interleaver = 0; - - /* create the OFDM waveform */ - - std::complex *temp = new std::complex[ofdm_m]; - - idft(ofdm, temp, ofdm->pilots); - - /* - * pilot_samples is 160 samples, but timing and freq offset est - * were found by experiment to work better without a cyclic - * prefix, so we uses zeroes instead. - */ - - /* zero out Cyclic Prefix (CP) values */ - - for (i = 0; i < ofdm_ncp; i++) { - ofdm->pilot_samples[i] = 0.0f; - } - - /* Now copy the whole thing after the above */ - - for (i = ofdm_ncp, j = 0; j < ofdm_m; i++, j++) { - ofdm->pilot_samples[i] = temp[j]; - } - - delete[] temp; - - /* calculate constant used to normalise timing correlation maximum */ - - float acc = 0.0f; - - for (i = 0; i < (ofdm_m + ofdm_ncp); i++) { - acc += cnormf(ofdm->pilot_samples[i]); - } - - ofdm->timing_norm = (ofdm_m + ofdm_ncp) * acc; - ofdm->clock_offset_counter = 0; - ofdm->sig_var = ofdm->noise_var = 1.0f; - ofdm->tx_bpf_en = false; - - return ofdm; /* Success */ - - //// Error return points with free call in the reverse order of allocation: - - delete[] tx_uw_syms; - free(uw_ind); - free(uw_ind_sym); - free(ofdm->tx_uw); - free(ofdm->aphase_est_pilot_log); - free(ofdm->rx_amp); - delete[] ofdm->rx_np; - - for (i = 0; i < free_last_rx_sym; i++) { - delete[] ofdm->rx_sym[i]; - } - - delete[] ofdm->rx_sym; - delete[] ofdm->pilots; - delete[] ofdm->rxbuf; - delete[] ofdm->pilot_samples; - delete ofdm; - - return(nullptr); -} - -void allocate_tx_bpf(struct OFDM *ofdm) { - ofdm->ofdm_tx_bpf = (struct quisk_cfFilter*) malloc(sizeof(struct quisk_cfFilter)); - - /* Transmit bandpass filter; complex coefficients, center frequency */ - - quisk_filt_cfInit(ofdm->ofdm_tx_bpf, filtP550S750, sizeof (filtP550S750) / sizeof (float)); - quisk_cfTune(ofdm->ofdm_tx_bpf, ofdm_tx_centre / ofdm_fs); -} - -void deallocate_tx_bpf(struct OFDM *ofdm) { - quisk_filt_destroy(ofdm->ofdm_tx_bpf); - free(ofdm->ofdm_tx_bpf); - ofdm->ofdm_tx_bpf = NULL; -} - -void ofdm_destroy(struct OFDM *ofdm) { - int i; - - if (ofdm->ofdm_tx_bpf) - deallocate_tx_bpf(ofdm); - - delete[] ofdm->pilot_samples; - delete[] ofdm->rxbuf; - delete[] ofdm->pilots; - - for (i = 0; i < (ofdm_ns + 3); i++) { /* 2D array */ - delete[] ofdm->rx_sym[i]; - } - - delete[] ofdm->rx_sym; - delete[] ofdm->rx_np; - free(ofdm->rx_amp); - free(ofdm->aphase_est_pilot_log); - free(ofdm->tx_uw); - free(ofdm); -} - -/* convert frequency domain into time domain */ - -static void idft(struct OFDM *ofdm, std::complex *result, std::complex *vector) { - (void) ofdm; - int row, col; - - result[0] = 0.0f; - - for (col = 0; col < (ofdm_nc + 2); col++) { - result[0] += vector[col]; // cexp(0j) == 1 - } - - result[0] *= ofdm_inv_m; - - for (row = 1; row < ofdm_m; row++) { - float tval1 = ofdm_tx_nlower * ofdm_doc *row; - float tval2 = ofdm_doc * row; - - std::complex c = cmplx(tval1); - std::complex delta = cmplx(tval2); - - result[row] = 0.0f; - - for (col = 0; col < (ofdm_nc + 2); col++) { - result[row] += (vector[col] * c); - c *= delta; - } - - result[row] *= ofdm_inv_m; - } -} - -/* convert time domain into frequency domain */ - -static void dft(struct OFDM *ofdm, std::complex *result, std::complex *vector) { - (void) ofdm; - int row, col, nlower; - - for (col = 0; col < (ofdm_nc + 2); col++) { - result[col] = vector[0]; // conj(cexp(0j)) == 1 - } - - for (col = 0, nlower = ofdm_rx_nlower; col < (ofdm_nc + 2); col++, nlower++) { - float tval = nlower * ofdm_doc; - std::complex c = cmplxconj(tval); - std::complex delta = c; - - for (row = 1; row < ofdm_m; row++) { - result[col] += (vector[row] * c); - c *= delta; - } - } -} - -static std::complex vector_sum(std::complex *a, int num_elements) { - int i; - - std::complex sum = 0.0f; - - for (i = 0; i < num_elements; i++) { - sum += a[i]; - } - - return sum; -} - -/* - * Correlates the OFDM pilot symbol samples with a window of received - * samples to determine the most likely timing offset. Combines two - * frames pilots so we need at least Nsamperframe+M+Ncp samples in rx. - * - * Can be used for acquisition (coarse timing), and fine timing. - * - * Unlike Octave version use states to return a few values. - */ - -static int est_timing(struct OFDM *ofdm, std::complex *rx, int length) { - std::complex csam; - int Ncorr = length - (ofdm_samplesperframe + (ofdm_m + ofdm_ncp)); - int SFrame = ofdm_samplesperframe; - float *corr = new float[Ncorr]; - int i, j; - - float acc = 0.0f; - - for (i = 0; i < length; i++) { - acc += cnormf(rx[i]); - } - - float av_level = 2.0f * sqrtf(ofdm->timing_norm * acc / length) + 1E-12f; - - for (i = 0; i < Ncorr; i++) { - std::complex corr_st = 0.0f; - std::complex corr_en = 0.0f; - - for (j = 0; j < (ofdm_m + ofdm_ncp); j++) { - csam = std::conj(ofdm->pilot_samples[j]); - - corr_st = corr_st + (rx[i + j ] * csam); - corr_en = corr_en + (rx[i + j + SFrame] * csam); - } - - corr[i] = (std::abs(corr_st) + std::abs(corr_en)) / av_level; - } - - /* find the max magnitude and its index */ - - float timing_mx = 0.0f; - int timing_est = 0; - - for (i = 0; i < Ncorr; i++) { - if (corr[i] > timing_mx) { - timing_mx = corr[i]; - timing_est = i; - } - } - - ofdm->timing_mx = timing_mx; - ofdm->timing_valid = (timing_mx > ofdm_timing_mx_thresh); /* bool but used as external int */ - - if (ofdm->verbose > 1) { - fprintf(stderr, " av_level: %f max: %f timing_est: %d timing_valid: %d\n", (double) av_level, (double) ofdm->timing_mx, timing_est, ofdm->timing_valid); - } - - delete[] corr; - - return timing_est; -} - -/* - * Determines frequency offset at current timing estimate, used for - * coarse freq offset estimation during acquisition. - * - * Freq offset is based on an averaged statistic that was found to be - * necessary to generate good quality estimates. - * - * Keep calling it when in trial or actual sync to keep statistic - * updated, in case we lose sync. - */ - -static float est_freq_offset(struct OFDM *ofdm, std::complex *rx, int timing_est) { - std::complex csam1, csam2; - float foff_est; - int j, k; - - /* - Freq offset can be considered as change in phase over two halves - of pilot symbols. We average this statistic over this and next - frames pilots. - */ - - std::complex p1, p2, p3, p4; - p1 = p2 = p3 = p4 = 0.0f; - - /* calculate phase of pilots at half symbol intervals */ - - for (j = 0, k = (ofdm_m + ofdm_ncp) / 2; j < (ofdm_m + ofdm_ncp) / 2; j++, k++) { - csam1 = std::conj(ofdm->pilot_samples[j]); - csam2 = std::conj(ofdm->pilot_samples[k]); - - /* pilot at start of frame */ - - p1 = p1 + (rx[timing_est + j] * csam1); - p2 = p2 + (rx[timing_est + k] * csam2); - - /* pilot at end of frame */ - - p3 = p3 + (rx[timing_est + j + ofdm_samplesperframe] * csam1); - p4 = p4 + (rx[timing_est + k + ofdm_samplesperframe] * csam2); - } - - /* Calculate sample rate of phase samples, we are sampling phase - of pilot at half a symbol intervals */ - - float Fs1 = ofdm_fs / ((ofdm_m + ofdm_ncp) / 2); - - /* - * subtract phase of adjacent samples, rate of change of phase is - * frequency est. We combine samples from either end of frame to - * improve estimate. Small real 1E-12 term to prevent instability - * with 0 inputs. - */ - - ofdm->foff_metric = 0.9f * ofdm->foff_metric + 0.1f * (std::conj(p1) * p2 + std::conj(p3) * p4); - foff_est = Fs1 * std::arg(ofdm->foff_metric + 1E-12f) / TAU; - - if (ofdm->verbose > 1) { - fprintf(stderr, " foff_metric: %f %f foff_est: %f\n", std::real(ofdm->foff_metric), std::imag(ofdm->foff_metric), (double) foff_est); - } - - return foff_est; -} - -/* - * ---------------------------------------------- - * ofdm_txframe - modulates one frame of symbols - * ---------------------------------------------- - */ - -void ofdm_txframe(struct OFDM *ofdm, std::complex *tx, std::complex *tx_sym_lin) { - int sx = ofdm_ns; - int sy = ofdm_nc + 2; - std::complex *aframe = new std::complex[sx*sy]; - std::complex *asymbol = new std::complex[ofdm_m]; - std::complex *asymbol_cp = new std::complex[ofdm_m + ofdm_ncp]; - int i, j, k, m; - - /* initialize aframe to complex zero */ - - for (i = 0; i < ofdm_ns; i++) { - for (j = 0; j < (ofdm_nc + 2); j++) { - aframe[i*sy+j] = 0.0f; - } - } - - /* copy in a row of complex pilots to first row */ - - for (i = 0; i < (ofdm_nc + 2); i++) { - aframe[0*sy+i] = ofdm->pilots[i]; - } - - /* - * Place symbols in multi-carrier frame with pilots - * This will place boundary values of complex zero around data - */ - - for (i = 1; i <= ofdm_rowsperframe; i++) { - - /* copy in the Nc complex values with [0 Nc 0] or (Nc + 2) total */ - - for (j = 1; j < (ofdm_nc + 1); j++) { - aframe[i*sy+j] = tx_sym_lin[((i - 1) * ofdm_nc) + (j - 1)]; - } - } - - /* OFDM up-convert symbol by symbol so we can add CP */ - - for (i = 0, m = 0; i < ofdm_ns; i++, m += (ofdm_m + ofdm_ncp)) { - idft(ofdm, asymbol, &aframe[i*sy]); - - /* Copy the last Ncp samples to the front */ - - for (j = (ofdm_m - ofdm_ncp), k = 0; j < ofdm_m; j++, k++) { - asymbol_cp[k] = asymbol[j]; - } - - /* Now copy the all samples for this row after it */ - - for (j = ofdm_ncp, k = 0; k < ofdm_m; j++, k++) { - asymbol_cp[j] = asymbol[k]; - } - - /* Now move row to the tx output */ - - for (j = 0; j < (ofdm_m + ofdm_ncp); j++) { - tx[m + j] = asymbol_cp[j]; - } - } - - /* optional Tx Band Pass Filter */ - - if (ofdm->tx_bpf_en == true) { - std::complex *tx_filt = new std::complex[ofdm_samplesperframe]; - - quisk_ccfFilter(tx, tx_filt, ofdm_samplesperframe, ofdm->ofdm_tx_bpf); - memcpy(tx, tx_filt, ofdm_samplesperframe * sizeof (std::complex)); - delete[] tx_filt; - } - - delete[] asymbol_cp; - delete[] asymbol; - delete[] aframe; - } - -struct OFDM_CONFIG *ofdm_get_config_param() { - return &ofdm_config; -} - -int ofdm_get_nin(struct OFDM *ofdm) { - return ofdm->nin; -} - -int ofdm_get_samples_per_frame() { - return ofdm_samplesperframe; -} - -int ofdm_get_max_samples_per_frame() { - return 2 * ofdm_max_samplesperframe; -} - -int ofdm_get_bits_per_frame() { - return ofdm_bitsperframe; -} - -void ofdm_set_verbose(struct OFDM *ofdm, int level) { - ofdm->verbose = level; -} - -void ofdm_set_timing_enable(struct OFDM *ofdm, bool val) { - ofdm->timing_en = val; - - if (ofdm->timing_en == false) { - /* manually set ideal timing instant */ - - ofdm->sample_point = (ofdm_ncp - 1); - } -} - -void ofdm_set_foff_est_enable(struct OFDM *ofdm, bool val) { - ofdm->foff_est_en = val; -} - -void ofdm_set_phase_est_enable(struct OFDM *ofdm, bool val) { - ofdm->phase_est_en = val; -} - -void ofdm_set_off_est_hz(struct OFDM *ofdm, float val) { - ofdm->foff_est_hz = val; -} - -void ofdm_set_tx_bpf(struct OFDM *ofdm, bool val) { - if (val == true) { - allocate_tx_bpf(ofdm); - ofdm->tx_bpf_en = true; - } else { - if (ofdm->ofdm_tx_bpf) - deallocate_tx_bpf(ofdm); - ofdm->tx_bpf_en = false; - } -} - -/* - * -------------------------------------- - * ofdm_mod - modulates one frame of bits - * -------------------------------------- - */ - -void ofdm_mod(struct OFDM *ofdm, COMP *result, const int *tx_bits) { - int length = ofdm_bitsperframe / ofdm_bps; - std::complex *tx = (std::complex *) &result[0]; // complex has same memory layout - std::complex *tx_sym_lin = new std::complex[length]; - int dibit[2]; - int s, i; - - if (ofdm_bps == 1) { - /* Here we will have Nbitsperframe / 1 */ - - for (s = 0; s < length; s++) { - tx_sym_lin[s] = (float) (2 * tx_bits[s] - 1); - } - } else if (ofdm_bps == 2) { - /* Here we will have Nbitsperframe / 2 */ - - for (s = 0, i = 0; i < length; s += 2, i++) { - dibit[0] = tx_bits[s + 1] & 0x1; - dibit[1] = tx_bits[s ] & 0x1; - tx_sym_lin[i] = qpsk_mod(dibit); - } - } - - ofdm_txframe(ofdm, tx, tx_sym_lin); - delete[] tx_sym_lin; - } - -/* - * ---------------------------------------------------------------------------------- - * ofdm_sync_search - attempts to find coarse sync parameters for modem initial sync - * ---------------------------------------------------------------------------------- - */ - -/* - * This is a wrapper to maintain the older functionality - * with an array of COMPs as input - */ -int ofdm_sync_search(struct OFDM *ofdm, COMP *rxbuf_in) { - std::complex *rx = (std::complex *) &rxbuf_in[0]; // complex has same memory layout - int i, j; - - /* - * insert latest input samples into rxbuf - * so it is primed for when we have to - * call ofdm_demod() - */ - for (i = 0, j = ofdm->nin; i < (ofdm_rxbuf - ofdm->nin); i++, j++) { - ofdm->rxbuf[i] = ofdm->rxbuf[j]; - } - - /* insert latest input samples onto tail of rxbuf */ - - for (i = (ofdm_rxbuf - ofdm->nin), j = 0; i < ofdm_rxbuf; i++, j++) { - ofdm->rxbuf[i] = rx[j]; - } - - return(ofdm_sync_search_core(ofdm)); -} - -/* - * This is a wrapper with a new interface to reduce memory allocated. - * This works with ofdm_demod and freedv_api. - */ -int ofdm_sync_search_shorts(struct OFDM *ofdm, short *rxbuf_in, float gain) { - int i, j; - - /* shift the buffer left based on nin */ - - for (i = 0, j = ofdm->nin; i < (ofdm_rxbuf - ofdm->nin); i++, j++) { - ofdm->rxbuf[i] = ofdm->rxbuf[j]; - } - - /* insert latest input samples onto tail of rxbuf */ - - for (i = (ofdm_rxbuf - ofdm->nin), j = 0; i < ofdm_rxbuf; i++, j++) { - ofdm->rxbuf[i] = ((float)rxbuf_in[j] * gain); - } - - return(ofdm_sync_search_core(ofdm)); -} - -/* - * This is the rest of the function which expects that the data is - * already in ofdm->rxbuf - */ -static int ofdm_sync_search_core(struct OFDM *ofdm) { - /* Attempt coarse timing estimate (i.e. detect start of frame) */ - - int st = ofdm_m + ofdm_ncp + ofdm_samplesperframe; - int en = st + 2 * ofdm_samplesperframe; - int ct_est = est_timing(ofdm, &ofdm->rxbuf[st], (en - st)); - - ofdm->coarse_foff_est_hz = est_freq_offset(ofdm, &ofdm->rxbuf[st], ct_est); - - if (ofdm->verbose) { - fprintf(stderr, " ct_est: %4d foff_est: %4.1f timing_valid: %d timing_mx: %5.4f\n", - ct_est, (double) ofdm->coarse_foff_est_hz, ofdm->timing_valid, (double) ofdm->timing_mx); - } - - if (ofdm->timing_valid) { - /* potential candidate found .... */ - - /* calculate number of samples we need on next buffer to get into sync */ - - ofdm->nin = ofdm_samplesperframe + ct_est; - - /* reset modem states */ - - ofdm->sample_point = ofdm->timing_est = 0; - ofdm->foff_est_hz = ofdm->coarse_foff_est_hz; - } else { - ofdm->nin = ofdm_samplesperframe; - } - - return ofdm->timing_valid; -} - -/* - * ------------------------------------------ - * ofdm_demod - Demodulates one frame of bits - * ------------------------------------------ - */ - -/* This is a wrapper to maintain the older functionality with an - * array of COMPs as input */ -void ofdm_demod(struct OFDM *ofdm, int *rx_bits, COMP *rxbuf_in) { - std::complex *rx = (std::complex *) &rxbuf_in[0]; // complex has same memory layout - int i, j; - - /* shift the buffer left based on nin */ - for (i = 0, j = ofdm->nin; i < (ofdm_rxbuf - ofdm->nin); i++, j++) { - ofdm->rxbuf[i] = ofdm->rxbuf[j]; - } - - /* insert latest input samples onto tail of rxbuf */ - for (i = (ofdm_rxbuf - ofdm->nin), j = 0; i < ofdm_rxbuf; i++, j++) { - ofdm->rxbuf[i] = rx[j]; - } - - ofdm_demod_core(ofdm, rx_bits); -} - -/* This is a wrapper with a new interface to reduce memory allocated. - * This works with ofdm_demod and freedv_api. */ -void ofdm_demod_shorts(struct OFDM *ofdm, int *rx_bits, short *rxbuf_in, float gain) { - int i, j; - - /* shift the buffer left based on nin */ - for (i = 0, j = ofdm->nin; i < (ofdm_rxbuf - ofdm->nin); i++, j++) { - ofdm->rxbuf[i] = ofdm->rxbuf[j]; - } - - /* insert latest input samples onto tail of rxbuf */ - for (i = (ofdm_rxbuf - ofdm->nin), j = 0; i < ofdm_rxbuf; i++, j++) { - ofdm->rxbuf[i] = ((float)rxbuf_in[j] * gain); - } - - ofdm_demod_core(ofdm, rx_bits); -} - -/* - * This is the rest of the function which expects that the data is - * already in ofdm->rxbuf - */ -static void ofdm_demod_core(struct OFDM *ofdm, int *rx_bits) { - std::complex aphase_est_pilot_rect; - float *aphase_est_pilot = new float[ofdm_nc + 2]; - float *aamp_est_pilot = new float[ofdm_nc + 2]; - float freq_err_hz; - int i, j, k, rr, st, en, ft_est; - int prev_timing_est = ofdm->timing_est; - - /* - * get user and calculated freq offset - */ - - float woff_est = TAU * ofdm->foff_est_hz / ofdm_fs; - - /* update timing estimate -------------------------------------------------- */ - - if (ofdm->timing_en == true) { - /* update timing at start of every frame */ - - st = ((ofdm_m + ofdm_ncp) + ofdm_samplesperframe) - floorf(ofdm_ftwindowwidth / 2) + ofdm->timing_est; - en = st + ofdm_samplesperframe - 1 + (ofdm_m + ofdm_ncp) + ofdm_ftwindowwidth; - - std::complex *work = new std::complex[(en - st)]; - - /* - * Adjust for the frequency error by shifting the phase - * using a conjugate multiply - */ - - for (i = st, j = 0; i < en; i++, j++) { - float tval = woff_est * i; - work[j] = ofdm->rxbuf[i] * cmplxconj(tval); - } - - ft_est = est_timing(ofdm, work, (en - st)); - ofdm->timing_est += (ft_est - ceilf(ofdm_ftwindowwidth / 2)); - - /* - * keep the freq est statistic updated in case we lose sync, - * note we supply it with uncorrected rxbuf, note - * ofdm->coarse_fest_off_hz is unused in normal operation, - * but stored for use in tofdm.c - */ - - ofdm->coarse_foff_est_hz = est_freq_offset(ofdm, &ofdm->rxbuf[st], ft_est); - - /* first frame in trial sync will have a better freq offset est - lets use it */ - - if (ofdm->frame_count == 0) { - ofdm->foff_est_hz = ofdm->coarse_foff_est_hz; - woff_est = TAU * ofdm->foff_est_hz / ofdm_fs; - } - - if (ofdm->verbose > 1) { - fprintf(stderr, " ft_est: %2d timing_est: %2d sample_point: %2d\n", ft_est, ofdm->timing_est, ofdm->sample_point); - } - - /* Black magic to keep sample_point inside cyclic prefix. Or something like that. */ - - ofdm->sample_point = max(ofdm->timing_est + (ofdm_ncp / 4), ofdm->sample_point); - ofdm->sample_point = min(ofdm->timing_est + ofdm_ncp, ofdm->sample_point); - delete[] work; - } - - /* - * Convert the time-domain samples to the frequency-domain using the rx_sym - * data matrix. This will be Nc+2 carriers of 11 symbols. - * - * You will notice there are Nc+2 BPSK symbols for each pilot symbol, and that there - * are Nc QPSK symbols for each data symbol. - * - * XXXXXXXXXXXXXXXXX <-- Timing Slip - * PPPPPPPPPPPPPPPPPPP <-- Previous Frames Pilot - * DDDDDDDDDDDDDDDDD - * DDDDDDDDDDDDDDDDD - * DDDDDDDDDDDDDDDDD - * DDDDDDDDDDDDDDDDD Ignore these past data symbols - * DDDDDDDDDDDDDDDDD - * DDDDDDDDDDDDDDDDD - * DDDDDDDDDDDDDDDDD - * PPPPPPPPPPPPPPPPPPP <-- This Frames Pilot - * DDDDDDDDDDDDDDDDD - * DDDDDDDDDDDDDDDDD - * DDDDDDDDDDDDDDDDD - * DDDDDDDDDDDDDDDDD These are the current data symbols to be decoded - * DDDDDDDDDDDDDDDDD - * DDDDDDDDDDDDDDDDD - * DDDDDDDDDDDDDDDDD - * PPPPPPPPPPPPPPPPPPP <-- Next Frames Pilot - * DDDDDDDDDDDDDDDDD - * DDDDDDDDDDDDDDDDD - * DDDDDDDDDDDDDDDDD - * DDDDDDDDDDDDDDDDD Ignore these next data symbols - * DDDDDDDDDDDDDDDDD - * DDDDDDDDDDDDDDDDD - * DDDDDDDDDDDDDDDDD - * PPPPPPPPPPPPPPPPPPP <-- Future Frames Pilot - * XXXXXXXXXXXXXXXXX <-- Timing Slip - * - * So this algorithm will have seven data symbols and four pilot symbols to process. - * The average of the four pilot symbols is our phase estimation. - */ - - for (i = 0; i < (ofdm_ns + 3); i++) { - for (j = 0; j < (ofdm_nc + 2); j++) { - ofdm->rx_sym[i][j] = 0.0f; - } - } - - /* - * "Previous" pilot symbol is one modem frame above. - */ - - st = (ofdm_m + ofdm_ncp) + 1 + ofdm->sample_point; - en = st + ofdm_m; - - std::complex *work = new std::complex[ofdm_m]; - - /* down-convert at current timing instant---------------------------------- */ - - for (j = st, k = 0; j < en; j++, k++) { - float tval = woff_est * j; - work[k] = ofdm->rxbuf[j] * cmplxconj(tval); - } - - /* - * Each symbol is of course (ofdm_m + ofdm_ncp) samples long and - * becomes Nc+2 carriers after DFT. - * - * We put this carrier pilot symbol at the top of our matrix: - * - * 1 .................. Nc+2 - * - * +----------------------+ - * | Previous Pilot | rx_sym[0] - * +----------------------+ - * | | - * - */ - - dft(ofdm, ofdm->rx_sym[0], work); - - /* - * "This" pilot comes after the extra symbol allotted at the top, and after - * the "previous" pilot and previous data symbols (let's call it, the previous - * modem frame). - * - * So we will now be starting at "this" pilot symbol, and continuing to the - * "next" pilot symbol. - * - * In this routine we also process the current data symbols. - */ - - for (rr = 0; rr < (ofdm_ns + 1); rr++) { - st = (ofdm_m + ofdm_ncp) + ofdm_samplesperframe + (rr * (ofdm_m + ofdm_ncp)) + 1 + ofdm->sample_point; - en = st + ofdm_m; - - /* down-convert at current timing instant---------------------------------- */ - - for (j = st, k = 0; j < en; j++, k++) { - float tval = woff_est * j; - work[k] = ofdm->rxbuf[j] * cmplxconj(tval); - } - - /* - * We put these Nc+2 carrier symbols into our matrix after the previous pilot: - * - * 1 .................. Nc+2 - * - * | Previous Pilot | rx_sym[0] - * +----------------------+ - * | This Pilot | rx_sym[1] - * +----------------------+ - * | Data | rx_sym[2] - * +----------------------+ - * | Data | rx_sym[3] - * +----------------------+ - * | Data | rx_sym[4] - * +----------------------+ - * | Data | rx_sym[5] - * +----------------------+ - * | Data | rx_sym[6] - * +----------------------+ - * | Data | rx_sym[7] - * +----------------------+ - * | Data | rx_sym[8] - * +----------------------+ - * | Next Pilot | rx_sym[9] - * +----------------------+ - * | | rx_sym[10] - */ - - dft(ofdm, ofdm->rx_sym[rr + 1], work); - } - - /* - * OK, now we want to process to the "future" pilot symbol. This is after - * the "next" modem frame. - * - * We are ignoring the data symbols between the "next" pilot and "future" pilot. - * We only want the "future" pilot symbol, to perform the averaging of all pilots. - */ - - st = (ofdm_m + ofdm_ncp) + (3 * ofdm_samplesperframe) + 1 + ofdm->sample_point; - en = st + ofdm_m; - - /* down-convert at current timing instant---------------------------------- */ - - for (j = st, k = 0; j < en; j++, k++) { - float tval = woff_est * j; - work[k] = ofdm->rxbuf[j] * cmplxconj(tval); - } - - /* - * We put the future pilot after all the previous symbols in the matrix: - * - * 1 .................. Nc+2 - * - * | | rx_sym[9] - * +----------------------+ - * | Future Pilot | rx_sym[10] - * +----------------------+ - */ - - dft(ofdm, ofdm->rx_sym[ofdm_ns + 2], work); - - /* - * We are finished now with the DFT and down conversion - * From here on down we are in frequency domain - */ - - /* est freq err based on all carriers ------------------------------------ */ - - if (ofdm->foff_est_en == true) { - /* - * sym[1] is (this) pilot symbol, sym[9] is (next) pilot symbol. - * - * By subtracting the two averages of these pilots, we find the frequency - * by the change in phase over time. - */ - - std::complex freq_err_rect = - std::conj(vector_sum(ofdm->rx_sym[1], ofdm_nc + 2)) * - vector_sum(ofdm->rx_sym[ofdm_ns + 1], ofdm_nc + 2); - - /* prevent instability in atan(im/re) when real part near 0 */ - - freq_err_rect += 1E-6f; - - freq_err_hz = std::arg(freq_err_rect) * ofdm_rs / (TAU * ofdm_ns); - ofdm->foff_est_hz += (ofdm->foff_est_gain * freq_err_hz); - } - - /* OK - now estimate and correct pilot phase ---------------------------------- */ - - for (i = 0; i < (ofdm_nc + 2); i++) { - aphase_est_pilot[i] = 10.0f; - aamp_est_pilot[i] = 0.0f; - } - - /* - * Basically we divide the Nc+2 pilots into groups of 3 - * - * Then average the phase surrounding each of the data symbols. - */ - - for (i = 1; i < (ofdm_nc + 1); i++) { - std::complex symbol[3]; - - for (j = (i - 1), k = 0; j < (i + 2); j++, k++) { - symbol[k] = ofdm->rx_sym[1][j] * std::conj(ofdm->pilots[j]); /* this pilot conjugate */ - } - - aphase_est_pilot_rect = vector_sum(symbol, 3); - - for (j = (i - 1), k = 0; j < (i + 2); j++, k++) { - symbol[k] = ofdm->rx_sym[ofdm_ns + 1][j] * std::conj(ofdm->pilots[j]); /* next pilot conjugate */ - } - - aphase_est_pilot_rect = aphase_est_pilot_rect + vector_sum(symbol, 3); - - /* use next step of pilots in past and future */ - - for (j = (i - 1), k = 0; j < (i + 2); j++, k++) { - symbol[k] = ofdm->rx_sym[0][j] * std::conj(ofdm->pilots[j]); /* previous pilot */ - } - - aphase_est_pilot_rect = aphase_est_pilot_rect + vector_sum(symbol, 3); - - for (j = (i - 1), k = 0; j < (i + 2); j++, k++) { - symbol[k] = ofdm->rx_sym[ofdm_ns + 2][j] * std::conj(ofdm->pilots[j]); /* last pilot */ - } - - aphase_est_pilot_rect = aphase_est_pilot_rect + vector_sum(symbol, 3); - aphase_est_pilot[i] = std::arg(aphase_est_pilot_rect); - - /* amplitude is estimated over 12 pilots */ - - aamp_est_pilot[i] = std::abs(aphase_est_pilot_rect / 12.0f); - } - - /* - * correct phase offset using phase estimate, and demodulate - * bits, separate loop as it runs across cols (carriers) to get - * frame bit ordering correct - */ - - std::complex rx_corr; - int abit[2]; - int bit_index = 0; - float sum_amp = 0.0f; - - for (rr = 0; rr < ofdm_rowsperframe; rr++) { - /* - * Note the i starts with the second carrier, ends with Nc+1. - * so we ignore the first and last carriers. - * - * Also note we are using sym[2..8] or the seven data symbols. - */ - - for (i = 1; i < (ofdm_nc + 1); i++) { - if (ofdm->phase_est_en == true) { - rx_corr = ofdm->rx_sym[rr + 2][i] * cmplxconj(aphase_est_pilot[i]); - } else { - rx_corr = ofdm->rx_sym[rr + 2][i]; - } - - /* - * Output complex data symbols after phase correction; - * rx_np means the pilot symbols have been removed - */ - - ofdm->rx_np[(rr * ofdm_nc) + (i - 1)] = rx_corr; - - /* - * Note even though amp ests are the same for each col, - * the FEC decoder likes to have one amplitude per symbol - * so convenient to log them all - */ - - ofdm->rx_amp[(rr * ofdm_nc) + (i - 1)] = aamp_est_pilot[i]; - sum_amp += aamp_est_pilot[i]; - - /* - * Note like amps in this implementation phase ests are the - * same for each col, but we log them for each symbol anyway - */ - - ofdm->aphase_est_pilot_log[(rr * ofdm_nc) + (i - 1)] = aphase_est_pilot[i]; - - if (ofdm_bps == 1) { - rx_bits[bit_index++] = std::real(rx_corr) > 0.0f; - } else if (ofdm_bps == 2) { - /* - * Only one final task, decode what quadrant the phase - * is in, and return the dibits - */ - qpsk_demod(rx_corr, abit); - rx_bits[bit_index++] = abit[1]; - rx_bits[bit_index++] = abit[0]; - } - } - } - - /* update mean amplitude estimate for LDPC decoder scaling */ - - ofdm->mean_amp = 0.9f * ofdm->mean_amp + 0.1f * sum_amp / (ofdm_rowsperframe * ofdm_nc); - - /* Adjust nin to take care of sample clock offset */ - - ofdm->nin = ofdm_samplesperframe; - - if (ofdm->timing_en == true) { - ofdm->clock_offset_counter += prev_timing_est - ofdm->timing_est; - - int thresh = (ofdm_m + ofdm_ncp) / 8; - int tshift = (ofdm_m + ofdm_ncp) / 4; - - if (ofdm->timing_est > thresh) { - ofdm->nin = ofdm_samplesperframe + tshift; - ofdm->timing_est -= tshift; - ofdm->sample_point -= tshift; - } else if (ofdm->timing_est < -thresh) { - ofdm->nin = ofdm_samplesperframe - tshift; - ofdm->timing_est += tshift; - ofdm->sample_point += tshift; - } - } - - /* - * estimate signal and noise power, see ofdm_lib.m, - * cohpsk.m for more info - */ - - std::complex *rx_np = ofdm->rx_np; - - float sig_var = 0.0f; - - for (i = 0; i < (ofdm_rowsperframe * ofdm_nc); i++) { - sig_var += cnormf(rx_np[i]); - } - - sig_var /= (ofdm_rowsperframe * ofdm_nc); - float sig_rms = sqrtf(sig_var); - - float sum_x = 0.0f; - float sum_xx = 0.0f; - int n = 0; - - for (i = 0; i < (ofdm_rowsperframe * ofdm_nc); i++) { - std::complex s = rx_np[i]; - - if (fabsf(std::real(s)) > sig_rms) { - sum_x += std::imag(s); - sum_xx += std::imag(s) * std::imag(s); - n++; - } - } - - /* - * with large interfering carriers this alg can break down - in - * that case set a benign value for noise_var that will produce a - * sensible (probably low) SNR est - */ - - float noise_var = 1.0f; - - if (n > 1) { - noise_var = (n * sum_xx - sum_x * sum_x) / (n * (n - 1)); - } - - ofdm->noise_var = 2.0f * noise_var; - ofdm->sig_var = sig_var; - - delete[] work; - delete[] aamp_est_pilot; - delete[] aphase_est_pilot; -} - -/* iterate state machine ------------------------------------*/ - -void ofdm_sync_state_machine(struct OFDM *ofdm, uint8_t *rx_uw) { - int i; - - State next_state = ofdm->sync_state; - - ofdm->sync_start = false; - ofdm->sync_end = false; - - if (ofdm->sync_state == search) { - if (ofdm->timing_valid) { - ofdm->frame_count = 0; - ofdm->sync_counter = 0; - ofdm->sync_start = true; - ofdm->clock_offset_counter = 0; - next_state = trial; - } - } - - if ((ofdm->sync_state == synced) || (ofdm->sync_state == trial)) { - ofdm->frame_count++; - ofdm->frame_count_interleaver++; - - /* - * freq offset est may be too far out, and has aliases every 1/Ts, so - * we use a Unique Word to get a really solid indication of sync. - */ - - ofdm->uw_errors = 0; - - for (i = 0; i < ofdm_nuwbits; i++) { - ofdm->uw_errors += ofdm->tx_uw[i] ^ rx_uw[i]; - } - - /* - * during trial sync we don't tolerate errors so much, we look - * for 3 consecutive frames with low error rate to confirm sync - */ - - if (ofdm->sync_state == trial) { - if (ofdm->uw_errors > 2) { - /* if we exceed thresh stay in trial sync */ - - ofdm->sync_counter++; - ofdm->frame_count = 0; - } - - if (ofdm->sync_counter == 2) { - /* if we get two bad frames drop sync and start again */ - - next_state = search; - ofdm->sync_state_interleaver = search; - } - - if (ofdm->frame_count == 4) { - /* three good frames, sync is OK! */ - - next_state = synced; - } - } - - /* once we have synced up we tolerate a higher error rate to wait out fades */ - - if (ofdm->sync_state == synced) { - if (ofdm->uw_errors > 2) { - ofdm->sync_counter++; - } else { - ofdm->sync_counter = 0; - } - - if ((ofdm->sync_mode == autosync) && (ofdm->sync_counter == 12)) { - /* run of consecutive bad frames ... drop sync */ - - next_state = search; - ofdm->sync_state_interleaver = search; - } - } - } - - ofdm->last_sync_state = ofdm->sync_state; - ofdm->last_sync_state_interleaver = ofdm->sync_state_interleaver; - ofdm->sync_state = next_state; -} - -/*---------------------------------------------------------------------------* \ - - FUNCTIONS...: ofdm_set_sync - AUTHOR......: David Rowe - DATE CREATED: May 2018 - - Operator control of sync state machine. This mode is required to - acquire sync up at very low SNRS. This is difficult to implement, - for example we may get a false sync, or the state machine may fall - out of sync by mistake during a long fade. - - So with this API call we allow some operator assistance. - - Ensure this is called in the same thread as ofdm_sync_state_machine(). - -\*---------------------------------------------------------------------------*/ - -void ofdm_set_sync(struct OFDM *ofdm, Sync sync_cmd) { - assert(ofdm != NULL); - - switch (sync_cmd) { - case unsync: - /* - * force manual unsync, in case operator detects false sync, - * which will cause sync state machine to have another go at sync - */ - ofdm->sync_state = search; - ofdm->sync_state_interleaver = search; - break; - case autosync: - /* normal operating mode - sync state machine decides when to unsync */ - - ofdm->sync_mode = autosync; - break; - case manualsync: - /* - * allow sync state machine to sync, but not to unsync, the - * operator will decide that manually - */ - ofdm->sync_mode = manualsync; - break; - default: - fprintf(stderr, "FreeDV::ofdm_set_sync: unknnown sync mode default to autosync"); - ofdm->sync_mode = autosync; - } -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: ofdm_get_demod_stats() - AUTHOR......: David Rowe - DATE CREATED: May 2018 - - Fills stats structure with a bunch of demod information. - -\*---------------------------------------------------------------------------*/ - -void ofdm_get_demod_stats(struct OFDM *ofdm, struct MODEM_STATS *stats) { - int c, r; - - stats->Nc = ofdm_nc; - assert(stats->Nc <= MODEM_STATS_NC_MAX); - - float snr_est = 10.0f * log10f((0.1f + (ofdm->sig_var / ofdm->noise_var)) * ofdm_nc * ofdm_rs / 3000.0f); - float total = ofdm->frame_count * ofdm_samplesperframe; - - stats->snr_est = 0.9f * stats->snr_est + 0.1f * snr_est; - stats->sync = ((ofdm->sync_state == synced) || (ofdm->sync_state == trial)); - stats->foff = ofdm->foff_est_hz; - stats->rx_timing = ofdm->timing_est; - stats->clock_offset = 0; - - if (total != 0.0f) { - stats->clock_offset = ofdm->clock_offset_counter / total; - } - - stats->sync_metric = ofdm->timing_mx; - - assert(ofdm_rowsperframe < MODEM_STATS_NR_MAX); - stats->nr = ofdm_rowsperframe; - - for (c = 0; c < ofdm_nc; c++) { - for (r = 0; r < ofdm_rowsperframe; r++) { - std::complex rot = ofdm->rx_np[r * c] * cmplx(ROT45); - - stats->rx_symbols[r][c].real = std::real(rot); - stats->rx_symbols[r][c].imag = std::imag(rot); - } - } -} - -/* Assemble modem frame of bits from UW, payload bits, and txt bits */ - -void ofdm_assemble_modem_frame(struct OFDM *ofdm, uint8_t modem_frame[], uint8_t payload_bits[], uint8_t txt_bits[]) { - int b, t; - - int p = 0; - int u = 0; - - for (b = 0; b < (ofdm_bitsperframe - ofdm_ntxtbits); b++) { - if ((u < ofdm_nuwbits) && (b == uw_ind[u])) { - modem_frame[b] = ofdm->tx_uw[u++]; - } else { - modem_frame[b] = payload_bits[p++]; - } - } - - assert(u == ofdm_nuwbits); - assert(p == (ofdm_bitsperframe - ofdm_nuwbits - ofdm_ntxtbits)); - - for (t = 0; b < ofdm_bitsperframe; b++, t++) { - modem_frame[b] = txt_bits[t]; - } - - assert(t == ofdm_ntxtbits); -} - -/* Assemble modem frame from UW, payload symbols, and txt bits */ - -void ofdm_assemble_modem_frame_symbols(std::complex modem_frame[], COMP payload_syms[], uint8_t txt_bits[]) { - std::complex *payload = (std::complex *) &payload_syms[0]; // complex has same memory layout - int Nsymsperframe = ofdm_bitsperframe / ofdm_bps; - int Nuwsyms = ofdm_nuwbits / ofdm_bps; - int Ntxtsyms = ofdm_ntxtbits / ofdm_bps; - int dibit[2]; - int s, t; - - int p = 0; - int u = 0; - - for (s = 0; s < Nsymsperframe - Ntxtsyms; s++) { - if ((u < Nuwsyms) && (s == uw_ind_sym[u])) { - modem_frame[s] = tx_uw_syms[u++]; - } else { - modem_frame[s] = payload[p++]; - } - } - - assert(u == Nuwsyms); - assert(p == (Nsymsperframe - Nuwsyms - Ntxtsyms)); - - for (t = 0; s < Nsymsperframe; s++, t += ofdm_bps) { - dibit[0] = txt_bits[t + 1] & 0x1; - dibit[1] = txt_bits[t] & 0x1; - modem_frame[s] = qpsk_mod(dibit); - } - - assert(t == ofdm_ntxtbits); -} - -void ofdm_disassemble_modem_frame(struct OFDM *ofdm, uint8_t rx_uw[], - COMP codeword_syms[], - float codeword_amps[], - short txt_bits[]) { - std::complex *codeword = (std::complex *) &codeword_syms[0]; // complex has same memory layout - int Nsymsperframe = ofdm_bitsperframe / ofdm_bps; - int Nuwsyms = ofdm_nuwbits / ofdm_bps; - int Ntxtsyms = ofdm_ntxtbits / ofdm_bps; - int dibit[2]; - int s, t; - - int p = 0; - int u = 0; - - for (s = 0; s < (Nsymsperframe - Ntxtsyms); s++) { - if ((u < Nuwsyms) && (s == uw_ind_sym[u])) { - qpsk_demod(ofdm->rx_np[s], dibit); - - rx_uw[ofdm_bps * u ] = dibit[1]; - rx_uw[ofdm_bps * u + 1] = dibit[0]; - u++; - } else { - codeword[p] = ofdm->rx_np[s]; - codeword_amps[p] = ofdm->rx_amp[s]; - p++; - } - } - - assert(u == Nuwsyms); - assert(p == (Nsymsperframe - Nuwsyms - Ntxtsyms)); - - for (t = 0; s < Nsymsperframe; s++, t += ofdm_bps) { - qpsk_demod(ofdm->rx_np[s], dibit); - - txt_bits[t ] = dibit[1]; - txt_bits[t + 1] = dibit[0]; - } - - assert(t == ofdm_ntxtbits); -} - - -/* - * Pseudo-random number generator that we can implement in C with - * identical results to Octave. Returns an unsigned int between 0 - * and 32767. Used for generating test frames of various lengths. - */ - -void ofdm_rand(uint16_t r[], int n) { - uint64_t seed = 1; - int i; - - for (i = 0; i < n; i++) { - seed = (1103515245l * seed + 12345) % 32768; - r[i] = seed; - } -} - - -void ofdm_generate_payload_data_bits(uint8_t payload_data_bits[], int data_bits_per_frame) { - uint16_t *r = new uint16_t[data_bits_per_frame]; - int i; - - /* construct payload data bits */ - - ofdm_rand(r, data_bits_per_frame); - - for(i=0; i 16384; - } - - delete[] r; -} - -void ofdm_print_info(struct OFDM *ofdm) { - const char *syncmode[] = { - "unsync", - "autosync", - "manualsync" - }; - - fprintf(stderr, "ofdm->foff_est_gain = %g\n", (double)ofdm->foff_est_gain); - fprintf(stderr, "ofdm->foff_est_hz = %g\n", (double)ofdm->foff_est_hz); - fprintf(stderr, "ofdm->timing_mx = %g\n", (double)ofdm->timing_mx); - fprintf(stderr, "ofdm->coarse_foff_est_hz = %g\n", (double)ofdm->coarse_foff_est_hz); - fprintf(stderr, "ofdm->timing_norm = %g\n", (double)ofdm->timing_norm); - fprintf(stderr, "ofdm->sig_var = %g\n", (double)ofdm->sig_var); - fprintf(stderr, "ofdm->noise_var = %g\n", (double)ofdm->noise_var); - fprintf(stderr, "ofdm->mean_amp = %g\n", (double)ofdm->mean_amp); - fprintf(stderr, "ofdm->clock_offset_counter = %d\n", ofdm->clock_offset_counter); - fprintf(stderr, "ofdm->verbose = %d\n", ofdm->verbose); - fprintf(stderr, "ofdm->sample_point = %d\n", ofdm->sample_point); - fprintf(stderr, "ofdm->timing_est = %d\n", ofdm->timing_est); - fprintf(stderr, "ofdm->timing_valid = %d\n", ofdm->timing_valid); - fprintf(stderr, "ofdm->nin = %d\n", ofdm->nin); - fprintf(stderr, "ofdm->uw_errors = %d\n", ofdm->uw_errors); - fprintf(stderr, "ofdm->sync_counter = %d\n", ofdm->sync_counter); - fprintf(stderr, "ofdm->frame_count = %d\n", ofdm->frame_count); - fprintf(stderr, "ofdm->sync_start = %s\n", ofdm->sync_start ? "true" : "false"); - fprintf(stderr, "ofdm->sync_end = %s\n", ofdm->sync_end ? "true" : "false"); - fprintf(stderr, "ofdm->sync_mode = %s\n", syncmode[ofdm->sync_mode]); - fprintf(stderr, "ofdm->frame_count_interleaver = %d\n", ofdm->frame_count_interleaver); - fprintf(stderr, "ofdm->timing_en = %s\n", ofdm->timing_en ? "true" : "false"); - fprintf(stderr, "ofdm->foff_est_en = %s\n", ofdm->foff_est_en ? "true" : "false"); - fprintf(stderr, "ofdm->phase_est_en = %s\n", ofdm->phase_est_en ? "true" : "false"); - fprintf(stderr, "ofdm->tx_bpf_en = %s\n", ofdm->tx_bpf_en ? "true" : "false"); -}; - -} // FreeDV diff --git a/libfreedv/ofdm_internal.h b/libfreedv/ofdm_internal.h deleted file mode 100644 index 50963d1ad..000000000 --- a/libfreedv/ofdm_internal.h +++ /dev/null @@ -1,137 +0,0 @@ -/*---------------------------------------------------------------------------*\ - - FILE........: ofdm_internal.h - AUTHORS.....: David Rowe & Steve Sampson - DATE CREATED: June 2017 - - OFDM Internal definitions. - -\*---------------------------------------------------------------------------*/ - -/* - Copyright (C) 2017 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 . - */ - -#ifndef OFDM_INTERNAL_H -#define OFDM_INTERNAL_H - -#include -#include -#include - -#include "codec2_ofdm.h" -#include "freedv_filter.h" -#include "fdv_arm_math.h" - -#ifndef M_PI -#define M_PI 3.14159265358979323846f -#endif - -#define TAU (2.0f * M_PI) -#define ROT45 float(M_PI / 4.0f) - -#define cmplx(value) (std::complex{cosf(value), sinf(value)}) -#define cmplxconj(value) (std::complex{cosf(value), -sinf(value)}) - -namespace FreeDV -{ - -/* - * Contains user configuration for OFDM modem - */ - -struct OFDM_CONFIG { - float tx_centre; /* TX Centre Audio Frequency */ - float rx_centre; /* RX Centre Audio Frequency */ - float fs; /* Sample Frequency */ - float rs; /* Modulation Symbol Rate */ - float ts; /* symbol duration */ - float tcp; /* Cyclic Prefix duration */ - float ofdm_timing_mx_thresh; - - int nc; /* Number of carriers */ - int ns; /* Number of Symbol frames */ - int bps; /* Bits per Symbol */ - int txtbits; /* number of auxiliary data bits */ - int ftwindowwidth; -}; - -struct OFDM { - std::complex *pilot_samples; - std::complex *rxbuf; - std::complex *pilots; - std::complex **rx_sym; - std::complex *rx_np; - - float *rx_amp; - float *aphase_est_pilot_log; - - uint8_t *tx_uw; - - State sync_state; - State last_sync_state; - State sync_state_interleaver; - State last_sync_state_interleaver; - - Sync sync_mode; - - struct quisk_cfFilter *ofdm_tx_bpf; - - std::complex foff_metric; - - float foff_est_gain; - float foff_est_hz; - float timing_mx; - float coarse_foff_est_hz; - float timing_norm; - float sig_var; - float noise_var; - float mean_amp; - - int clock_offset_counter; - int verbose; - int sample_point; - int timing_est; - int timing_valid; - int nin; - int uw_errors; - int sync_counter; - int frame_count; - - int frame_count_interleaver; - - bool sync_start; - bool sync_end; - bool timing_en; - bool foff_est_en; - bool phase_est_en; - bool tx_bpf_en; -}; - -/* function headers exposed for LDPC work */ - -std::complex qpsk_mod(int *); -void qpsk_demod(std::complex, int *); -void ofdm_txframe(struct OFDM *, std::complex *, std::complex []); -void ofdm_assemble_modem_frame(struct OFDM *, uint8_t [], uint8_t [], uint8_t []); -void ofdm_assemble_modem_frame_symbols(std::complex [], COMP [], uint8_t []); -void ofdm_disassemble_modem_frame(struct OFDM *, uint8_t [], COMP [], float [], short []); -void ofdm_rand(uint16_t [], int); -void ofdm_generate_payload_data_bits(uint8_t payload_data_bits[], int data_bits_per_frame); - -} // FreeDV - -#endif diff --git a/libfreedv/os.h b/libfreedv/os.h deleted file mode 100644 index 0922622e3..000000000 --- a/libfreedv/os.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Generate using fir1(47,1/2) in Octave */ - -namespace FreeDV -{ - -static const float fdmdv_os_filter[]= { - -0.0008215855034550382, - -0.0007833023901802921, - 0.001075563790768233, - 0.001199092367787555, - -0.001765309502928316, - -0.002055372115328064, - 0.002986877604154257, - 0.003462567920638414, - -0.004856570111126334, - -0.005563143845031497, - 0.007533613299748122, - 0.008563932468880897, - -0.01126857129039911, - -0.01280782411693687, - 0.01651443896361847, - 0.01894875110322284, - -0.02421604439474981, - -0.02845107338464062, - 0.03672973563400258, - 0.04542046150312214, - -0.06189165826716491, - -0.08721876380763803, - 0.1496157094199961, - 0.4497962274137046, - 0.4497962274137046, - 0.1496157094199961, - -0.08721876380763803, - -0.0618916582671649, - 0.04542046150312216, - 0.03672973563400257, - -0.02845107338464062, - -0.02421604439474984, - 0.01894875110322284, - 0.01651443896361848, - -0.01280782411693687, - -0.0112685712903991, - 0.008563932468880899, - 0.007533613299748123, - -0.005563143845031501, - -0.004856570111126346, - 0.003462567920638419, - 0.002986877604154259, - -0.002055372115328063, - -0.001765309502928318, - 0.001199092367787557, - 0.001075563790768233, - -0.0007833023901802925, - -0.0008215855034550383 -}; - -} // FreeDV diff --git a/libfreedv/phi0.cpp b/libfreedv/phi0.cpp deleted file mode 100644 index b5e18da4a..000000000 --- a/libfreedv/phi0.cpp +++ /dev/null @@ -1,223 +0,0 @@ - -// phi0.c -// -// An approximation of the function -// -// This file is generated by the gen_phi0 scritps -// Any changes should be made to that file, not this one - -#include - -#define SI16(f) ((int32_t)(f * (1<<16))) - -namespace FreeDV -{ - -float phi0( float xf ) { - - int32_t x = SI16(xf); - - if (x >= SI16(10.0f)) return(0.0f); - else { - if (x >= SI16(5.0f)) { - int i = 19 - (x >> 15); - switch (i) { - case 0: return(0.000116589f); // (9.5) - case 1: return(0.000192223f); // (9.0) - case 2: return(0.000316923f); // (8.5) - case 3: return(0.000522517f); // (8.0) - case 4: return(0.000861485f); // (7.5) - case 5: return(0.001420349f); // (7.0) - case 6: return(0.002341760f); // (6.5) - case 7: return(0.003860913f); // (6.0) - case 8: return(0.006365583f); // (5.5) - case 9: return(0.010495133f); // (5.0) - } - } - else { - if (x >= SI16(1.0f)) { - int i = 79 - (x >> 12); - switch (i) { - case 0: return(0.013903889f); // (4.9375) - case 1: return(0.014800644f); // (4.8750) - case 2: return(0.015755242f); // (4.8125) - case 3: return(0.016771414f); // (4.7500) - case 4: return(0.017853133f); // (4.6875) - case 5: return(0.019004629f); // (4.6250) - case 6: return(0.020230403f); // (4.5625) - case 7: return(0.021535250f); // (4.5000) - case 8: return(0.022924272f); // (4.4375) - case 9: return(0.024402903f); // (4.3750) - case 10: return(0.025976926f); // (4.3125) - case 11: return(0.027652501f); // (4.2500) - case 12: return(0.029436184f); // (4.1875) - case 13: return(0.031334956f); // (4.1250) - case 14: return(0.033356250f); // (4.0625) - case 15: return(0.035507982f); // (4.0000) - case 16: return(0.037798579f); // (3.9375) - case 17: return(0.040237016f); // (3.8750) - case 18: return(0.042832850f); // (3.8125) - case 19: return(0.045596260f); // (3.7500) - case 20: return(0.048538086f); // (3.6875) - case 21: return(0.051669874f); // (3.6250) - case 22: return(0.055003924f); // (3.5625) - case 23: return(0.058553339f); // (3.5000) - case 24: return(0.062332076f); // (3.4375) - case 25: return(0.066355011f); // (3.3750) - case 26: return(0.070637993f); // (3.3125) - case 27: return(0.075197917f); // (3.2500) - case 28: return(0.080052790f); // (3.1875) - case 29: return(0.085221814f); // (3.1250) - case 30: return(0.090725463f); // (3.0625) - case 31: return(0.096585578f); // (3.0000) - case 32: return(0.102825462f); // (2.9375) - case 33: return(0.109469985f); // (2.8750) - case 34: return(0.116545700f); // (2.8125) - case 35: return(0.124080967f); // (2.7500) - case 36: return(0.132106091f); // (2.6875) - case 37: return(0.140653466f); // (2.6250) - case 38: return(0.149757747f); // (2.5625) - case 39: return(0.159456024f); // (2.5000) - case 40: return(0.169788027f); // (2.4375) - case 41: return(0.180796343f); // (2.3750) - case 42: return(0.192526667f); // (2.3125) - case 43: return(0.205028078f); // (2.2500) - case 44: return(0.218353351f); // (2.1875) - case 45: return(0.232559308f); // (2.1250) - case 46: return(0.247707218f); // (2.0625) - case 47: return(0.263863255f); // (2.0000) - case 48: return(0.281099022f); // (1.9375) - case 49: return(0.299492155f); // (1.8750) - case 50: return(0.319127030f); // (1.8125) - case 51: return(0.340095582f); // (1.7500) - case 52: return(0.362498271f); // (1.6875) - case 53: return(0.386445235f); // (1.6250) - case 54: return(0.412057648f); // (1.5625) - case 55: return(0.439469363f); // (1.5000) - case 56: return(0.468828902f); // (1.4375) - case 57: return(0.500301872f); // (1.3750) - case 58: return(0.534073947f); // (1.3125) - case 59: return(0.570354566f); // (1.2500) - case 60: return(0.609381573f); // (1.1875) - case 61: return(0.651427083f); // (1.1250) - case 62: return(0.696805010f); // (1.0625) - case 63: return(0.745880827f); // (1.0000) - } - } - else { - if (x > SI16(0.007812f)) { - if (x > SI16(0.088388f)) { - if (x > SI16(0.250000f)) { - if (x > SI16(0.500000f)) { - if (x > SI16(0.707107f)) { - return(0.922449644f); - } else { - return(1.241248638f); - } - } else { - if (x > SI16(0.353553f)) { - return(1.573515241f); - } else { - return(1.912825912f); - } - } - } else { - if (x > SI16(0.125000f)) { - if (x > SI16(0.176777f)) { - return(2.255740095f); - } else { - return(2.600476919f); - } - } else { - return(2.946130351f); - } - } - } else { - if (x > SI16(0.022097f)) { - if (x > SI16(0.044194f)) { - if (x > SI16(0.062500f)) { - return(3.292243417f); - } else { - return(3.638586634f); - } - } else { - if (x > SI16(0.031250f)) { - return(3.985045009f); - } else { - return(4.331560985f); - } - } - } else { - if (x > SI16(0.011049f)) { - if (x > SI16(0.015625f)) { - return(4.678105767f); - } else { - return(5.024664952f); - } - } else { - return(5.371231340f); - } - } - } - } else { - if (x > SI16(0.000691f)) { - if (x > SI16(0.001953f)) { - if (x > SI16(0.003906f)) { - if (x > SI16(0.005524f)) { - return(5.717801329f); - } else { - return(6.064373119f); - } - } else { - if (x > SI16(0.002762f)) { - return(6.410945809f); - } else { - return(6.757518949f); - } - } - } else { - if (x > SI16(0.000977f)) { - if (x > SI16(0.001381f)) { - return(7.104092314f); - } else { - return(7.450665792f); - } - } else { - return(7.797239326f); - } - } - } else { - if (x > SI16(0.000173f)) { - if (x > SI16(0.000345f)) { - if (x > SI16(0.000488f)) { - return(8.143812888f); - } else { - return(8.490386464f); - } - } else { - if (x > SI16(0.000244f)) { - return(8.836960047f); - } else { - return(9.183533634f); - } - } - } else { - if (x > SI16(0.000086f)) { - if (x > SI16(0.000122f)) { - return(9.530107222f); - } else { - return(9.876680812f); - } - } else { - return(10.000000000f); - } - } - } - } - } - } - } - return(10.0f); -} - -} // FreeDV diff --git a/libfreedv/phi0.h b/libfreedv/phi0.h deleted file mode 100644 index e1e67d859..000000000 --- a/libfreedv/phi0.h +++ /dev/null @@ -1,11 +0,0 @@ -// phi0.h -#ifndef PHI0_H -#define PHI0_H - -namespace FreeDV { - -extern float phi0( float xf ); - -} // FreeDV - -#endif diff --git a/libfreedv/pilot_coeff.h b/libfreedv/pilot_coeff.h deleted file mode 100644 index 63320a4cb..000000000 --- a/libfreedv/pilot_coeff.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Generated by pilot_coeff_file() Octave function */ - -// const removed since this provides gain -// on the STM32F4 platform - -namespace FreeDV -{ - -#ifdef CORTEX_M4 -/* const */ float pilot_coeff[]={ -#else -const float pilot_coeff[]={ -#endif - 0.00223001, - 0.00301037, - 0.00471258, - 0.0075934, - 0.0118145, - 0.0174153, - 0.0242969, - 0.0322204, - 0.0408199, - 0.0496286, - 0.0581172, - 0.0657392, - 0.0719806, - 0.0764066, - 0.0787022, - 0.0787022, - 0.0764066, - 0.0719806, - 0.0657392, - 0.0581172, - 0.0496286, - 0.0408199, - 0.0322204, - 0.0242969, - 0.0174153, - 0.0118145, - 0.0075934, - 0.00471258, - 0.00301037, - 0.00223001 -}; - -} // FreeDV diff --git a/libfreedv/pilots_coh.h b/libfreedv/pilots_coh.h deleted file mode 100644 index 00f4816a4..000000000 --- a/libfreedv/pilots_coh.h +++ /dev/null @@ -1,11 +0,0 @@ -/* Generated by write_pilot_file() Octave function */ - -namespace FreeDV -{ - -float pilots_coh[][PILOTS_NC]={ - { 1.000000, -1.000000, 1.000000, -1.000000, 1.000000, -1.000000, -1.000000}, - { -1.000000, 1.000000, 1.000000, -1.000000, 1.000000, 1.000000, 1.000000} -}; - -} // FreeDV diff --git a/libfreedv/rn.h b/libfreedv/rn.h deleted file mode 100644 index d10c239d0..000000000 --- a/libfreedv/rn.h +++ /dev/null @@ -1,969 +0,0 @@ -/* Generated by rn_file() Octave function */ - -namespace FreeDV -{ - -const float gt_alpha5_root[]={ - 2.86997e-05, - 2.2286e-05, - 1.82863e-05, - 1.42303e-05, - 1.04905e-05, - 6.70859e-06, - 3.05918e-06, - -6.22187e-07, - -4.22748e-06, - -7.85603e-06, - -1.14317e-05, - -1.50227e-05, - -1.85712e-05, - -2.21275e-05, - -2.56455e-05, - -2.91642e-05, - -3.26453e-05, - -3.61199e-05, - -3.95556e-05, - -4.29778e-05, - -4.63581e-05, - -4.97179e-05, - -5.3032e-05, - -5.63184e-05, - -5.95548e-05, - -6.27565e-05, - -6.59032e-05, - -6.90085e-05, - -7.20538e-05, - -7.50509e-05, - -7.7983e-05, - -8.08605e-05, - -8.36678e-05, - -8.64141e-05, - -8.9085e-05, - -9.16888e-05, - -9.42119e-05, - -9.66619e-05, - -9.9026e-05, - -0.000101311, - -0.000103505, - -0.000105614, - -0.000107627, - -0.00010955, - -0.000111372, - -0.000113099, - -0.00011472, - -0.000116241, - -0.000117652, - -0.000118959, - -0.000120152, - -0.000121235, - -0.000122201, - -0.000123053, - -0.000123784, - -0.000124397, - -0.000124884, - -0.00012525, - -0.000125487, - -0.000125598, - -0.000125578, - -0.000125428, - -0.000125145, - -0.000124729, - -0.000124185, - -0.000123518, - -0.000122709, - -0.000121766, - -0.000120685, - -0.000119471, - -0.000118119, - -0.000116633, - -0.000115009, - -0.000113251, - -0.000111356, - -0.000109326, - -0.00010716, - -0.00010486, - -0.000102424, - -9.98553e-05, - -9.71528e-05, - -9.43199e-05, - -9.13551e-05, - -8.82623e-05, - -8.50404e-05, - -8.16936e-05, - -7.82211e-05, - -7.46271e-05, - -7.09109e-05, - -6.70773e-05, - -6.31256e-05, - -5.90607e-05, - -5.48823e-05, - -5.05954e-05, - -4.62001e-05, - -4.17016e-05, - -3.71002e-05, - -3.24015e-05, - -2.7606e-05, - -2.27195e-05, - -1.77428e-05, - -1.2682e-05, - -7.53795e-06, - -2.31702e-06, - 2.97965e-06, - 8.34567e-06, - 1.37796e-05, - 1.9275e-05, - 2.483e-05, - 3.04382e-05, - 3.60975e-05, - 4.18011e-05, - 4.75467e-05, - 5.33273e-05, - 5.91403e-05, - 6.49787e-05, - 7.08393e-05, - 7.67152e-05, - 8.26029e-05, - 8.84957e-05, - 9.43895e-05, - 0.000100278, - 0.000106157, - 0.00011202, - 0.000117864, - 0.000123681, - 0.000129468, - 0.000135218, - 0.000140929, - 0.000146583, - 0.000152183, - 0.000157725, - 0.000163202, - 0.000168608, - 0.000173938, - 0.000179183, - 0.00018434, - 0.0001894, - 0.00019436, - 0.000199211, - 0.000203949, - 0.000208568, - 0.000213063, - 0.000217426, - 0.000221654, - 0.00022574, - 0.000229678, - 0.000233463, - 0.000237089, - 0.000240551, - 0.000243843, - 0.000246959, - 0.000249895, - 0.000252644, - 0.000255202, - 0.000257562, - 0.000259721, - 0.000261672, - 0.000263411, - 0.000264933, - 0.000266234, - 0.000267308, - 0.000268152, - 0.00026876, - 0.000269128, - 0.000269253, - 0.000269129, - 0.000268754, - 0.000268123, - 0.000267232, - 0.000266079, - 0.000264658, - 0.000262968, - 0.000261006, - 0.000258767, - 0.000256251, - 0.000253453, - 0.000250373, - 0.000247007, - 0.000243354, - 0.000239412, - 0.00023518, - 0.000230655, - 0.000225837, - 0.000220723, - 0.000215314, - 0.000209608, - 0.000203605, - 0.000197304, - 0.000190706, - 0.000183812, - 0.000176621, - 0.000169145, - 0.000161363, - 0.000153275, - 0.000144895, - 0.000136224, - 0.000127266, - 0.00011802, - 0.000108491, - 9.8679e-05, - 8.85877e-05, - 7.82196e-05, - 6.7577e-05, - 5.66636e-05, - 4.54822e-05, - 3.40369e-05, - 2.23311e-05, - 1.03695e-05, - -1.844e-06, - -1.43041e-05, - -2.70061e-05, - -3.99444e-05, - -5.31139e-05, - -6.65082e-05, - -8.01218e-05, - -9.39481e-05, - -0.000107981, - -0.000122213, - -0.000136638, - -0.000151248, - -0.000166036, - -0.000180995, - -0.000196115, - -0.00021139, - -0.000226811, - -0.000242369, - -0.000258056, - -0.000273861, - -0.000289776, - -0.000305792, - -0.000321898, - -0.000338084, - -0.000354342, - -0.00037066, - -0.000387027, - -0.000403434, - -0.00041987, - -0.000436324, - -0.000452784, - -0.00046924, - -0.00048568, - -0.000502091, - -0.000518464, - -0.000534785, - -0.000551043, - -0.000567225, - -0.000583319, - -0.000599314, - -0.000615196, - -0.000630955, - -0.000646575, - -0.000662049, - -0.000677361, - -0.000692506, - -0.000707464, - -0.00072229, - -0.000736922, - -0.000751266, - -0.000765372, - -0.000779217, - -0.000792798, - -0.000806094, - -0.000819098, - -0.000831793, - -0.000844168, - -0.000856207, - -0.000867898, - -0.000879227, - -0.00089018, - -0.000900744, - -0.000910906, - -0.000920652, - -0.00092997, - -0.000938844, - -0.000947263, - -0.000955214, - -0.000962682, - -0.000969654, - -0.000976119, - -0.000982062, - -0.00098747, - -0.000992332, - -0.000996634, - -0.00100036, - -0.00100351, - -0.00100606, - -0.001008, - -0.00100932, - -0.00101, - -0.00101005, - -0.00100943, - -0.00100816, - -0.0010062, - -0.00100356, - -0.00100021, - -0.000996162, - -0.000991392, - -0.000985892, - -0.000979654, - -0.000972668, - -0.000964925, - -0.000956415, - -0.000947131, - -0.000937065, - -0.000926208, - -0.000914552, - -0.00090209, - -0.000888816, - -0.000874721, - -0.0008598, - -0.000844046, - -0.000827453, - -0.000810015, - -0.000791726, - -0.000772581, - -0.000752576, - -0.000731704, - -0.000709965, - -0.00068735, - -0.000663865, - -0.000639509, - -0.000614269, - -0.000588146, - -0.000561139, - -0.000533246, - -0.000504468, - -0.000474802, - -0.000444251, - -0.000412813, - -0.00038049, - -0.000347281, - -0.000313189, - -0.000278215, - -0.000242361, - -0.000205629, - -0.000168024, - -0.000129546, - -9.02024e-05, - -4.99954e-05, - -8.93026e-06, - 3.2988e-05, - 7.57537e-05, - 0.000119361, - 0.000163804, - 0.000209075, - 0.000255167, - 0.000302074, - 0.000349786, - 0.000398297, - 0.000447596, - 0.000497676, - 0.000548526, - 0.000600136, - 0.000652497, - 0.000705598, - 0.000759427, - 0.000813972, - 0.000869223, - 0.000925166, - 0.000981789, - 0.00103908, - 0.00109702, - 0.00115561, - 0.00121482, - 0.00127464, - 0.00133505, - 0.00139605, - 0.00145762, - 0.00151973, - 0.00158238, - 0.00164555, - 0.00170922, - 0.00177337, - 0.00183799, - 0.00190305, - 0.00196854, - 0.00203445, - 0.00210075, - 0.00216742, - 0.00223445, - 0.00230181, - 0.00236949, - 0.00243747, - 0.00250572, - 0.00257423, - 0.00264296, - 0.00271192, - 0.00278107, - 0.00285039, - 0.00291986, - 0.00298947, - 0.00305918, - 0.00312898, - 0.00319884, - 0.00326874, - 0.00333866, - 0.00340857, - 0.00347846, - 0.00354831, - 0.00361808, - 0.00368775, - 0.00375731, - 0.00382673, - 0.00389599, - 0.00396506, - 0.00403393, - 0.00410256, - 0.00417094, - 0.00423904, - 0.00430684, - 0.00437431, - 0.00444144, - 0.0045082, - 0.00457457, - 0.00464052, - 0.00470603, - 0.00477108, - 0.00483565, - 0.00489972, - 0.00496325, - 0.00502623, - 0.00508865, - 0.00515046, - 0.00521166, - 0.00527223, - 0.00533213, - 0.00539135, - 0.00544987, - 0.00550766, - 0.00556472, - 0.005621, - 0.00567651, - 0.00573121, - 0.00578508, - 0.00583811, - 0.00589028, - 0.00594157, - 0.00599196, - 0.00604143, - 0.00608996, - 0.00613754, - 0.00618415, - 0.00622977, - 0.00627439, - 0.00631798, - 0.00636054, - 0.00640204, - 0.0064425, - 0.00648186, - 0.00652009, - 0.00655722, - 0.00659322, - 0.00662808, - 0.00666179, - 0.00669433, - 0.00672571, - 0.00675589, - 0.00678488, - 0.00681266, - 0.00683921, - 0.00686454, - 0.00688863, - 0.00691147, - 0.00693305, - 0.00695336, - 0.0069724, - 0.00699016, - 0.00700663, - 0.00702181, - 0.00703569, - 0.00704826, - 0.00705952, - 0.00706947, - 0.00707809, - 0.0070854, - 0.00709138, - 0.00709604, - 0.00709937, - 0.00710136, - 0.00710203, - 0.00710136, - 0.00709937, - 0.00709604, - 0.00709138, - 0.0070854, - 0.00707809, - 0.00706947, - 0.00705952, - 0.00704826, - 0.00703569, - 0.00702181, - 0.00700663, - 0.00699016, - 0.0069724, - 0.00695336, - 0.00693305, - 0.00691147, - 0.00688863, - 0.00686454, - 0.00683921, - 0.00681266, - 0.00678488, - 0.00675589, - 0.00672571, - 0.00669433, - 0.00666179, - 0.00662808, - 0.00659322, - 0.00655722, - 0.00652009, - 0.00648186, - 0.0064425, - 0.00640204, - 0.00636054, - 0.00631798, - 0.00627439, - 0.00622977, - 0.00618415, - 0.00613754, - 0.00608996, - 0.00604143, - 0.00599196, - 0.00594157, - 0.00589028, - 0.00583811, - 0.00578508, - 0.00573121, - 0.00567651, - 0.005621, - 0.00556472, - 0.00550766, - 0.00544987, - 0.00539135, - 0.00533213, - 0.00527223, - 0.00521166, - 0.00515046, - 0.00508865, - 0.00502623, - 0.00496325, - 0.00489972, - 0.00483565, - 0.00477108, - 0.00470603, - 0.00464052, - 0.00457457, - 0.0045082, - 0.00444144, - 0.00437431, - 0.00430684, - 0.00423904, - 0.00417094, - 0.00410256, - 0.00403393, - 0.00396506, - 0.00389599, - 0.00382673, - 0.00375731, - 0.00368775, - 0.00361808, - 0.00354831, - 0.00347846, - 0.00340857, - 0.00333866, - 0.00326874, - 0.00319884, - 0.00312898, - 0.00305918, - 0.00298947, - 0.00291986, - 0.00285039, - 0.00278107, - 0.00271192, - 0.00264296, - 0.00257423, - 0.00250572, - 0.00243747, - 0.00236949, - 0.00230181, - 0.00223445, - 0.00216742, - 0.00210075, - 0.00203445, - 0.00196854, - 0.00190305, - 0.00183799, - 0.00177337, - 0.00170922, - 0.00164555, - 0.00158238, - 0.00151973, - 0.00145762, - 0.00139605, - 0.00133505, - 0.00127464, - 0.00121482, - 0.00115561, - 0.00109702, - 0.00103908, - 0.000981789, - 0.000925166, - 0.000869223, - 0.000813972, - 0.000759427, - 0.000705598, - 0.000652497, - 0.000600136, - 0.000548526, - 0.000497676, - 0.000447596, - 0.000398297, - 0.000349786, - 0.000302074, - 0.000255167, - 0.000209075, - 0.000163804, - 0.000119361, - 7.57537e-05, - 3.2988e-05, - -8.93026e-06, - -4.99954e-05, - -9.02024e-05, - -0.000129546, - -0.000168024, - -0.000205629, - -0.000242361, - -0.000278215, - -0.000313189, - -0.000347281, - -0.00038049, - -0.000412813, - -0.000444251, - -0.000474802, - -0.000504468, - -0.000533246, - -0.000561139, - -0.000588146, - -0.000614269, - -0.000639509, - -0.000663865, - -0.00068735, - -0.000709965, - -0.000731704, - -0.000752576, - -0.000772581, - -0.000791726, - -0.000810015, - -0.000827453, - -0.000844046, - -0.0008598, - -0.000874721, - -0.000888816, - -0.00090209, - -0.000914552, - -0.000926208, - -0.000937065, - -0.000947131, - -0.000956415, - -0.000964925, - -0.000972668, - -0.000979654, - -0.000985892, - -0.000991392, - -0.000996162, - -0.00100021, - -0.00100356, - -0.0010062, - -0.00100816, - -0.00100943, - -0.00101005, - -0.00101, - -0.00100932, - -0.001008, - -0.00100606, - -0.00100351, - -0.00100036, - -0.000996634, - -0.000992332, - -0.00098747, - -0.000982062, - -0.000976119, - -0.000969654, - -0.000962682, - -0.000955214, - -0.000947263, - -0.000938844, - -0.00092997, - -0.000920652, - -0.000910906, - -0.000900744, - -0.00089018, - -0.000879227, - -0.000867898, - -0.000856207, - -0.000844168, - -0.000831793, - -0.000819098, - -0.000806094, - -0.000792798, - -0.000779217, - -0.000765372, - -0.000751266, - -0.000736922, - -0.00072229, - -0.000707464, - -0.000692506, - -0.000677361, - -0.000662049, - -0.000646575, - -0.000630955, - -0.000615196, - -0.000599314, - -0.000583319, - -0.000567225, - -0.000551043, - -0.000534785, - -0.000518464, - -0.000502091, - -0.00048568, - -0.00046924, - -0.000452784, - -0.000436324, - -0.00041987, - -0.000403434, - -0.000387027, - -0.00037066, - -0.000354342, - -0.000338084, - -0.000321898, - -0.000305792, - -0.000289776, - -0.000273861, - -0.000258056, - -0.000242369, - -0.000226811, - -0.00021139, - -0.000196115, - -0.000180995, - -0.000166036, - -0.000151248, - -0.000136638, - -0.000122213, - -0.000107981, - -9.39481e-05, - -8.01218e-05, - -6.65082e-05, - -5.31139e-05, - -3.99444e-05, - -2.70061e-05, - -1.43041e-05, - -1.844e-06, - 1.03695e-05, - 2.23311e-05, - 3.40369e-05, - 4.54822e-05, - 5.66636e-05, - 6.7577e-05, - 7.82196e-05, - 8.85877e-05, - 9.8679e-05, - 0.000108491, - 0.00011802, - 0.000127266, - 0.000136224, - 0.000144895, - 0.000153275, - 0.000161363, - 0.000169145, - 0.000176621, - 0.000183812, - 0.000190706, - 0.000197304, - 0.000203605, - 0.000209608, - 0.000215314, - 0.000220723, - 0.000225837, - 0.000230655, - 0.00023518, - 0.000239412, - 0.000243354, - 0.000247007, - 0.000250373, - 0.000253453, - 0.000256251, - 0.000258767, - 0.000261006, - 0.000262968, - 0.000264658, - 0.000266079, - 0.000267232, - 0.000268123, - 0.000268754, - 0.000269129, - 0.000269253, - 0.000269128, - 0.00026876, - 0.000268152, - 0.000267308, - 0.000266234, - 0.000264933, - 0.000263411, - 0.000261672, - 0.000259721, - 0.000257562, - 0.000255202, - 0.000252644, - 0.000249895, - 0.000246959, - 0.000243843, - 0.000240551, - 0.000237089, - 0.000233463, - 0.000229678, - 0.00022574, - 0.000221654, - 0.000217426, - 0.000213063, - 0.000208568, - 0.000203949, - 0.000199211, - 0.00019436, - 0.0001894, - 0.00018434, - 0.000179183, - 0.000173938, - 0.000168608, - 0.000163202, - 0.000157725, - 0.000152183, - 0.000146583, - 0.000140929, - 0.000135218, - 0.000129468, - 0.000123681, - 0.000117864, - 0.00011202, - 0.000106157, - 0.000100278, - 9.43895e-05, - 8.84957e-05, - 8.26029e-05, - 7.67152e-05, - 7.08393e-05, - 6.49787e-05, - 5.91403e-05, - 5.33273e-05, - 4.75467e-05, - 4.18011e-05, - 3.60975e-05, - 3.04382e-05, - 2.483e-05, - 1.9275e-05, - 1.37796e-05, - 8.34567e-06, - 2.97965e-06, - -2.31702e-06, - -7.53795e-06, - -1.2682e-05, - -1.77428e-05, - -2.27195e-05, - -2.7606e-05, - -3.24015e-05, - -3.71002e-05, - -4.17016e-05, - -4.62001e-05, - -5.05954e-05, - -5.48823e-05, - -5.90607e-05, - -6.31256e-05, - -6.70773e-05, - -7.09109e-05, - -7.46271e-05, - -7.82211e-05, - -8.16936e-05, - -8.50404e-05, - -8.82623e-05, - -9.13551e-05, - -9.43199e-05, - -9.71528e-05, - -9.98553e-05, - -0.000102424, - -0.00010486, - -0.00010716, - -0.000109326, - -0.000111356, - -0.000113251, - -0.000115009, - -0.000116633, - -0.000118119, - -0.000119471, - -0.000120685, - -0.000121766, - -0.000122709, - -0.000123518, - -0.000124185, - -0.000124729, - -0.000125145, - -0.000125428, - -0.000125578, - -0.000125598, - -0.000125487, - -0.00012525, - -0.000124884, - -0.000124397, - -0.000123784, - -0.000123053, - -0.000122201, - -0.000121235, - -0.000120152, - -0.000118959, - -0.000117652, - -0.000116241, - -0.00011472, - -0.000113099, - -0.000111372, - -0.00010955, - -0.000107627, - -0.000105614, - -0.000103505, - -0.000101311, - -9.9026e-05, - -9.66619e-05, - -9.42119e-05, - -9.16888e-05, - -8.9085e-05, - -8.64141e-05, - -8.36678e-05, - -8.08605e-05, - -7.7983e-05, - -7.50509e-05, - -7.20538e-05, - -6.90085e-05, - -6.59032e-05, - -6.27565e-05, - -5.95548e-05, - -5.63184e-05, - -5.3032e-05, - -4.97179e-05, - -4.63581e-05, - -4.29778e-05, - -3.95556e-05, - -3.61199e-05, - -3.26453e-05, - -2.91642e-05, - -2.56455e-05, - -2.21275e-05, - -1.85712e-05, - -1.50227e-05, - -1.14317e-05, - -7.85603e-06, - -4.22748e-06, - -6.22187e-07, - 3.05918e-06, - 6.70859e-06, - 1.04905e-05, - 1.42303e-05, - 1.82863e-05, - 2.2286e-05 -}; - -} // FreeDV diff --git a/libfreedv/rn_coh.h b/libfreedv/rn_coh.h deleted file mode 100644 index 53d4598bf..000000000 --- a/libfreedv/rn_coh.h +++ /dev/null @@ -1,609 +0,0 @@ -/* Generated by rn_file() Octave function */ - -namespace FreeDV -{ - -const float gt_alpha5_root_coh[]={ - 4.05576e-05, - 2.58255e-05, - 1.58964e-05, - 5.78773e-06, - -3.71244e-06, - -1.33229e-05, - -2.2664e-05, - -3.20611e-05, - -4.12734e-05, - -5.04935e-05, - -5.9545e-05, - -6.85565e-05, - -7.73902e-05, - -8.6137e-05, - -9.46835e-05, - -0.000103097, - -0.000111281, - -0.000119289, - -0.000127034, - -0.000134559, - -0.000141789, - -0.000148756, - -0.000155393, - -0.000161723, - -0.000167689, - -0.000173315, - -0.00017854, - -0.000183382, - -0.000187794, - -0.000191793, - -0.000195333, - -0.000198429, - -0.000201038, - -0.000203173, - -0.000204797, - -0.000205922, - -0.000206515, - -0.00020659, - -0.000206117, - -0.000205109, - -0.000203541, - -0.000201427, - -0.000198743, - -0.000195505, - -0.000191693, - -0.000187324, - -0.000182382, - -0.000176885, - -0.000170822, - -0.00016421, - -0.000157041, - -0.000149335, - -0.000141089, - -0.000132323, - -0.000123038, - -0.000113258, - -0.000102985, - -9.22439e-05, - -8.10442e-05, - -6.94109e-05, - -5.73536e-05, - -4.49012e-05, - -3.20661e-05, - -1.88794e-05, - -5.35615e-06, - 8.47105e-06, - 2.25833e-05, - 3.69472e-05, - 5.15418e-05, - 6.63317e-05, - 8.12934e-05, - 9.63895e-05, - 0.000111594, - 0.000126869, - 0.000142183, - 0.000157497, - 0.000172781, - 0.000187996, - 0.000203111, - 0.000218088, - 0.000232892, - 0.000247474, - 0.000261806, - 0.000275847, - 0.000289559, - 0.000302903, - 0.000315839, - 0.00032833, - 0.000340339, - 0.000351824, - 0.000362751, - 0.00037308, - 0.000382774, - 0.000391795, - 0.000400108, - 0.000407675, - 0.000414464, - 0.000420437, - 0.000425565, - 0.000429812, - 0.000433151, - 0.000435544, - 0.000436975, - 0.000437401, - 0.000436865, - 0.000435237, - 0.00043246, - 0.000428592, - 0.000423608, - 0.000417497, - 0.00041024, - 0.000401823, - 0.000392231, - 0.000381449, - 0.000369471, - 0.000356284, - 0.000341885, - 0.000326267, - 0.00030943, - 0.000291373, - 0.000272099, - 0.000251612, - 0.000229921, - 0.000207034, - 0.000182964, - 0.000157726, - 0.000131338, - 0.000103821, - 7.51956e-05, - 4.54842e-05, - 1.4721e-05, - -1.7067e-05, - -4.98479e-05, - -8.35883e-05, - -0.000118248, - -0.00015379, - -0.000190167, - -0.000227336, - -0.000265248, - -0.000303856, - -0.000343104, - -0.000382942, - -0.00042331, - -0.000464152, - -0.000505403, - -0.000547003, - -0.000588883, - -0.000630979, - -0.000673218, - -0.000715533, - -0.000757849, - -0.000800092, - -0.000842187, - -0.000884054, - -0.000925613, - -0.000966788, - -0.00100749, - -0.00104765, - -0.00108717, - -0.00112597, - -0.00116397, - -0.00120108, - -0.0012372, - -0.00127227, - -0.00130617, - -0.00133884, - -0.00137017, - -0.00140008, - -0.00142848, - -0.00145528, - -0.0014804, - -0.00150374, - -0.00152522, - -0.00154475, - -0.00156225, - -0.00157763, - -0.00159081, - -0.00160171, - -0.00161024, - -0.00161633, - -0.0016199, - -0.00162088, - -0.00161917, - -0.00161472, - -0.00160744, - -0.00159729, - -0.00158419, - -0.00156807, - -0.00154888, - -0.00152655, - -0.00150103, - -0.00147227, - -0.00144021, - -0.00140482, - -0.00136604, - -0.00132384, - -0.00127818, - -0.00122903, - -0.00117635, - -0.00112013, - -0.00106033, - -0.000996946, - -0.000929956, - -0.000859348, - -0.000785117, - -0.000707261, - -0.000625779, - -0.00054068, - -0.000451952, - -0.000359651, - -0.000263788, - -0.00016436, - -6.13947e-05, - 4.5076e-05, - 0.000155016, - 0.000268384, - 0.000385134, - 0.000505217, - 0.000628582, - 0.000755171, - 0.000884923, - 0.00101777, - 0.00115366, - 0.00129249, - 0.00143421, - 0.00157873, - 0.00172596, - 0.00187583, - 0.00202822, - 0.00218306, - 0.00234023, - 0.00249965, - 0.00266119, - 0.00282475, - 0.00299023, - 0.00315749, - 0.00332643, - 0.00349691, - 0.00366882, - 0.00384202, - 0.00401639, - 0.0041918, - 0.0043681, - 0.00454516, - 0.00472285, - 0.00490101, - 0.00507951, - 0.00525821, - 0.00543695, - 0.0056156, - 0.005794, - 0.00597201, - 0.00614947, - 0.00632623, - 0.00650216, - 0.00667708, - 0.00685086, - 0.00702335, - 0.00719439, - 0.00736383, - 0.00753153, - 0.00769734, - 0.00786111, - 0.00802269, - 0.00818194, - 0.00833872, - 0.00849289, - 0.0086443, - 0.00879283, - 0.00893832, - 0.00908066, - 0.00921971, - 0.00935534, - 0.00948743, - 0.00961585, - 0.00974049, - 0.00986123, - 0.00997795, - 0.0100905, - 0.0101989, - 0.0103029, - 0.0104025, - 0.0104976, - 0.0105881, - 0.0106738, - 0.0107548, - 0.010831, - 0.0109022, - 0.0109684, - 0.0110295, - 0.0110855, - 0.0111364, - 0.011182, - 0.0112224, - 0.0112575, - 0.0112872, - 0.0113115, - 0.0113305, - 0.0113441, - 0.0113522, - 0.0113549, - 0.0113522, - 0.0113441, - 0.0113305, - 0.0113115, - 0.0112872, - 0.0112575, - 0.0112224, - 0.011182, - 0.0111364, - 0.0110855, - 0.0110295, - 0.0109684, - 0.0109022, - 0.010831, - 0.0107548, - 0.0106738, - 0.0105881, - 0.0104976, - 0.0104025, - 0.0103029, - 0.0101989, - 0.0100905, - 0.00997795, - 0.00986123, - 0.00974049, - 0.00961585, - 0.00948743, - 0.00935534, - 0.00921971, - 0.00908066, - 0.00893832, - 0.00879283, - 0.0086443, - 0.00849289, - 0.00833872, - 0.00818194, - 0.00802269, - 0.00786111, - 0.00769734, - 0.00753153, - 0.00736383, - 0.00719439, - 0.00702335, - 0.00685086, - 0.00667708, - 0.00650216, - 0.00632623, - 0.00614947, - 0.00597201, - 0.005794, - 0.0056156, - 0.00543695, - 0.00525821, - 0.00507951, - 0.00490101, - 0.00472285, - 0.00454516, - 0.0043681, - 0.0041918, - 0.00401639, - 0.00384202, - 0.00366882, - 0.00349691, - 0.00332643, - 0.00315749, - 0.00299023, - 0.00282475, - 0.00266119, - 0.00249965, - 0.00234023, - 0.00218306, - 0.00202822, - 0.00187583, - 0.00172596, - 0.00157873, - 0.00143421, - 0.00129249, - 0.00115366, - 0.00101777, - 0.000884923, - 0.000755171, - 0.000628582, - 0.000505217, - 0.000385134, - 0.000268384, - 0.000155016, - 4.5076e-05, - -6.13947e-05, - -0.00016436, - -0.000263788, - -0.000359651, - -0.000451952, - -0.00054068, - -0.000625779, - -0.000707261, - -0.000785117, - -0.000859348, - -0.000929956, - -0.000996946, - -0.00106033, - -0.00112013, - -0.00117635, - -0.00122903, - -0.00127818, - -0.00132384, - -0.00136604, - -0.00140482, - -0.00144021, - -0.00147227, - -0.00150103, - -0.00152655, - -0.00154888, - -0.00156807, - -0.00158419, - -0.00159729, - -0.00160744, - -0.00161472, - -0.00161917, - -0.00162088, - -0.0016199, - -0.00161633, - -0.00161024, - -0.00160171, - -0.00159081, - -0.00157763, - -0.00156225, - -0.00154475, - -0.00152522, - -0.00150374, - -0.0014804, - -0.00145528, - -0.00142848, - -0.00140008, - -0.00137017, - -0.00133884, - -0.00130617, - -0.00127227, - -0.0012372, - -0.00120108, - -0.00116397, - -0.00112597, - -0.00108717, - -0.00104765, - -0.00100749, - -0.000966788, - -0.000925613, - -0.000884054, - -0.000842187, - -0.000800092, - -0.000757849, - -0.000715533, - -0.000673218, - -0.000630979, - -0.000588883, - -0.000547003, - -0.000505403, - -0.000464152, - -0.00042331, - -0.000382942, - -0.000343104, - -0.000303856, - -0.000265248, - -0.000227336, - -0.000190167, - -0.00015379, - -0.000118248, - -8.35883e-05, - -4.98479e-05, - -1.7067e-05, - 1.4721e-05, - 4.54842e-05, - 7.51956e-05, - 0.000103821, - 0.000131338, - 0.000157726, - 0.000182964, - 0.000207034, - 0.000229921, - 0.000251612, - 0.000272099, - 0.000291373, - 0.00030943, - 0.000326267, - 0.000341885, - 0.000356284, - 0.000369471, - 0.000381449, - 0.000392231, - 0.000401823, - 0.00041024, - 0.000417497, - 0.000423608, - 0.000428592, - 0.00043246, - 0.000435237, - 0.000436865, - 0.000437401, - 0.000436975, - 0.000435544, - 0.000433151, - 0.000429812, - 0.000425565, - 0.000420437, - 0.000414464, - 0.000407675, - 0.000400108, - 0.000391795, - 0.000382774, - 0.00037308, - 0.000362751, - 0.000351824, - 0.000340339, - 0.00032833, - 0.000315839, - 0.000302903, - 0.000289559, - 0.000275847, - 0.000261806, - 0.000247474, - 0.000232892, - 0.000218088, - 0.000203111, - 0.000187996, - 0.000172781, - 0.000157497, - 0.000142183, - 0.000126869, - 0.000111594, - 9.63895e-05, - 8.12934e-05, - 6.63317e-05, - 5.15418e-05, - 3.69472e-05, - 2.25833e-05, - 8.47105e-06, - -5.35615e-06, - -1.88794e-05, - -3.20661e-05, - -4.49012e-05, - -5.73536e-05, - -6.94109e-05, - -8.10442e-05, - -9.22439e-05, - -0.000102985, - -0.000113258, - -0.000123038, - -0.000132323, - -0.000141089, - -0.000149335, - -0.000157041, - -0.00016421, - -0.000170822, - -0.000176885, - -0.000182382, - -0.000187324, - -0.000191693, - -0.000195505, - -0.000198743, - -0.000201427, - -0.000203541, - -0.000205109, - -0.000206117, - -0.00020659, - -0.000206515, - -0.000205922, - -0.000204797, - -0.000203173, - -0.000201038, - -0.000198429, - -0.000195333, - -0.000191793, - -0.000187794, - -0.000183382, - -0.00017854, - -0.000173315, - -0.000167689, - -0.000161723, - -0.000155393, - -0.000148756, - -0.000141789, - -0.000134559, - -0.000127034, - -0.000119289, - -0.000111281, - -0.000103097, - -9.46835e-05, - -8.6137e-05, - -7.73902e-05, - -6.85565e-05, - -5.9545e-05, - -5.04935e-05, - -4.12734e-05, - -3.20611e-05, - -2.2664e-05, - -1.33229e-05, - -3.71244e-06, - 5.78773e-06, - 1.58964e-05, - 2.58255e-05 -}; - -} // FreeDV diff --git a/libfreedv/rxdec_coeff.h b/libfreedv/rxdec_coeff.h deleted file mode 100644 index e0600cd71..000000000 --- a/libfreedv/rxdec_coeff.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Generated by rxdec_file() Octave function */ - -namespace FreeDV -{ - -const float rxdec_coeff[]={ - -0.00125472, - -0.00204605, - -0.0019897, - 0.000163906, - 0.00490937, - 0.00986375, - 0.0096718, - -0.000480351, - -0.019311, - -0.0361822, - -0.0341251, - 0.000827866, - 0.0690577, - 0.152812, - 0.222115, - 0.249004, - 0.222115, - 0.152812, - 0.0690577, - 0.000827866, - -0.0341251, - -0.0361822, - -0.019311, - -0.000480351, - 0.0096718, - 0.00986375, - 0.00490937, - 0.000163906, - -0.0019897, - -0.00204605, - -0.00125472 -}; - -} // FreeDV diff --git a/libfreedv/test_bits.h b/libfreedv/test_bits.h deleted file mode 100644 index 861add362..000000000 --- a/libfreedv/test_bits.h +++ /dev/null @@ -1,170 +0,0 @@ -/* Generated by test_bits_file() Octave function */ - -namespace FreeDV -{ - -const int test_bits[]={ - 0, - 1, - 1, - 0, - 0, - 0, - 1, - 1, - 0, - 0, - 1, - 0, - 1, - 0, - 0, - 1, - 0, - 1, - 1, - 0, - 0, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 0, - 1, - 1, - 0, - 0, - 1, - 1, - 1, - 0, - 1, - 1, - 0, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 1, - 0, - 0, - 1, - 1, - 1, - 0, - 0, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 0, - 1, - 1, - 1, - 0, - 0, - 1, - 1, - 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 1, - 1, - 0, - 1, - 0, - 0, - 0, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 0, - 1, - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 0, - 1, - 1, - 0, - 0, - 0, - 1, - 0, - 1, - 1, - 1, - 0, - 1 -}; - -} // FreeDV - diff --git a/libfreedv/test_bits_coh.h b/libfreedv/test_bits_coh.h deleted file mode 100644 index e80183b6f..000000000 --- a/libfreedv/test_bits_coh.h +++ /dev/null @@ -1,569 +0,0 @@ -/* Generated by test_bits_coh_file() Octave function */ - -namespace FreeDV -{ - -const int test_bits_coh[]={ - 0, - 1, - 1, - 0, - 0, - 0, - 1, - 1, - 0, - 0, - 1, - 0, - 1, - 0, - 0, - 1, - 0, - 1, - 1, - 0, - 0, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 0, - 1, - 1, - 0, - 0, - 1, - 1, - 1, - 0, - 1, - 1, - 0, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 1, - 0, - 0, - 1, - 1, - 1, - 0, - 0, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 0, - 1, - 1, - 1, - 0, - 0, - 1, - 1, - 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 1, - 1, - 0, - 1, - 0, - 0, - 0, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 0, - 1, - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 0, - 1, - 1, - 0, - 0, - 0, - 1, - 0, - 1, - 1, - 1, - 0, - 1, - 1, - 1, - 0, - 1, - 0, - 1, - 0, - 1, - 0, - 0, - 1, - 1, - 0, - 1, - 0, - 1, - 1, - 0, - 0, - 0, - 1, - 0, - 1, - 1, - 1, - 0, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 1, - 1, - 0, - 0, - 0, - 1, - 1, - 0, - 0, - 1, - 1, - 1, - 0, - 1, - 1, - 0, - 1, - 0, - 1, - 0, - 0, - 1, - 0, - 1, - 1, - 1, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 0, - 1, - 0, - 0, - 0, - 1, - 1, - 1, - 0, - 1, - 1, - 0, - 1, - 0, - 0, - 0, - 1, - 1, - 1, - 0, - 0, - 1, - 1, - 0, - 1, - 0, - 0, - 1, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 1, - 0, - 1, - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 1, - 0, - 1, - 0, - 0, - 0, - 1, - 1, - 1, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 1, - 1, - 0, - 0, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 1, - 0, - 1, - 0, - 1, - 0, - 1, - 1, - 0, - 1, - 0, - 1, - 1, - 1, - 0, - 0, - 1, - 1, - 0, - 1, - 0, - 1, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 1, - 1, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 1, - 0, - 0, - 1, - 1, - 1, - 0, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 0, - 1, - 0, - 0, - 1, - 1, - 0, - 1, - 1, - 0, - 1, - 1, - 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 1, - 1, - 0, - 1, - 1, - 0, - 1, - 0, - 1, - 0, - 1, - 1, - 1, - 0, - 1, - 1, - 0, - 1, - 1, - 1, - 1, - 0, - 1, - 1, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 1, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 0, - 0, - 1, - 0, - 1, - 0, - 1, - 1, - 1, - 1, - 1, - 0, - 1, - 1, - 1, - 0, - 0, - 0, - 1, - 0, - 1, - 1, - 1, - 1, - 1, - 0, - 1, - 1, - 0, - 1, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 0, - 1, - 0, - 1, - 1, - 0, - 0, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 0, - 1, - 1, - 1, - 1, - 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 1, - 1, - 1, - 0 -}; - -} // FreeDV diff --git a/plugins/channelrx/demodfreedv/CMakeLists.txt b/plugins/channelrx/demodfreedv/CMakeLists.txt index b9d90b794..4b756f313 100644 --- a/plugins/channelrx/demodfreedv/CMakeLists.txt +++ b/plugins/channelrx/demodfreedv/CMakeLists.txt @@ -13,23 +13,20 @@ set(freedv_HEADERS ) include_directories( - ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client - ${CMAKE_SOURCE_DIR}/libfreedv - ${CODEC2_INCLUDE_DIR} + ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${CODEC2_INCLUDE_DIR} ) if(NOT SERVER_MODE) set(freedv_SOURCES ${freedv_SOURCES} freedvdemodgui.cpp - - freedvdemodgui.ui + freedvdemodgui.ui ) set(freedv_HEADERS ${freedv_HEADERS} freedvdemodgui.h ) - set(TARGET_NAME demodfreedv) set(TARGET_LIB "Qt5::Widgets") set(TARGET_LIB_GUI "sdrgui") @@ -50,13 +47,12 @@ if(ENABLE_EXTERNAL_LIBRARIES) endif() target_link_libraries(${TARGET_NAME} - Qt5::Core - ${TARGET_LIB} + Qt5::Core + ${TARGET_LIB} sdrbase ${TARGET_LIB_GUI} - swagger - freedv - ${CODEC2_LIBRARIES} + swagger + ${CODEC2_LIBRARIES} ) install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER}) diff --git a/plugins/channelrx/demodfreedv/freedvdemod.cpp b/plugins/channelrx/demodfreedv/freedvdemod.cpp index ce0774294..3ee1c62c3 100644 --- a/plugins/channelrx/demodfreedv/freedvdemod.cpp +++ b/plugins/channelrx/demodfreedv/freedvdemod.cpp @@ -23,7 +23,8 @@ #include #include -#include "libfreedv.h" +#include "codec2/freedv_api.h" +#include "codec2/modem_stats.h" #include "SWGChannelSettings.h" #include "SWGFreeDVDemodSettings.h" @@ -68,12 +69,12 @@ void FreeDVDemod::FreeDVStats::init() m_fps = 1; } -void FreeDVDemod::FreeDVStats::collect(struct FreeDV::freedv *freeDV) +void FreeDVDemod::FreeDVStats::collect(struct freedv *freeDV) { - struct FreeDV::MODEM_STATS stats; + struct MODEM_STATS stats; - FreeDV::freedv_get_modem_extended_stats(freeDV, &stats); - m_totalBitErrors = FreeDV::freedv_get_total_bit_errors(freeDV); + freedv_get_modem_extended_stats(freeDV, &stats); + m_totalBitErrors = freedv_get_total_bit_errors(freeDV); m_clockOffset = stats.clock_offset; m_freqOffset = stats.foff; m_syncMetric = stats.sync_metric; @@ -404,7 +405,7 @@ bool FreeDVDemod::handleMessage(const Message& cmd) { qDebug("FreeDVDemod::handleMessage: MsgResyncFreeDVDemod"); m_settingsMutex.lock(); - FreeDV::freedv_set_sync(m_freeDV, FreeDV::unsync); + freedv_set_sync(m_freeDV, FREEDV_SYNC_UNSYNC); m_settingsMutex.unlock(); return true; } @@ -463,7 +464,7 @@ void FreeDVDemod::pushSampleToDV(int16_t sample) if (m_iModem == m_nin) { - int nout = FreeDV::freedv_rx(m_freeDV, m_speechOut, m_modIn); + int nout = freedv_rx(m_freeDV, m_speechOut, m_modIn); m_freeDVStats.collect(m_freeDV); m_freeDVSNR.accumulate(m_freeDVStats.m_snrEst); @@ -583,7 +584,7 @@ void FreeDVDemod::applyFreeDVMode(FreeDVDemodSettings::FreeDVMode mode) // FreeDV object if (m_freeDV) { - FreeDV::freedv_close(m_freeDV); + freedv_close(m_freeDV); } int fdv_mode = -1; @@ -610,32 +611,32 @@ void FreeDVDemod::applyFreeDVMode(FreeDVDemodSettings::FreeDVMode mode) if (fdv_mode == FREEDV_MODE_700D) { - struct FreeDV::freedv_advanced adv; + struct freedv_advanced adv; adv.interleave_frames = 1; - m_freeDV = FreeDV::freedv_open_advanced(fdv_mode, &adv); + m_freeDV = freedv_open_advanced(fdv_mode, &adv); } else { - m_freeDV = FreeDV::freedv_open(fdv_mode); + m_freeDV = freedv_open(fdv_mode); } if (m_freeDV) { - FreeDV::freedv_set_test_frames(m_freeDV, 0); - FreeDV::freedv_set_snr_squelch_thresh(m_freeDV, -100.0); - FreeDV::freedv_set_squelch_en(m_freeDV, 0); - FreeDV::freedv_set_clip(m_freeDV, 0); - FreeDV::freedv_set_ext_vco(m_freeDV, 0); - FreeDV::freedv_set_sync(m_freeDV, FreeDV::manualsync); + freedv_set_test_frames(m_freeDV, 0); + freedv_set_snr_squelch_thresh(m_freeDV, -100.0); + freedv_set_squelch_en(m_freeDV, 0); + freedv_set_clip(m_freeDV, 0); + freedv_set_ext_vco(m_freeDV, 0); + freedv_set_sync(m_freeDV, FREEDV_SYNC_MANUAL); - FreeDV::freedv_set_callback_txt(m_freeDV, nullptr, nullptr, nullptr); - FreeDV::freedv_set_callback_protocol(m_freeDV, nullptr, nullptr, nullptr); - FreeDV::freedv_set_callback_data(m_freeDV, nullptr, nullptr, nullptr); + freedv_set_callback_txt(m_freeDV, nullptr, nullptr, nullptr); + freedv_set_callback_protocol(m_freeDV, nullptr, nullptr, nullptr); + freedv_set_callback_data(m_freeDV, nullptr, nullptr, nullptr); - int nSpeechSamples = FreeDV::freedv_get_n_speech_samples(m_freeDV); - int nMaxModemSamples = FreeDV::freedv_get_n_max_modem_samples(m_freeDV); - int Fs = FreeDV::freedv_get_modem_sample_rate(m_freeDV); - int Rs = FreeDV::freedv_get_modem_symbol_rate(m_freeDV); + int nSpeechSamples = freedv_get_n_speech_samples(m_freeDV); + int nMaxModemSamples = freedv_get_n_max_modem_samples(m_freeDV); + int Fs = freedv_get_modem_sample_rate(m_freeDV); + int Rs = freedv_get_modem_symbol_rate(m_freeDV); m_freeDVStats.init(); if (nSpeechSamples != m_nSpeechSamples) @@ -660,7 +661,7 @@ void FreeDVDemod::applyFreeDVMode(FreeDVDemodSettings::FreeDVMode mode) m_iSpeech = 0; m_iModem = 0; - m_nin = FreeDV::freedv_nin(m_freeDV); + m_nin = freedv_nin(m_freeDV); if (m_nin > 0) { m_freeDVStats.m_fps = m_modemSampleRate / m_nin; diff --git a/plugins/channelrx/demodfreedv/freedvdemod.h b/plugins/channelrx/demodfreedv/freedvdemod.h index 8289031a0..68b7a134d 100644 --- a/plugins/channelrx/demodfreedv/freedvdemod.h +++ b/plugins/channelrx/demodfreedv/freedvdemod.h @@ -45,9 +45,7 @@ class DeviceAPI; class ThreadedBasebandSampleSink; class DownChannelizer; -namespace FreeDV { struct freedv; -} class FreeDVDemod : public BasebandSampleSink, public ChannelAPI { Q_OBJECT @@ -222,7 +220,7 @@ private: { FreeDVStats(); void init(); - void collect(struct FreeDV::freedv *freedv); + void collect(struct freedv *freedv); bool m_sync; float m_snrEst; @@ -395,7 +393,7 @@ private: QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; - struct FreeDV::freedv *m_freeDV; + struct freedv *m_freeDV; int m_nSpeechSamples; int m_nMaxModemSamples; int m_nin; diff --git a/plugins/channeltx/modfreedv/CMakeLists.txt b/plugins/channeltx/modfreedv/CMakeLists.txt index 7f2fc3592..3609d89f4 100644 --- a/plugins/channeltx/modfreedv/CMakeLists.txt +++ b/plugins/channeltx/modfreedv/CMakeLists.txt @@ -14,7 +14,6 @@ set(modfreedv_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client - ${CMAKE_SOURCE_DIR}/libfreedv ${CODEC2_INCLUDE_DIR} ) @@ -22,14 +21,12 @@ if(NOT SERVER_MODE) set(modfreedv_SOURCES ${modfreedv_SOURCES} freedvmodgui.cpp - freedvmodgui.ui ) set(modfreedv_HEADERS ${modfreedv_HEADERS} freedvmodgui.h ) - set(TARGET_NAME modfreedv) set(TARGET_LIB "Qt5::Widgets") set(TARGET_LIB_GUI "sdrgui") @@ -50,13 +47,12 @@ if(ENABLE_EXTERNAL_LIBRARIES) endif() target_link_libraries(${TARGET_NAME} - Qt5::Core - ${TARGET_LIB} + Qt5::Core + ${TARGET_LIB} sdrbase ${TARGET_LIB_GUI} - swagger - freedv - ${CODEC2_LIBRARIES} + swagger + ${CODEC2_LIBRARIES} ) install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER}) diff --git a/plugins/channeltx/modfreedv/freedvmod.cpp b/plugins/channeltx/modfreedv/freedvmod.cpp index 12104fc8b..eb56634a0 100644 --- a/plugins/channeltx/modfreedv/freedvmod.cpp +++ b/plugins/channeltx/modfreedv/freedvmod.cpp @@ -28,7 +28,7 @@ #include #include -#include "libfreedv.h" +#include "codec2/freedv_api.h" #include "SWGChannelSettings.h" #include "SWGChannelReport.h" @@ -138,7 +138,7 @@ FreeDVMod::~FreeDVMod() delete[] m_SSBFilterBuffer; if (m_freeDV) { - FreeDV::freedv_close(m_freeDV); + freedv_close(m_freeDV); } } @@ -231,7 +231,7 @@ void FreeDVMod::pullAF(Complex& sample) calculateLevel(m_speechIn[i]); } } - FreeDV::freedv_tx(m_freeDV, m_modOut, m_speechIn); + freedv_tx(m_freeDV, m_modOut, m_speechIn); break; case FreeDVModSettings::FreeDVModInputFile: if (m_iModem >= m_nNomModemSamples) @@ -271,7 +271,7 @@ void FreeDVMod::pullAF(Complex& sample) } } - FreeDV::freedv_tx(m_freeDV, m_modOut, m_speechIn); + freedv_tx(m_freeDV, m_modOut, m_speechIn); } } else @@ -296,7 +296,7 @@ void FreeDVMod::pullAF(Complex& sample) calculateLevel(m_speechIn[i]); } } - FreeDV::freedv_tx(m_freeDV, m_modOut, m_speechIn); + freedv_tx(m_freeDV, m_modOut, m_speechIn); break; case FreeDVModSettings::FreeDVModInputCWTone: for (int i = 0; i < m_nSpeechSamples; i++) @@ -325,12 +325,12 @@ void FreeDVMod::pullAF(Complex& sample) calculateLevel(m_speechIn[i]); } } - FreeDV::freedv_tx(m_freeDV, m_modOut, m_speechIn); + freedv_tx(m_freeDV, m_modOut, m_speechIn); break; case FreeDVModSettings::FreeDVModInputNone: default: std::fill(m_speechIn, m_speechIn + m_nSpeechSamples, 0); - FreeDV::freedv_tx(m_freeDV, m_modOut, m_speechIn); + freedv_tx(m_freeDV, m_modOut, m_speechIn); break; } @@ -642,7 +642,7 @@ void FreeDVMod::applyFreeDVMode(FreeDVModSettings::FreeDVMode mode) // FreeDV object if (m_freeDV) { - FreeDV::freedv_close(m_freeDV); + freedv_close(m_freeDV); } int fdv_mode = -1; @@ -674,32 +674,32 @@ void FreeDVMod::applyFreeDVMode(FreeDVModSettings::FreeDVMode mode) if (fdv_mode == FREEDV_MODE_700D) { - struct FreeDV::freedv_advanced adv; + struct freedv_advanced adv; adv.interleave_frames = 1; - m_freeDV = FreeDV::freedv_open_advanced(fdv_mode, &adv); + m_freeDV = freedv_open_advanced(fdv_mode, &adv); } else { - m_freeDV = FreeDV::freedv_open(fdv_mode); + m_freeDV = freedv_open(fdv_mode); } if (m_freeDV) { - FreeDV::freedv_set_test_frames(m_freeDV, 0); - FreeDV::freedv_set_snr_squelch_thresh(m_freeDV, -100.0); - FreeDV::freedv_set_squelch_en(m_freeDV, 1); - FreeDV::freedv_set_clip(m_freeDV, 0); - FreeDV::freedv_set_tx_bpf(m_freeDV, 1); - FreeDV::freedv_set_ext_vco(m_freeDV, 0); + freedv_set_test_frames(m_freeDV, 0); + freedv_set_snr_squelch_thresh(m_freeDV, -100.0); + freedv_set_squelch_en(m_freeDV, 1); + freedv_set_clip(m_freeDV, 0); + freedv_set_tx_bpf(m_freeDV, 1); + freedv_set_ext_vco(m_freeDV, 0); - FreeDV::freedv_set_callback_txt(m_freeDV, nullptr, nullptr, nullptr); - FreeDV::freedv_set_callback_protocol(m_freeDV, nullptr, nullptr, nullptr); - FreeDV::freedv_set_callback_data(m_freeDV, nullptr, nullptr, nullptr); + freedv_set_callback_txt(m_freeDV, nullptr, nullptr, nullptr); + freedv_set_callback_protocol(m_freeDV, nullptr, nullptr, nullptr); + freedv_set_callback_data(m_freeDV, nullptr, nullptr, nullptr); - int nSpeechSamples = FreeDV::freedv_get_n_speech_samples(m_freeDV); - int nNomModemSamples = FreeDV::freedv_get_n_nom_modem_samples(m_freeDV); - int Fs = FreeDV::freedv_get_modem_sample_rate(m_freeDV); - int Rs = FreeDV::freedv_get_modem_symbol_rate(m_freeDV); + int nSpeechSamples = freedv_get_n_speech_samples(m_freeDV); + int nNomModemSamples = freedv_get_n_nom_modem_samples(m_freeDV); + int Fs = freedv_get_modem_sample_rate(m_freeDV); + int Rs = freedv_get_modem_symbol_rate(m_freeDV); if (nSpeechSamples != m_nSpeechSamples) { diff --git a/plugins/channeltx/modfreedv/freedvmod.h b/plugins/channeltx/modfreedv/freedvmod.h index 0a113e598..d77c1c07e 100644 --- a/plugins/channeltx/modfreedv/freedvmod.h +++ b/plugins/channeltx/modfreedv/freedvmod.h @@ -46,9 +46,7 @@ class DeviceAPI; class ThreadedBasebandSampleSource; class UpChannelizer; -namespace FreeDV { struct freedv; -} class FreeDVMod : public BasebandSampleSource, public ChannelAPI { Q_OBJECT @@ -332,7 +330,7 @@ private: QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; - struct FreeDV::freedv *m_freeDV; + struct freedv *m_freeDV; int m_nSpeechSamples; int m_nNomModemSamples; int m_iSpeech;